Skip to content

/proc/modules and /sys/kernel/notes KASLR leak

Kernel modüllerinin randomize load base'ini /proc/modules'tan kurtar ve kernel'in ELF .notes section'ını /sys/kernel/notes'tan parse ederek KASLR'yi yen.

Mechanism

Note

Her iki dosya da KASLR ile birlikte hareket eden absolute kernel adreslerini açığa çıkarır. /proc/modules, yüklü her modülün text base'ini (mod->mem[MOD_TEXT].base) basar; modül bölgesi boot başına randomize edildiğinden tek bir base onu derandomize eder. /sys/kernel/notes, çalışan vmlinux'un ELF .notes section'ının ham binary dump'ıdır (ELFNOTE() makrosunun ürettiği veri). Tarihsel olarak bir absolute symbol adresi (startup_xen) içeriyordu, dolayısıyla unprivileged bir okuyucu note'u parse edip KASLR offset'ini kurtarabiliyordu — 2007'den beri var olan, KASLR'den (x86 için 3.14 döngüsünde, 2013) bile önce gelen bir maruziyet. (Guixiong Wei'nin bulgusu, LWN 962782'de belgelendi.)

Walkthrough

/proc/modules satır formatı, kernel/module/procfs.c m_show()'dan:

seq_printf(m, "%s %u", mod->name, size);   /* name, total size      */
print_unload_info(m, mod);                  /* refcount + dependents */
seq_printf(m, " %s", /* state */ ... "Live");
value = m->private ? NULL : mod->mem[MOD_TEXT].base;
seq_printf(m, " 0x%px", value);             /* base address          */

Yani alanlar şöyle: name size refcount deps state 0x<base>. Şununla oku:

$ cat /proc/modules
$ grep nf_tables /proc/modules

Adres görünürlüğü modules_open() içinde belirlenir:

m->private = kallsyms_show_value(file->f_cred) ? NULL : (void *)8ul;

Okuyucu değerleri göremediğinde m->private non-NULL'dur, dolayısıyla value NULL olur ve base 0x0000000000000000 olarak basılır; privileged bir okuyucu gerçek mod->mem[MOD_TEXT].base'i alır.

/sys/kernel/notes için ELF notes blob'unu dump edip parse et (her note: name-size, desc-size, type, ardından name ve descriptor payload):

$ hexdump -C /sys/kernel/notes | head

Warning

0x%px bir raw pointer'dır, yalnızca açık kallsyms_show_value() check'iyle (kptr_restrict'in beslediği predicate) geçit altına alınır — %pK formatlamasıyla değil. v6.6 kernel/module/procfs.c m_show()'da doğrulandı: seq_printf(m, " 0x%px", value) gerçekten %px kullanır, yani format specifier hiçbir redaction yapmaz; güvenlik tamamen m->private wrapper'ının value'yu NULL'a düşürmesine dayanır. O check senin context'in için geçerse, gerçek base aynen basılır.

Detection

Kernel, dosya içeriklerini /proc/kallsyms ile karşılaştırarak binary-encoded adresleri saptamak üzere genişletilmiş scripts/leaking_addresses.pl'i içerir — grep tabanlı taramanın kaçırdığı durumları (örn. binary /sys/kernel/notes leak'i) yakalar.

Mitigation

  • /sys/kernel/notes yalnızca-root'a (0400) kısıtlandı ve takip eden bir yama, hiçbir absolute adres görünmesin diye address relocation'larını notes section'ından tamamen kaldırdı.
  • /proc/modules base'leri, unprivileged user'lar için kallsyms_show_value() / kernel.kptr_restrict üzerinden sıfırlanır.

References