AF_UNIX MSG_OOB UAF & SKB-based kernel primitives
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Sažetak
- Linux >=6.9 je uveo problematičan refaktor
manage_oob()(5aa57d9f2d53) za AF_UNIXMSG_OOBhandling. Složeni zero-length SKB-ovi su zaobišli logiku koja brišeu->oob_skb, pa je običanrecv()mogao osloboditi out-of-band SKB dok je pokazivač ostajao živ, što je dovelo do CVE-2025-38236. - Ponovno pokretanje
recv(..., MSG_OOB)dereferencira danglingstruct sk_buff. SaMSG_PEEK, putanjaunix_stream_recv_urg() -> __skb_datagram_iter() -> copy_to_user()postaje stabilno 1-bajtno arbitrarno kernel čitanje; bezMSG_PEEKprimitiv povećavaUNIXCB(oob_skb).consumedna offsetu0x44, tj. dodaje +4 GiB gornjem dword-u bilo koje 64-bit vrednosti smeštene na offsetu0x40unutar ponovo alociranog objekta. - Ispraznivši order-0/1 unmovable stranice (page-table spray), prisilnim oslobađanjem SKB slab stranice u buddy allocator i ponovnim korišćenjem fizičke stranice kao pipe buffer, exploit falsifikuje SKB metadata u kontrolisanoj memoriji da identifikuje dangling stranicu i pivotira read primitiv u
.data, vmemmap, per-CPU i page-table regione uprkos usercopy hardening-u. - Ista stranica kasnije se može reciklirati kao gornja kernel-stack stranica sveže kloniranog threada.
CONFIG_RANDOMIZE_KSTACK_OFFSETpostaje orakl: ispitujući layout steka dokpipe_write()blokira, napadač čeka dok prosuta dužinacopy_page_from_iter()(R14) ne dospe na offset0x40, pa onda pusti +4 GiB inkrement da korumpira vrednost na steku. - Self-looping
skb_shinfo()->frag_listdrži UAF syscall u petlji u kernel prostoru dok saradnički thread ne zaustavicopy_from_iter()(putemmprotect()nad VMA koja sadrži jednuMADV_DONTNEEDrupu). Prekidanje petlje oslobađa inkrement tačno kada je ciljani stack lokalan, uvećavajući argumentbytestako dacopy_page_from_iter()piše preko pipe buffer stranice u sledeću fizičku stranicu. - Praćenjem PFN-ova pipe-buffer-a i page table-a pomoću read primitiva, napadač osigurava da je sledeća stranica PTE stranica, konvertuje OOB copy u arbitrarne PTE write-ove i dobija neograničeno kernel read/write/execute. Chrome je smanjio dostupnost blokiranjem
MSG_OOBiz renderera (6711812), a Linux je ispravio logičku grešku u32ca245464e1i uveoCONFIG_AF_UNIX_OOBda bi opcija postala izborna.
Root cause: manage_oob() assumes only one zero-length SKB
unix_stream_read_generic() očekuje da svaki SKB koji vrati manage_oob() ima unix_skb_len() > 0. Posle 93c99f21db36, manage_oob() je preskakao cleanup putanju skb == u->oob_skb kad god bi prvo uklonio zero-length SKB koji je ostao nakon recv(MSG_OOB). Naknadno rešenje (5aa57d9f2d53) i dalje je napredovalo sa prvog zero-length SKB-a na skb_peek_next() bez ponovnog provere dužine. Sa dva uzastopna zero-length SKB-a, funkcija je vratila drugi prazan SKB; unix_stream_read_generic() ga je onda preskočio bez ponovnog poziva manage_oob(), tako da je pravi OOB SKB bio dequeued i oslobođen dok je u->oob_skb i dalje pokazivao na njega.
Minimal trigger sequence
char byte;
int socks[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, socks);
for (int i = 0; i < 2; ++i) {
send(socks[1], "A", 1, MSG_OOB);
recv(socks[0], &byte, 1, MSG_OOB);
}
send(socks[1], "A", 1, MSG_OOB); // SKB3, u->oob_skb = SKB3
recv(socks[0], &byte, 1, 0); // normal recv frees SKB3
recv(socks[0], &byte, 1, MSG_OOB); // dangling u->oob_skb
Primitivi koje izlaže unix_stream_recv_urg()
- 1-byte arbitrary read (repeatable):
state->recv_actor()na kraju izvodicopy_to_user(user, skb_sourced_addr, 1). Ako se dangling SKB ponovo alocira u memoriju pod kontrolom napadača (ili u kontrolisani alias kao što je pipe page), svakirecv(MSG_OOB | MSG_PEEK)kopira bajt sa proizvoljne kernel adrese koju dozvoljava__check_object_size()u korisnički prostor bez rušenja procesa. OstavitiMSG_PEEKomogućava neograničeno čitanje jer sačuva dangling pointer. - Constrained write: Kada je
MSG_PEEKisključen,UNIXCB(oob_skb).consumed += 1uvećava 32-bitno polje na offsetu0x44. Na 0x100-poravnatim SKB alokacijama ovo leži četiri bajta iznad 8-bajt-poravnatog word-a, pretvarajući primitiv u +4 GiB inkrement word-a koji je na offsetu0x40. Da bi se ovo pretvorilo u kernel write, potrebno je pozicionirati osetljivu 64-bit vrednost na taj offset.
Realokacija SKB stranice za proizvoljno čitanje
- Isprazniti order-0/1 unmovable freeliste: Mapirati veliki read-only anonymous VMA i izazvati fault za svaku stranicu da bi se forsirala alokacija page-table-a (order-0 unmovable). Popunjavanje ~10% RAM-a page tabelama osigurava da će naredne
skbuff_head_cachealokacije uzimati sveže buddy stranice kada se order-0 liste iscrpe. - Spray SKB-ova i izolovati slab stranicu: Koristiti desetine stream socketpair-ova i staviti stotine malih poruka po socketu (~0x100 bajtova po SKB) da se popuni
skbuff_head_cache. Otpustiti izabrane SKB-ove da se ciljna slab stranica potpuno dovede pod kontrolu napadača i pratiti njenstruct pagerefcount putem nastalog read primitiva. - Vratiti slab stranicu u buddy allocator: Otpustiti svaki objekat na stranici, zatim izvršiti dovoljno dodatnih alokacija/oslobađanja da se stranica izbaci iz SLUB per-CPU partial listi i per-CPU page listi tako da postane order-1 stranica na buddy freelistu.
- Ponovo alocirati kao pipe buffer: Napraviti stotine pipe-ova; svaki pipe rezerviše najmanje dve 0x1000-bajt data stranice (
PIPE_MIN_DEF_BUFFERS). Kada buddy allocator split-uje order-1 stranicu, jedna polovina može ponovo koristiti oslobođenu SKB stranicu. Da se locira koji pipe i koji offset alias-ujeoob_skb, upisati jedinstvene marker bajtove u lažne SKB-ove smeštene širom pipe stranica i izdavati ponovljenerecv(MSG_OOB | MSG_PEEK)pozive dok marker ne bude vraćen. - Forgovati stabilan SKB layout: Popuniti alias-ovanu pipe stranicu lažnim
struct sk_buffčijidata/headpokazivači iskb_shared_infostruktura pokazuju na proizvoljne kernel adrese od interesa. Pošto x86_64 onemogućava SMAP unutarcopy_to_user(), user-mode adrese mogu služiti kao staging baferi dok kernel pokazivači ne postanu poznati. - Poštovati usercopy hardening: Kopija uspeva protiv
.data/.bss, vmemmap unosa, per-CPU vmalloc opsega, kernel stack-ova drugih thread-ova i direct-map stranica koje ne prelaze granice višeg-order folio-a. Čitanja prema.textili specijalizovanim keševima koja__check_heap_object()odbije jednostavno vraćaju-EFAULTbez ubijanja procesa.
Introspekcija allocator-a pomoću read primitiva
- Break KASLR: Pročitati bilo koji IDT deskriptor iz fixed mapping-a na
CPU_ENTRY_AREA_RO_IDT_VADDR(0xfffffe0000000000) i oduzeti poznati handler offset da se obnovi kernel base. - SLUB/buddy stanje: Globalni
.datasimboli otkrivajukmem_cachebaze, dok vmemmap unosi izlažu tip flag-ove svake stranice, freelist pokazivač i owning cache. Skeniranje per-CPU vmalloc segmenata otkrivastruct kmem_cache_cpuinstance tako da sledeća adresa alokacije ključnih keševa (npr.skbuff_head_cache,kmalloc-cg-192) postane predvidljiva. - Page tables: Umesto čitanja
mm_struct(blokirano od usercopy), proći kroz globalnipgd_list(struct ptdesc) i uskladiti trenutnimm_structputemcpu_tlbstate.loaded_mm. Kada je rootpgdpoznat, primitiv može traversirati sve page table-ove da mapira PFN-ove za pipe buffer-e, page table-ove i kernel stack-ove.
Recikliranje SKB stranice kao gornja kernel-stack stranica
- Otpustiti kontrolisanu pipe stranicu ponovo i potvrditi preko vmemmap da se njen refcount vrati na nulu.
- Odmah alocirati četiri pomoćne pipe stranice i zatim ih otpustiti u obrnutom redosledu da bi LIFO ponašanje buddy allocator-a bilo determinističko.
- Pozvati
clone()da se pokrene pomoćni thread; Linux stack-ovi su četiri stranice na x86_64, tako da četiri najrecentnije oslobođene stranice postaju njegov stack, pri čemu je poslednja oslobođena stranica (bivša SKB stranica) na najvišim adresama. - Verifikovati preko page-table walka da li PFN helper thread-ovog top stack-a odgovara recikliranom SKB PFN-u.
- Upotrebiti arbitrary read da se posmatra layout stack-a dok se thread usmerava u
pipe_write().CONFIG_RANDOMIZE_KSTACK_OFFSEToduzima nasumičan 0x0–0x3f0 (poravnat) odRSPpo syscall-u; ponovljeni write-ovi u kombinaciji sapoll()/read()iz drugog threada otkrivaju kada writer blokira sa željenim offsetom. Kada se poklopi, prosutacopy_page_from_iter()bytesargument (R14) se nalazi na offsetu0x40unutar reciklirane stranice.
Postavljanje lažnih SKB metadata na stack
- Koristiti
sendmsg()na AF_UNIX datagram socketu: kernel kopira korisničkisockaddr_unu stack-residentsockaddr_storage(do 108 bajtova) i ancillary podatke u drugi on-stack bafer pre nego što syscall blokira čekajući prostor u queue-u. Ovo omogućava postavljanje precizne lažne SKB strukture u memoriju stack-a. - Detektovati kada je kopija završena snabdevanjem 1-bajt control message koji se nalazi u nemapiranoj korisničkoj strani;
____sys_sendmsg()izaziva fault prilikom toga, tako da pomoćni thread koji poll-ujemincore()na toj adresi saznaje kada destinaciona stranica postane prisutna. - Zero-inicijalizovani padding iz
CONFIG_INIT_STACK_ALL_ZEROzgodno popunjava neiskorišćena polja, dovršavajući validan SKB header bez dodatnih upisa.
C time+ing the +4 GiB increment sa self-looping frag list-om
- Forgovati
skb_shinfo(fakeskb)->frag_listda pokazuje na drugi lažni SKB (smešten u memoriji pod kontrolom napadača) koji imalen = 0inext = &self. Kadaskb_walk_frags()iterira ovu listu unutar__skb_datagram_iter(), izvršavanje se zavrti u nedogled jer iterator nikad ne dostigneNULLi copy petlja ne napreduje. - Ostaviti recv syscall da trči unutar kernela dozvoljavajući drugom lažnom SKB-u da se self-loop-uje. Kada dođe vreme da se ispali inkrement, jednostavno promeniti
nextpokazivač drugog SKB-a iz korisničkog prostora uNULL. Petlja izlazi iunix_stream_recv_urg()odmah izvršavaUNIXCB(oob_skb).consumed += 1jednom, utičući na bilo koji objekat koji trenutno zauzima recikliranu stack stranicu na offsetu0x40.
Zastavljanje copy_from_iter() bez userfaultfd
- Mapirati ogromnu anonymous RW VMA i fault-ovati je u potpunosti.
- Napraviti jednodržan hole sa
madvise(MADV_DONTNEED, hole, PAGE_SIZE)i staviti tu adresu unutariov_iterkoji se koristi zawrite(pipefd, user_buf, 0x3000). - Paralelno pozvati
mprotect()na celoj VMA iz drugog threada. Syscall zahvata mmap write lock i prolazi kroz svaki PTE. Kada pipe writer stigne do hole-a, page fault handler blokira na mmap lock koji držimprotect(), pauzirajućicopy_from_iter()u determinističkoj tački dok se prosutibytesvrednost nalazi na segmentu stack-a hostovanom od strane reciklirane SKB stranice.
Pretvaranje inkrementa u proizvoljne PTE write-ove
- Ispaliti inkrement: Otpustiti frag loop dok je
copy_from_iter()zaustavljen tako da +4 GiB inkrement pogodibytesvarijablu. - Overflow copy-a: Kada se fault nastavi,
copy_page_from_iter()veruje da može kopirati >4 GiB u trenutnu pipe stranicu. Nakon popunjavanja legitimnih 0x2000 bajtova (dva pipe buffera), izvršava još jednu iteraciju i upisuje preostale korisničke podatke u fizičku stranicu koja sledi PFN pipe buffera. - Rasporediti susedstvo: Koristeći telemetry allocator-a, forsirati buddy allocator da postavi process-owned PTE stranicu odmah posle ciljane pipe buffer stranice (npr. naizmenično alocirati pipe stranice i dirati nove virtuelne opsege da bi se izazvala alokacija page-table-a dok se PFN-ovi ne poravnaju unutar istog 2 MiB pageblock-a).
- Overwrite-ovati page table-ove: Kodirati željene PTE unose u dodatnih 0x1000 bajtova korisničkih podataka tako da OOB
copy_from_iter()popuni susednu stranicu sa unesenim entry-ima koje je izabrao napadač, dajući RW/RWX korisničke mape kernel fizičke memorije ili prepisujući postojeće unose da onemoguće SMEP/SMAP.
Mitigations / hardening ideas
- Kernel: Apply
32ca245464e1479bfea8592b9db227fdc1641705(properly revalidates SKBs) i razmotriti onemogućavanje AF_UNIX OOB potpuno osim ako nije striktno potrebno prekoCONFIG_AF_UNIX_OOB(5155cbcdbf03). Harden-ovatimanage_oob()dodatnim sanity check-ovima (npr. loop dokunix_skb_len() > 0) i audit-ovati druge socket protokole za slična pretpostavljanja. - Sandboxing: Filtrirati
MSG_OOB/MSG_PEEKflag-ove u seccomp profilima ili višem nivou broker API-ja (Chrome change6711812sada blokira renderer-sideMSG_OOB). - Allocator defenses: Jačanje SLUB freelist randomizacije ili forsiranje per-cache page coloring bi otežalo determinističko recikliranje stranica; ograničavanje broja pipe buffera takođe smanjuje pouzdanost rerne alokacije.
- Monitoring: Izložiti visoke stope page-table alokacija ili abnormalno korišćenje pipe-ova putem telemetrije — ovaj exploit troši velike količine page tabela i pipe buffera.
References
- Project Zero – “From Chrome renderer code exec to kernel with MSG_OOB”
- Linux fix for CVE-2025-38236 (
manage_oobrevalidation) - Chromium CL 6711812 – block
MSG_OOBin renderers - Commit adding
CONFIG_AF_UNIX_OOBprompt
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.


