seq_operations function-pointer overwrite / leak¶
32-byte'lık
struct seq_operations'ı (/proc/self/statgibi dosyalar açılırken allocate edilir) spray'leyerek KASLR için bir kernel.textpointer'ı leak et ya da function pointer'larını overwrite ederekread()anında control flow'u hijack et.
Mechanism¶
struct seq_operations, kernel'in seq_file interface'ini süren dört function pointer (start, stop, next, show) tutar. Tüm struct 0x20 byte'tır, dolayısıyla kmalloc-32 genel cache'inden allocate edilir. /proc/self/stat gibi seq_file-backed bir procfs dosyası açmak yeni bir tane allocate eder — kmalloc-32'de unprivileged, tekrarlanabilir bir allocation.
Note
İki özellik onu birinci sınıf bir exploit object'i yapar. (1) Leak: dört pointer'ı kernel .text'e işaret eder; bunları bir out-of-bounds / UAF read ile okumak bir text adresi verir ve sabit bir offset çıkarmak kernel base'ini verir — KASLR'ı yener. (2) Hijack: fd üzerinde read() çağırmak seq_read()'e ulaşır; bu da seq->op->start/show/...'ı dereference edip çağırır; bu pointer'ları bir write primitive ile overwrite etmek RIP'i attacker'ın seçtiği bir gadget'a yönlendirir. CONFIG_SLAB_FREELIST_RANDOM kapalıyken SLUB free edilmiş kmalloc-32 chunk'larını LIFO sırayla geri verir; bu da henüz free edilmiş bir victim chunk'ının reclaim'ini deterministik yapar.
Walkthrough¶
seq_operations'ı free edilmiş kmalloc-32 slot'larına spray'le, sonra leak et ve/veya hijack et:
struct seq_operations { // 0x20 bytes => kmalloc-32
void *(*start)(struct seq_file *, loff_t *);
void (*stop) (struct seq_file *, void *);
void *(*next) (struct seq_file *, void *, loff_t *);
int (*show) (struct seq_file *, void *);
};
int fds[256];
for (int i = 0; i < 256; i++)
fds[i] = open("/proc/self/stat", O_RDONLY); // each spreads one seq_operations
- Leak path: spray'lenmiş bir chunk üzerinde bug'ın OOB/UAF read'ini tetikle; byte'lar bir
.textpointer'ıdır (ör.single_start).kbase = leaked - known_offset. - Hijack path: write primitive'i kullanarak
seq->op->start'ı (ya dastop'u) bir stack-pivotgadget'ıyla overwrite et, sonraread(fds[i], buf, 1)ileseq_read()'e gir ve bozulmuş pointer'ı ateşle → ROP.
Beklenen sonuç: leak edilmiş bir kernel-text adresi ya da read() anında RIP kontrolü.
Mitigation¶
CONFIG_SLAB_FREELIST_RANDOM ve CONFIG_SLAB_FREELIST_HARDENED reclaim determinizmini azaltır; CFI (CONFIG_CFI_CLANG / FineIBT) overwrite edilmiş pointer üzerinden keyfi bir gadget çağrılmasını engeller; kptr_restrict ve infoleak primitive'lerinin kaldırılması KASLR-leak yarısını köreltir.