Skip to content

Arbitrary read/write via pipe_buffer

Bir struct pipe_buffer'ın page pointer'ını corrupt et ki sıradan pipe read()/write() keyfi bir kernel physical page'i üzerinde çalışsın — tam sayfalık, keyfi bir R/W primitive'i.

Info

Bu doc R/W primitive'inin kendisine ve anon_pipe_get_page()/anon_pipe_put_page() page-reuse davranışına (write-back yoluyla persistence) odaklanır. Corrupt edilmiş page'i bir heap target'ının struct page'ine çeviren vmemmap aritmetiği ve F_SETPIPE_SZ cross-cache grooming'i için tamamlayıcı pipe-buffer-hijack'e bak — aynı corruption'ın data-only, targeting'e odaklı görünümü.

Mechanism

Note

Bir pipe, her biri bir struct page *page ile o page'e bir offset/len penceresine referans veren bir struct pipe_buffer dizisi tutar. Pipe read()/write(), page[offset .. offset+len] üzerinde çalışır. Bir attacker page pointer'ını corrupt ederse (bir UAF ile ya da pipe_buffer dizisine bir overflow ile), pipe I/O keyfi bir physical page'e yönlendirilir — kernel keyfi read ve write. Bunun yerine ops'u (→ anon_pipe_buf_ops) corrupt etmek control-flow hijack verir; flags'i (PIPE_BUF_FLAG_CAN_MERGE) corrupt etmek ise Dirty Pipe sınıfıdır.

Obje (40 byte):

struct pipe_buffer {
    struct page *page;                      /* off 0   <-- corrupt for R/W */
    unsigned int offset;                    /* off 8  */
    unsigned int len;                       /* off 12 */
    const struct pipe_buf_operations *ops;  /* off 16  <-- corrupt for RIP */
    unsigned int flags;                     /* off 24 */
    unsigned long private;                  /* off 32 */
};

Default 16-buffer'lık pipe dizisi 16 * 40 = 640 byte'tır → kmalloc-1024.

Walkthrough

int pfd[2];
pipe(pfd);
write(pfd[1], pagebuf, 0x1000);     /* populate a pipe_buffer.page */

/* ... UAF/overflow overwrites pipe_buffer.page with a target kernel page ... */

read(pfd[0], leak, 0x1000);         /* leaks a full page of kernel memory */
/* or write(pfd[1], data, n) to write the target page */

anon_pipe_get_page(), page'leri pipe_inode_info.tmp_page[2]'den çeker ve anon_pipe_put_page(), (corrupt edilmiş) pointer'ı yeniden kullanım için geri saklar — bu da sonraki pipe operasyonlarında keyfi kernel memory'sine write-back yapmayı mümkün kılar. ops'u sahte bir anon_pipe_buf_ops table'ına işaret ettirmek, bir function-pointer/control-flow target'ı sağlar.

Warning

Corrupt edilmiş bir pipe'ı kapatmak, saldırılan page'i page allocator'a geri verir ve öngörülemeyen kernel memory reuse'una yol açar — kernel'i crash'leyebilen ya da bir forensic sinyal bırakabilen bir cleanup mayını. Kapatmadan önce orijinal page'i geri yükle ya da pipe'ı hiç kapatma.

Mitigation

Bu primitive'i hedefleyen özel bir mitigation yoktur; savunma, başlangıçtaki pipe_buffer corruption'ını engellemeye (slab freelist hardening, freelist-pointer randomization, cache isolation) ve flags/uninitialized varyantı için Dirty Pipe fix'ine dayanır.

References