Skip to content

dmesg / kernel log buffer pointer leak

Read raw kernel addresses out of the printk ring buffer — oops/WARN/BUG register dumps print true (unhashed) kernel pointers, defeating KASLR.

Mechanism

Note

Kernel tüm log mesajlarını dairesel bir printk ring buffer'da tutar; bu, userspace'e dmesg(8), /dev/kmsg, syslog-daemon dosyaları (/var/log/syslog, /var/log/kern.log) ve syslog(2)/klogctl syscall'ı üzerinden açılır — hepsi aynı buffer'ı okur. Kernel bir fault'a, WARN()'a, BUG()'a ya da bir oops'a çarptığında register durumunu, bir call trace'i ve fault'lu instruction pointer'ı (RIP) döker. Linux 4.15'ten beri düz %p specifier'ı hash'lenir, ama oops register dump'ları ve RIP: satırı ham hex register değerleri olarak, %p üzerinden değil yayımlanır, dolayısıyla hash'lemeyi bypass eder ve gerçek kernel sanal adreslerini açığa çıkarır. Leak'lenen bir .text adresinden bilinen bir sembol offset'ini çıkararak attacker KASLR slide'ını hesaplar.

syslog(2) action'ları: SYSLOG_ACTION_READ_ALL = 3 (kalan her şeyi oku), READ_CLEAR = 4, SIZE_BUFFER = 10. Man page'e göre, 3 ve 10 dışındaki tüm komutlar privilege gerektirir, ve 2.6.37'den beri 3/10 bile unprivileged process'lere yalnızca kernel.dmesg_restrict 0 olduğunda izin verilir. İlgili capability CAP_SYSLOG'dur.

Walkthrough

dmesg                 # syslog(2) / /dev/kmsg; respects dmesg_restrict
cat /dev/kmsg         # raw ring-buffer device
cat /var/log/syslog   # persisted copy from the syslog daemon
dmesg | grep -E 'RIP:|ffffffff[0-9a-f]{8}'   # pull kernel addresses

Doğrudan syscall üzerinden (SYSLOG_ACTION_READ_ALL):

#include <sys/klog.h>
char buf[1<<16];
/* int klogctl(int type, char *bufp, int len); */
int n = klogctl(3 /* SYSLOG_ACTION_READ_ALL */, buf, sizeof(buf));

Kernel bug-hunting dokümanlarından gerçek bir WARN trace'i, adres leak'leyen sembol+offset ve instruction pointer'ı gösterir:

WARNING: CPU: 1 PID: 28102 at kernel/module.c:1108 module_put+0x57/0x70
...
[<c109e8a7>] ? module_put+0x57/0x70
BUG: unable to handle kernel NULL pointer dereference at   (null)
IP: [<c06969d4>] iret_exc+0x7d0/0xa59

x86_64'te modern biçim, tam ffffffff........ adresleriyle RIP: 0010:<symbol>+offset/len şeklindedir ve register dump'ı (RSP/RAX/.../R15) ham stack/heap/text pointer'ları taşır.

Warning

Bazı driver'lar oops olmadan bile adres leak'ler. CVE-2018-7273'te floppy driver'ının drivers/block/floppy.c içindeki show_floppy'si kernel fonksiyonlarının ve global'lerinin adreslerini doğrudan dmesg'e basıyordu; bu, KASLR'ı etkisizleştirmek için herhangi bir kullanıcı tarafından okunabiliyordu. (Kesin printk format string'i advisory'den kurtarılamadı.)

Detection

Log'daki oops/WARN sıçramaları, tekrarlanan syslog(2) READ_ALL/READ_CLEAR çağrıları ya da hayatta kalan bir leak'i toplamak için kontrollü fault'lar tetikleyen bir process gözlemlenebilir sinyallerdir.

Mitigation

  • sysctl -w kernel.dmesg_restrict=1 (CONFIG_SECURITY_DMESG_RESTRICT) — buffer'ı okumak için CAP_SYSLOG gerektirir.
  • kptr_restrict=2 — privilege'tan bağımsız olarak %pK pointer'larını sıfırlar.
  • panic_on_oops=1 — tekrarlanabilir, hayatta kalan bir oops-leak primitive'ini engeller.

References