Skip to content

kptr_restrict

%pK format specifier'ı üzerinden basılan kernel pointer'larını (0'a) redact eden bir sysctl; unprivileged userspace'e KASLR'yi derandomize eden adres leak'lerini esirger.

Mechanism

Neden çalışır

KASLR yalnızca kernel'in boot başına text/heap base'i sır kaldığı sürece işe yarar. Tek bir sızdırılmış kernel pointer'ı slide'ı açığa çıkarır (slide = leaked_addr − known_base) ve her şeyi derandomize eder. Birçok kernel interface'i tarihsel olarak ham pointer'ları /proc, /sys ve dmesg'e bastı ve o sırrı herhangi bir unprivileged okuyucuya teslim etti.

kptr_restrict, leak'i formatting katmanında kapatır. Kernel'in vsnprintf'i, çıktısı kernel.kptr_restrict sysctl'i ve çağıranın credential'larıyla gate'lenen özel bir conversion, %pK, implement eder. Geri kazandığı invariant: bir kernel virtual address'i privileged bir sırdır, yani bir %pK field'ının unprivileged tüketicisi 0 almalıdır, asla gerçek pointer'ı değil. Karar, değer render edilirken okuyan task'ın cred'ine karşı verilir, yani daha önce farklı yetkilerle açılmış bir file descriptor üzerinden sızdırarak yenilemez.

%pK call site başına opt-in'dir: yalnızca bir geliştiricinin %pK ile işaretlediği field'lar (örn. /proc/kallsyms, /proc/modules) kapsanır. Düz %p hash'lenir (bkz. hashed-kernel-pointers); %px her zaman ham'dır.

Walkthrough

1. Mevcut politikayı oku ve ayarla. Üç değer tanımlıdır:

# 0 = no restriction (the address is hashed before printing, like %p)
# 1 = %pK prints 0 unless caller has CAP_SYSLOG and euid==ruid, egid==rgid
# 2 = %pK prints 0 for everyone, regardless of privilege

$ cat /proc/sys/kernel/kptr_restrict
1

$ sudo sysctl -w kernel.kptr_restrict=1
kernel.kptr_restrict = 1

# persist across reboots:
$ echo 'kernel.kptr_restrict = 1' | sudo tee /etc/sysctl.d/10-kptr.conf

2. Bir %pK field'ındaki etkisini gözlemle. /proc/kallsyms symbol adreslerini %pK ile basar, yani unprivileged okumalar sıfırlanır:

$ id -u
1000
$ cat /proc/sys/kernel/kptr_restrict
1
$ grep ' commit_creds$' /proc/kallsyms
0000000000000000 T commit_creds

$ sudo grep ' commit_creds$' /proc/kallsyms
ffffffff8a0b1d40 T commit_creds
kptr_restrict=2 adresi root için bile sıfırlar
$ sudo sysctl -w kernel.kptr_restrict=2
kernel.kptr_restrict = 2
$ sudo grep ' commit_creds$' /proc/kallsyms
0000000000000000 T commit_creds

Yalnızca %pK'yı kapsar, read anında değerlendirilir

kptr_restrict ham %px için, doğrudan memory disclosure bug'ları için ya da side-channel KASLR break'leri (örn. EntryBleed) için hiçbir şey yapmaz. Credential kontrolü read() anında okuyan task'ın cred'ini kullanır, yani open() ile read() arasındaki privilege geçişleri leak'i genişletmez — ama meşru olarak CAP_SYSLOG'a sahip bir process değer 1'de hâlâ gerçek pointer'ları görür.

Detection

Durum operasyonel olarak gözlemlenebilir: sysctl kernel.kptr_restrict ve /proc/kallsyms ile /proc/modules gibi %pK field'larının unprivileged çağıranlar için 0 render edip etmediği. Birçok hardening baseline'ı (CIS) değer 1 ya da 2 ister.

Mitigation

(Residual risk / bypass.) Mitigation %pK çıktı path'leriyle sınırlıdır. Saldırganlar bunun etrafından doğrudan read primitive'leri, %px/debug interface'leri, dmesg (dmesg-restrict ile birleştir), perf ya da ../kernel/entrybleed-kpti-kaslr-bypass.md gibi microarchitectural KASLR oracle'ları ile dolaşır. kallsyms-address-restriction'ı tamamlar ama yerini almaz.

References