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ışı:
- Slab'i düzenle — bir slab page'i, vulnerable ve victim object'lerin etrafında padding object'lerle doldur (hepsi aynı physical page'de).
- 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.
- Geri dönüştür — free edilmiş slab page'i buddy allocator'ın free list'lerine girer.
- 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_write→struct pipe_buffer'da saklananalloc_page(GFP_HIGHUSER | __GFP_ACCOUNT).skb_copy_datagram_from_iter()ile doldurulanalloc_skb_with_frags()page frag'ları (socket'ler).tun_build_skb/tap_alloc_skbdriver 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(pgvpage 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).