pipe_buffer ops overwrite data-only attack¶
Freed/yeniden-spray'lenmiş bir
pipe_buffer'ınopspointer'ını forged birpipe_buf_operationstable'a yeniden yönlendir (ya da bir page UAF zincirle) ki pipe teardown attacker'ın seçtiği davranışı sürsün — herhangi bir kernel.text'ini overwrite etmeden.
Mechanism¶
Note
Her pipe_buffer ops taşır, bir struct pipe_buf_operations vtable'ına
(anon_pipe_buf_ops) bir pointer; pipe kodu bunun release/try_steal/get
callback'lerini normal lifecycle event'leri sırasında çağırır (örn. release, tüketilen
bir buffer recycle edildiğinde ya da pipe kapatıldığında çalışır). Kernel ops'a körü
körüne güvenir. Onu bir pipe_buffer UAF üzerinden overwrite etmek — buffer array'ini
free et, aynı slab slot'unu kontrol edilen byte'larla yeniden allocate et — attacker'ın
ops'u, function pointer'larını kendisinin doldurduğu fake bir table'a yönlendirmesini
sağlar. Bu "data-only"dir, şu anlamda: hiçbir kernel kodu yamalanmaz ve hiçbir read-only
vtable değiştirilmez; attacker kontrol edilen memory'de writable bir replica table forge
eder ve kernel onu gerçekmiş gibi dereference eder. Yakından ilişkili, tamamen data-only
bir varyant ops'tan büsbütün kaçınır: page pointer'ını kısmen overwrite et ki bir
pipe'ın buffer'ı başka bir pipe'ın canlı page'ini alias etsin (PageJack page-UAF), hiç
forged pointer olmadan page-granular R/W vererek.
struct pipe_buf_operations {
int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *);
void (*release)(struct pipe_inode_info *, struct pipe_buffer *); /* invoked on recycle/close */
bool (*try_steal)(struct pipe_inode_info *, struct pipe_buffer *);
bool (*get)(struct pipe_inode_info *, struct pipe_buffer *);
};
Buffer array'i, varsayılan 16-buffer'lı bir pipe için kmalloc-1k'dır (16 * 40 = 640 byte);
fcntl(fd, F_SETPIPE_SZ, …) grooming için onu başka bir cache'e taşır. Array sade bir kmalloc
allocation'ı olduğundan, bir UAF ya da cross-cache reclaim içeriğini toptan değiştirebilir.
Walkthrough¶
UAF akışı: bir pipe_buffer array'ini free ettir, sonra slot'a aynı boyutta kontrol edilen
bir object spray'le ki pipe_buffer[i].ops olarak yorumlanan byte'lar attacker memory'sini
göstersin; bir buffer recycle / close() tetiklemek ops->release'i çağırır:
int pfd[2];
pipe(pfd);
write(pfd[1], buf, 0x10); /* live pipe_buffer with real page + ops */
/* ... free the pipe_buffer array (UAF) and re-spray the slot ... */
/* attacker bytes now overlay the buffer: */
fake[i].ops = &forged_ops; /* forged_ops.release = controlled */
close(pfd[0]); close(pfd[1]); /* pipe teardown calls ops->release */
Saf page-UAF (PageJack) alternatifi forged bir table gerektirmez — page'in kısmi bir
overwrite'ı iki pipe'ın bir page'i paylaşması için yeterlidir:
/* OOB write touches only the low bytes of pbuf->page, aliasing it
onto a page that another, still-open pipe owns -> page use-after-free */
pbuf->page = (struct page *)((uintptr_t)pbuf->page & ~0xffffUL | groomed_low);
Bu neden "data-only" kalıyor
kernel CFI'li platformlarda ya da ops'un yalnızca veri olarak tüketildiği yerlerde
(örn. statik anon_pipe_buf_ops symbol address'i üzerinden kernel base'ini sızdırmak için
ops'u okuyan türetilmiş primitive'ler — bkz.
kernel-base-leak-via-ops-pointer), attacker'ın asla
executable bir hedefe ihtiyacı olmaz. Özellikle PageJack varyantı yalnızca bir data
pointer'a ve bir page'e dokunur, dolayısıyla SMEP/SMAP/CFI'den etkilenmez; mitigation,
heap corruption'ının kendisini engellemekten gelmelidir.
Warning
release/get refcounting'i sadakatle uygulamayan forged bir ops table'ı, page
allocator'ı desenkronize eder ve corruption anında değil, bir sonraki ilgisiz
allocation'da crash eder — bu da bu bug'ları aldatıcı biçimde kararsız kılar. Teardown'dan
önce orijinal page/ops'u geri döndürmek güvenilir cleanup path'idir.
Mitigation¶
Primitive'e özgü bir mitigation yoktur; savunma pipe_buffer UAF/OOB'sini engellemektir:
freelist hardening, cross-cache'in farkında olan allocator'lar ve slab cache isolation.
anon_pipe_buf_ops'un statik konumu (bir KASLR-leak oracle'ı) corruption'la ilgisizdir ve
kendisi düzeltilebilir bir surface değildir.