Skip to content

Page spray

Page-granular bir reclaim tekniği: free edilmiş bir kernel slab page'i (veya page-level UAF) page allocator'a döndükten sonra, içeriğini kontrol ettiğin birçok page allocation'ı spray'leyerek free edilen page'in üzerine konmasını ve victim'i overwrite etmesini sağla.

Mechanism

Note

Object-level "heap spray", aynı kmem cache'i yeniden allocate ederek free edilmiş bir slab object'i reclaim eder. Page spray bir seviye aşağıda çalışır: free edilmiş page'in kendisini hedefler. Tüm bir slab free edildiğinde, slab'in backing page'i buddy/page allocator'a döner; taze page'ler isteyip içlerine attacker data'sı kopyalayan herhangi bir subsystem o tam page'i reclaim edebilir. Yayınlanan DirtyPage modeli bunu formalize eder: bir reference-to-victim'i free edilmiş bir page'e dangling reference'a çevir, sonra object'i corrupt etmek için "page-level data" inject et. Model tüm page'ler üzerinde çalıştığı için, victim object'in type'ından bağımsızdır, böylece tek bir teknik UAF, double-free ve OOB bug'larına eşit derecede hizmet eder — ve object reuse'ı zorlaştıran per-cache mitigation'ları ve RCU grace-period timing'ini es geçer.

DirtyPage akışı:

  1. Slab'i düzenle — bir slab page'i, vulnerable ve victim object'lerin etrafında padding object'lerle doldur (hepsi aynı physical page'de).
  2. Tüm slab'i free et — victim'e bir (artık dangling) reference tutarak tüm object'leri free et, böylece page page allocator'a geri atılır.
  3. Geri dönüştür — free edilmiş slab page'i buddy allocator'ın free list'lerine girer.
  4. Page'leri spray'le — biri free edilmiş page'i reclaim etsin diye birçok controlled page allocate et; attacker-written page içeriği artık victim object ile overlap eder.

Walkthrough

User data'nın page'e nasıl ulaştığıyla ayrışan iki spray vector ailesi vardır:

Copy-write vector'leri (kernel copy_*_from_iter()'in taze alloc_page()'lenmiş page'lere):

/* pipe pages: each write can pull a fresh page and fill it with chosen bytes */
int p[2]; pipe(p);
char buf[4096]; memset(buf, 0x41, sizeof buf);   /* controlled page contents */
for (int i = 0; i < N; i++)
    write(p[1], buf, sizeof buf);                /* pipe_write -> alloc_page + copy */
  • pipe_writestruct pipe_buffer'da saklanan alloc_page(GFP_HIGHUSER | __GFP_ACCOUNT).
  • skb_copy_datagram_from_iter() ile doldurulan alloc_skb_with_frags() page frag'ları (socket'ler).
  • tun_build_skb / tap_alloc_skb driver path'leri.

Remap / zero-copy vector'leri (userspace'e eklenen kernel page'leri, stabil bir pencere verir):

/* AF_PACKET ring: packet_set_ring controls how many pages to allocate;
   packet_mmap maps them back to userspace via vm_insert_page() */
setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof req);
void *ring = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, s, 0);
  • packet_set_ring / packet_mmap (pgv page vector'leri), io_uring_mmap. Bunlar attacker'ın reclaim edilmiş page'i doğrudan user mapping üzerinden geri okumasına ve yeniden yazmasına izin verir.

Yayınlanan static analysis, pipe, packet, io_uring ve network-driver subsystem'leri boyunca ~21 page-spraying callsite'ı sayıdı — controllable page allocator'lardan oluşan geniş bir menü. Copy-write ailesi netlink_sendmsg(), tcp_send_rcvq(), aead_sendmsg(), rds_message_copy_from_user(), unix_dgram_sendmsg() gibi vector'leri; remap ailesi ise xsk_mmap(), array_map_mmap(), ringbuf_map_mmap() (BPF) gibi vector'leri kapsar.

Neden physmap-spray'den daha güçlü

Makalenin manşet sonucu, page spray'in eski physmap-spray attack'larının memory-pressure kısıtları olmadan başarılı olmasıdır. Daha önceki physmap teknikleri yüzlerce MB userspace belleğini zorlardı; modern kernel'ler process'i basitçe OOM-kill eder. Allocation'ı bunun yerine kernel-space callsite'larından sürerek, page spray pressure limitini es geçer; object spray'in info-leak yokluğundan başarısız olduğu CVE-2022-2585 (POSIX CPU timer UAF) bug'ında exploit edilebildiği gösterildi.

Warning

Reclaim olasılıksal ve order-duyarlıdır: free edilen page yalnızca spray'in slab'in backing page'iyle aynı allocation order ve pressure'ı talep etmesi durumunda yeniden servis verir. NUMA node, GFP flag'leri ve per-CPU page cache'leri, hangi page'i geri aldığını etkiler — block/frag boyutlarını victim slab'in page order'ına uyacak şekilde ayarla.

Detection

Bir free'nin hemen ardından, özellikle unprivileged/namespaced context'lerden gelen page-backed allocation patlamaları (çok sayıda pipe write, AF_PACKET ring veya io_uring buffer) gözlemlenebilir bir sinyaldir. Page-allocator accounting anomalileri bunu doğrulayabilir.

Mitigation

  • Page-level isolation savunmaları (örn. CONFIG_SLAB_VIRTUAL, cache type başına dedicated virtual aralıklar) free edilmiş slab page'lerin foreign-type page'ler olarak remap edilmesini engellemeyi hedefler; same-type spray naif varyantları hâlâ yenebilir.
  • Erişilebilir spray vector'lerini azalt (AF_PACKET, io_uring üzerinde seccomp; userns'i kısıtla).

References