00 DAC vs MAC
Linux'ta geleneksel erişim kontrolü Discretionary Access Control (DAC) üzerine kurulmuştur. DAC yeterli değildir: root hesabı ele geçirildiğinde veya setuid ikili dosyaları kötüye kullanıldığında tüm sistem risk altına girer. Mandatory Access Control (MAC) bu açığı sistemin özünde kapatır.
DAC (Discretionary Access Control)
DAC'ta dosya sahibi erişim kurallarını kendisi belirler. chmod 777 komutu çalıştırabilen bir kullanıcı dosyayı herkese açabilir. Kernel bunu sorunsuz kabul eder — politika sahibin takdirine (discretion) bırakılmıştır.
# DAC örnek: kullanıcı kendi dosyasında tam kontrol sahibi
ls -la /etc/passwd
-rw-r--r-- 1 root root 1234 Apr 12 2026 /etc/passwd
# root okuyabilir/yazabilir, diğerleri sadece okuyabilir
# Ancak root yetkisiyle her şeyi yapabilirsiniz
# setuid binary riski:
ls -la /usr/bin/passwd
-rwsr-xr-x 1 root root 59976 /usr/bin/passwd
# s biti: çalıştıran ne olursa olsun root yetkileriyle çalışır
# Bu binary'de buffer overflow varsa → root shell
MAC (Mandatory Access Control)
MAC'ta erişim kuralları sistem yöneticisi tarafından merkezi olarak tanımlanır ve kullanıcılar bu kuralları değiştiremez. root bile MAC politikasına tabidir — bir process sadece politikasının izin verdiği işlemleri yapabilir.
Gerçek CVE örnekleri — MAC olsaydı
| CVE | Zafiyet | DAC'ta etki | MAC ile etki |
|---|---|---|---|
| CVE-2021-4034 (PwnKit) | pkexec privilege escalation | Local root | SELinux: pkexec domain kısıtlı, privilege yok |
| CVE-2022-0847 (Dirty Pipe) | Pipe buffer write — root dosya yazma | /etc/passwd değiştirilir | SELinux: passwd_t dosyasına yazma engellenir |
| CVE-2016-5195 (Dirty COW) | Race condition, root write | Sistem dosyaları değişir | AppArmor: korunan profil dosyaları değiştirilemez |
| Log4Shell benzeri | RCE via web app | Web server yetkisiyle OS erişimi | AppArmor: httpd profili /tmp ve /etc'ye erişemez |
MAC bir "sihirli çözüm" değildir — yanlış yapılandırılmış politikalar güvenlik yanılsaması yaratır. "Permissive mode"da log üretilir ama engelleme olmaz. Prodüksiyon sistemleri her zaman "enforcing mode"da çalışmalıdır.
01 LSM framework
Linux Security Module (LSM), çekirdek içinde güvenlik politikalarını uygulayan bir kanca (hook) mekanizmasıdır. Tüm MAC implementasyonları LSM üzerinden çalışır ve çekirdek içindeki kritik sistem çağrılarına müdahale ederler.
Mevcut LSM implementasyonları
| LSM | Köken | Model | Kullanım alanı |
|---|---|---|---|
| SELinux | NSA / Red Hat | Label tabanlı (Type Enforcement) | Android, RHEL/Fedora, CentOS |
| AppArmor | Immunix/Canonical | Path tabanlı profil | Ubuntu, openSUSE, Debian, snaps |
| Smack | Casey Schaufler | Basit label tabanlı | Tizen OS, gömülü (Automotive) |
| Tomoyo | NTT Data | Path tabanlı öğrenen | Japonya kaynaklı, az yaygın |
| Yama | Kees Cook | ptrace kısıtlama | Desktop güvenliği — diğerleriyle birlikte |
| Landlock | Mickaël Salaün | Kullanıcı alanı tanımlı | Sandbox — root olmadan MAC, kernel 5.13+ |
Hangi LSM'i seçmeli?
# Aktif LSM'leri kontrol et:
cat /sys/kernel/security/lsm
# Örnek çıktı: lockdown,capability,yama,selinux
# veya: lockdown,capability,yama,apparmor
# Kernel derleme zamanı LSM listesi:
grep CONFIG_LSM /boot/config-$(uname -r)
02 SELinux temelleri
SELinux (Security-Enhanced Linux), NSA tarafından geliştirilen ve 2003'te mainline kernel'e dahil edilen en kapsamlı LSM implementasyonudur. Temel modeli, her process ve dosyaya bir güvenlik bağlamı (security context) atamak üzerine kurulmuştur.
Subject / Object / Permission modeli
Subject (process) Object (dosya, soket, port)
┌─────────────────┐ ┌──────────────────────────┐
│ httpd_t │ ──?──► │ httpd_sys_content_t │
│ (domain) │ │ /var/www/html/index.html │
└─────────────────┘ └──────────────────────────┘
│
└── SELinux Policy sorar:
"httpd_t" domain'i "httpd_sys_content_t"
tipi üzerinde "read" yapabilir mi?
→ ALLOW httpd_t httpd_sys_content_t:file { read getattr open }
Security context formatı
# user:role:type:level (MLS için level eklenir)
# Örnek context'leri göster:
# Process context:
ps axZ | grep httpd
# system_u:system_r:httpd_t:s0 12345 ? Ss httpd
# Dosya context'leri:
ls -Z /var/www/html/
# system_u:object_r:httpd_sys_content_t:s0 index.html
ls -Z /etc/passwd
# system_u:object_r:passwd_file_t:s0 /etc/passwd
ls -Z /etc/shadow
# system_u:object_r:shadow_t:s0 /etc/shadow
# Kendi process'iniz:
id -Z
# unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
SELinux mod kontrolü
# Mevcut modu göster:
getenforce
# Enforcing | Permissive | Disabled
# Geçici mod değişimi (reboot'a kadar):
setenforce 0 # Permissive
setenforce 1 # Enforcing
# Kalıcı mod (/etc/selinux/config):
SELINUX=enforcing # enforcing / permissive / disabled
SELINUXTYPE=targeted # targeted / minimum / mls
# SELinux durumu:
sestatus
# SELinux status: enabled
# SELinuxfs mount: /sys/fs/selinux
# SELinux mount point: /sys/fs/selinux
# Loaded policy name: targeted
# Current mode: enforcing
# Policy version: 33
03 SELinux policy yönetimi
SELinux politikası, izin verilen erişimlerin tanımlandığı kurallar bütünüdür. Targeted policy, sistem servislerini kısıtlarken kullanıcı süreçlerini serbest bırakır — bu denge gömülü sistemler için pratik bir başlangıç noktasıdır.
audit2allow — reddeden kuraldan izin kuralı üretme
# SELinux reddetme logları /var/log/audit/audit.log'a düşer
# Örnek ret mesajı:
# type=AVC msg=audit(1714567890.123:456): avc: denied { read }
# for pid=1234 comm="myapp" name="config.txt"
# scontext=system_u:system_r:myapp_t:s0
# tcontext=system_u:object_r:etc_t:s0
# tclass=file permissive=0
# Ret mesajlarını incele:
ausearch -m avc -ts recent
audit2why -a
# İzin kuralı üret:
ausearch -m avc -ts recent | audit2allow
# Yeni modül olarak derle ve yükle:
ausearch -m avc -ts recent | audit2allow -M myapp_policy
semodule -i myapp_policy.pp
# Modülleri listele:
semodule -l | grep myapp
Boolean'lar — politikayı esnetme
# SELinux Boolean'ları: politikayı yeniden derlemeden ayarla
# Mevcut boolean'ları listele:
getsebool -a | grep httpd
# Örnekler:
getsebool httpd_can_network_connect
# httpd_can_network_connect --> off
# httpd'nin ağa bağlanmasına izin ver (proxy backend için):
setsebool -P httpd_can_network_connect on
# -P: kalıcı (reboot sonrası geçerli)
# Başka yararlı boolean'lar:
setsebool -P httpd_read_user_content on # ~/public_html
setsebool -P ftp_home_dir on # FTP ev dizini erişimi
setsebool -P ssh_sysadm_login on # sysadm_r SSH girişi
restorecon ve chcon
# Dosya context'ini varsayılana döndür (policy'de tanımlı değer):
restorecon /var/www/html/index.html
restorecon -Rv /var/www/html/ # Recursive, verbose
# Geçici context değiştirme (reboot'ta sıfırlanır):
chcon -t httpd_sys_content_t /var/www/html/myfile.html
# Kalıcı context tanımlama (policy'e ekler):
semanage fcontext -a -t httpd_sys_content_t "/mywebroot(/.*)?"
restorecon -Rv /mywebroot
# Port context:
semanage port -l | grep http
# http_port_t tcp 80, 443, 488, 8008, 8009, 8443
# Özel port ekle:
semanage port -a -t http_port_t -p tcp 8080
04 SELinux gömülü kullanımı
SELinux, gömülü Linux ekosisteminde özellikle Android ve Yocto aracılığıyla kullanılmaktadır. Android 5.0'dan itibaren tüm Android cihazları SELinux enforcing modunda çalışmaktadır.
Android SELinux mimarisi
Android SELinux Politika Katmanları:
┌──────────────────────────────────────────────────┐
│ Vendor Policy (OEM özelleştirmeleri) │
│ /vendor/etc/selinux/ │
├──────────────────────────────────────────────────┤
│ Platform Policy (AOSP politikası) │
│ /system/etc/selinux/ │
├──────────────────────────────────────────────────┤
│ Public Platform Policy (API sözleşmesi) │
│ OEM'ler bu API'yi genişletebilir │
└──────────────────────────────────────────────────┘
# Android SELinux kontrol:
adb shell getenforce # Enforcing
adb shell ls -Z /data/ # Dosya context'leri
# Yeni Android uygulaması için context:
# AOSP: system/sepolicy/private/app.te
# Vendor: device/vendor/board/sepolicy/
Yocto meta-selinux layer
# meta-selinux layer ekle:
git clone https://github.com/SELinuxProject/meta-selinux.git
# meta-openembedded de gereklidir:
git clone https://github.com/openembedded/meta-openembedded.git
# conf/bblayers.conf:
BBLAYERS += " \
/path/to/meta-openembedded/meta-oe \
/path/to/meta-openembedded/meta-networking \
/path/to/meta-selinux \
"
# conf/local.conf:
DISTRO_FEATURES:append = " selinux"
DEFAULT_ENFORCING = "enforcing" # veya "permissive"
# SELinux araçları için:
IMAGE_INSTALL:append = " \
packagegroup-core-selinux \
selinux-python \
setools \
"
# Build:
bitbake core-image-selinux-minimal
Özel SELinux politikası yazma (Yocto)
# meta-myboard/recipes-security/myapp-selinux/myapp.te
policy_module(myapp, 1.0.0)
# Tip tanımlamaları
type myapp_t;
type myapp_exec_t;
type myapp_var_t;
type myapp_log_t;
# Domain geçişi: myapp_exec_t çalıştırıldığında myapp_t domain'ine gir
domain_type(myapp_t)
domain_entry_file(myapp_t, myapp_exec_t)
# Temel izinler
files_read_etc_files(myapp_t)
logging_send_syslog_msg(myapp_t)
miscfiles_read_localization(myapp_t)
# Özel izinler
allow myapp_t myapp_var_t:dir { read write add_name remove_name };
allow myapp_t myapp_var_t:file { create read write unlink getattr setattr };
allow myapp_t myapp_log_t:file { create append read getattr };
05 AppArmor temelleri
AppArmor, path (dosya yolu) tabanlı bir MAC sistemidir. SELinux'un dosya etiketleme yaklaşımının aksine AppArmor, profilde belirtilen yol kalıplarıyla erişimi kısıtlar. Öğrenmesi ve uygulaması daha kolaydır.
Profil yapısı
# /etc/apparmor.d/usr.sbin.nginx — nginx AppArmor profili
#include <tunables/global>
/usr/sbin/nginx {
#include <abstractions/base>
#include <abstractions/nameservice>
# Capability'ler
capability net_bind_service, # 1024 altı port bind
capability setgid,
capability setuid,
capability dac_override,
# Binary
/usr/sbin/nginx mr, # m=mmap, r=read
# Konfigürasyon dosyaları
/etc/nginx/ r,
/etc/nginx/** r,
# Web içeriği
/var/www/ r,
/var/www/** r,
# Log dosyaları
/var/log/nginx/ rw,
/var/log/nginx/** rw,
# PID ve socket dosyaları
/run/nginx.pid rw,
/run/nginx/ rw,
/run/nginx/** rw,
# Geçici dosyalar
/tmp/ rw,
/tmp/** rw,
# Ağ erişimi
network tcp,
network udp,
# /proc erişimi (worker process bilgisi)
/proc/*/status r,
/proc/sys/kernel/ngroups_max r,
}
Dosya izin notasyonu
Profil durumu yönetimi
# Tüm profillerin durumunu listele:
aa-status
# Profil yükle:
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
# Profili complain moduna al (log yaz, engelleme yok):
sudo aa-complain /usr/sbin/nginx
# Enforce moduna al:
sudo aa-enforce /usr/sbin/nginx
# Profili devre dışı bırak:
sudo aa-disable /usr/sbin/nginx
# Audit log izle:
sudo journalctl -k -f | grep apparmor
# veya:
sudo tail -f /var/log/syslog | grep apparmor
06 aa-genprof ile profil oluşturma
aa-genprof ve aa-logprof araçları, uygulamayı çalıştırarak AppArmor profilini otomatik olarak oluşturur. Bu yaklaşım sıfırdan profil yazmaktan çok daha hızlıdır.
aa-genprof ile ilk profil
# 1. aa-genprof'u başlat (uygulama henüz çalışmıyor)
sudo aa-genprof /usr/bin/myapp
# aa-genprof şu mesajı gösterir:
# Please start the application to be profiled in another window
# and exercise its functionality now.
# Once completed, select the (F)inish option below.
# 2. Başka terminal'de uygulamayı çalıştır ve tüm işlevleri dene
# (okuma, yazma, ağ bağlantısı, vs.)
/usr/bin/myapp --config /etc/myapp/config.yaml
# 3. aa-genprof terminalinde (S)can → kural önerileri incele → (F)inish
# Örnek etkileşim:
# = Change profile /usr/bin/myapp =
# ...
# Profile: /usr/bin/myapp
# Execute: /bin/bash
# Severity: 4
#
# (I)nherit / (C)hild / (P)rofile / (N)ame / (U)nconfined / (D)eny / Abo(r)t / (F)inish
aa-logprof — mevcut profili güncelleme
# Uygulama complain modunda çalışırken logları biriktir:
sudo aa-complain /usr/bin/myapp
# Uygulamayı çalıştır ve test et...
# Biriken logları analiz et ve profili güncelle:
sudo aa-logprof
# Otomatik güncelleme (onaylama gerekmeden):
sudo aa-logprof -f /var/log/syslog
audit log analizi
# AppArmor ret logları — syslog formatı:
# kernel: [12345.678] audit: type=1400 audit(1714567890.123:456):
# apparmor="DENIED" operation="open"
# profile="/usr/bin/myapp" name="/etc/ssl/private/key.pem"
# pid=1234 comm="myapp" requested_mask="r" denied_mask="r"
# fsuid=0 ouid=0
# Log'ları filtrele:
sudo journalctl -k | grep 'apparmor="DENIED"'
# Belirli uygulama için:
sudo journalctl -k | grep 'profile="/usr/bin/myapp"'
# Ret edilen dosya erişimlerini özetle:
sudo journalctl -k | grep 'apparmor="DENIED"' | \
grep -oP 'name="\K[^"]+' | sort | uniq -c | sort -rn
07 AppArmor gömülü kullanımı
AppArmor, Ubuntu Core ve snap ekosistemi aracılığıyla gömülü cihazlarda yaygınlaşmıştır. Yocto meta-security layer ile özel rootfs'e de entegre edilebilir.
Ubuntu Core ve snap confinement
Ubuntu Core, snap paket yöneticisini kullanan gömülü bir Ubuntu variantıdır. Her snap paketi otomatik olarak AppArmor + seccomp ile izole edilir. snapd profilleri dinamik olarak oluşturur ve uygular.
# Snap AppArmor profillerini incele:
ls /var/lib/snapd/apparmor/profiles/
# snap.myapp.myapp
# snap.myapp.hook.configure
# Snap bağlantıları (interface):
snap connections myapp
# Interface Plug Slot Notes
# network myapp:network :network -
# camera myapp:camera - -
# gpio myapp:gpio pi:gpio manual
# Snap için AppArmor profil şablonu:
cat /var/lib/snapd/apparmor/profiles/snap.myapp.myapp
Yocto meta-security layer
# meta-security AppArmor desteği:
git clone https://git.yoctoproject.org/meta-security
# conf/bblayers.conf:
BBLAYERS += "/path/to/meta-security"
# conf/local.conf:
DISTRO_FEATURES:append = " apparmor"
PREFERRED_PROVIDER_virtual/refpolicy = "refpolicy-targeted"
# AppArmor paketlerini imaja ekle:
IMAGE_INSTALL:append = " \
apparmor \
apparmor-utils \
apparmor-profiles \
apparmor-parser \
"
# Kernel konfigürasyonu (meta-security otomatik ayarlar):
# CONFIG_SECURITY_APPARMOR=y
# CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
# CONFIG_DEFAULT_SECURITY_APPARMOR=y
Gömülü cihaz için özel profil stratejisi
08 Pratik: Web server için AppArmor profili
Bu bölümde nginx web server'ı için sıfırdan AppArmor profili oluşturup enforce moduna alacağız. Profil dosya erişimini, ağ kurallarını ve capability'leri kapsar.
Başlangıç: aa-genprof ile otomatik profil
# 1. nginx'i durdur:
sudo systemctl stop nginx
# 2. aa-genprof başlat:
sudo aa-genprof /usr/sbin/nginx
# 3. nginx'i başlat (başka terminal):
sudo nginx -t # konfigürasyon testi
sudo nginx # başlat
# 4. Birkaç HTTP isteği gönder:
curl http://localhost/
curl http://localhost/index.html
curl http://localhost/api/status
# 5. aa-genprof'ta (S)can ve kuralları kabul et, (F)inish
Üretilen profili iyileştirme
sudo nano /etc/apparmor.d/usr.sbin.nginx
# /etc/apparmor.d/usr.sbin.nginx — tam ve optimize edilmiş profil
#include <tunables/global>
/usr/sbin/nginx {
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/openssl>
#include <abstractions/ssl_certs>
# Gerekli capability'ler
capability net_bind_service, # 80/443 portlarına bind
capability setgid, # worker process'e gid değiştir
capability setuid, # worker process'e uid değiştir
capability dac_override, # log dosyası sahipliği
capability sys_resource, # rlimit ayarı
# Ana nginx binary
/usr/sbin/nginx mr,
# Konfigürasyon (salt okunur)
/etc/nginx/ r,
/etc/nginx/** r,
/etc/ssl/certs/ r,
/etc/ssl/certs/** r,
/etc/ssl/private/ r,
/etc/ssl/private/nginx.key r, # özel anahtar
# Web içeriği (salt okunur)
/var/www/ r,
/var/www/html/ r,
/var/www/html/** r,
# Log dosyaları (yazılabilir)
/var/log/nginx/ rw,
/var/log/nginx/access.log rw,
/var/log/nginx/error.log rw,
# Çalışma zamanı dosyaları
/run/nginx.pid rw,
/run/nginx/ rw,
/run/nginx/** rw,
# Geçici dosyalar (proxy cache, upload buffer)
/var/cache/nginx/ rw,
/var/cache/nginx/** rw,
/tmp/ rw,
# /proc erişimi (worker process sayısı, CPU bilgisi)
/proc/*/status r,
/proc/cpuinfo r,
/proc/sys/kernel/ngroups_max r,
/sys/devices/system/cpu/online r,
# Ağ kuralları (explicit olarak belirt)
network tcp,
network udp,
# Unix socket (PHP-FPM, backend)
/run/php/php8.1-fpm.sock rw,
# Worker process'leri için dahili geçiş
/usr/sbin/nginx px -> nginx_worker,
}
Worker profili
# /etc/apparmor.d/nginx_worker — ayrı worker profili
profile nginx_worker {
#include <abstractions/base>
#include <abstractions/nameservice>
# Worker sadece içerik okur ve ağ kullanır
/var/www/html/** r,
/var/cache/nginx/** rw,
/tmp/** rw,
/var/log/nginx/** rw,
/run/nginx/** rw,
network tcp,
network udp,
# Worker'ın yeni process başlatmasını engelle
deny /bin/** x,
deny /usr/bin/** x,
deny /sbin/** x,
}
Profili yükle ve test et
# 1. Önce complain modunda test et:
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
sudo aa-complain /usr/sbin/nginx
# 2. nginx'i başlat ve logları izle:
sudo systemctl start nginx
sudo journalctl -k -f | grep apparmor &
# 3. Kapsamlı test:
curl http://localhost/
curl https://localhost/ -k
# Farklı endpoint'leri test et...
# 4. 5-10 dakika bekle, ret mesajı var mı kontrol et:
sudo journalctl -k | grep 'apparmor="DENIED"' | grep nginx
# 5. Ret yoksa enforce moduna geç:
sudo aa-enforce /usr/sbin/nginx
sudo systemctl restart nginx
# 6. Enforce modunu doğrula:
sudo aa-status | grep nginx
# /usr/sbin/nginx (enforce)
Test: profil çalışıyor mu?
# nginx üzerinden yasaklı dosyaya erişim denemesi
# (profil /etc/passwd'ye erişimi engellemelidir)
# nginx config'de test endpoint ekle (test ortamında):
# location /test {
# alias /etc/passwd;
# }
# İstek gönder:
curl http://localhost/test
# Beklenen: 403 Forbidden (nginx izni yok)
# AppArmor logu kontrol:
sudo journalctl -k | grep 'DENIED.*nginx.*passwd'
# apparmor="DENIED" operation="open"
# profile="/usr/sbin/nginx" name="/etc/passwd"
# requested_mask="r" denied_mask="r"
echo "AppArmor profili doğru çalışıyor!"
Enforce moduna geçmeden önce tüm çalışma senaryolarını (normal trafik, hata koşulları, log rotation, SSL sertifika yenileme, reload sinyal işleme) complain modunda test edin. Eksik bir kural prodüksiyonda servis kesintisine yol açar. AppArmor'ın audit kuralı ile reddedilen değil, yalnızca izin verilen erişimleri de loglamak mümkündür — profil doğrulama için kullanışlıdır.