kptr_restrict¶
%pKformat 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
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¶
- The Linux Kernel documentation. Documentation for /proc/sys/kernel/ — kptr_restrict. — https://docs.kernel.org/admin-guide/sysctl/kernel.html
- proc(5) — Linux manual page. — https://man7.org/linux/man-pages/man5/proc.5.html