AF_UNIX MSG_OOB UAF & SKB-based kernel primitives
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Opsomming
- Linux >=6.9 het ’n foutiewe
manage_oob()refactor (5aa57d9f2d53) vir AF_UNIXMSG_OOBhantering bekend gestel. Gestapelde zero-length SKBs omseil die logika watu->oob_skbskoonmaak, sodat ’n gewonerecv()die out-of-band SKB kon vrymaak terwyl die pointer steeds lewend was, wat gelei het tot CVE-2025-38236. - Heraktiveer van
recv(..., MSG_OOB)dereferensieer die danglingstruct sk_buff. MetMSG_PEEKword die padunix_stream_recv_urg() -> __skb_datagram_iter() -> copy_to_user()’n stabiele 1-byte arbitrary kernel read; sonderMSG_PEEKverhoog die primitiveUNIXCB(oob_skb).consumedby offset0x44, d.w.s. voeg +4 GiB by die boonste dword van enige 64-bit waarde wat by offset0x40in die heralloceerde objek geplaas is. - Deur order-0/1 unmovable pages leeg te dreineer (page-table spray), ’n SKB slab page geforceerd in die buddy allocator vry te maak, en die fisiese bladsy as ’n pipe buffer te hergebruik, smeed die exploit SKB metadata in beheerde geheue om die dangling bladsy te identifiseer en die read-primitive na
.data, vmemmap, per-CPU, en page-table streke te draai ondanks usercopy hardening. - Dieselfde bladsy kan later as die boonste kernel-stack bladsy van ’n pas gekloonde draad herwin word.
CONFIG_RANDOMIZE_KSTACK_OFFSETword ’n orakel: deur die stack-layout te peil terwylpipe_write()blokkeer, wag die aanvaller totdat die uitgespoeldecopy_page_from_iter()lengte (R14) by offset0x40land, en aktiveer dan die +4 GiB verhoging om die stack-waarde te korrupteer. - ’n Self-looping
skb_shinfo()->frag_listhou die UAF syscall in kernel-ruimte draai totdat ’n samewerkende draadcopy_from_iter()laat stagneer (viamprotect()oor ’n VMA wat ’n enkeleMADV_DONTNEEDgap bevat). Breek van die lus laat die verhoging vry presies wanneer die stack-doel lewendig is, wat diebytesargument opblaas sodatcopy_page_from_iter()verby die pipe buffer bladsy skryf en in die volgende fisiese bladsy beland. - Deur pipe-buffer PFNs en page tables met die read-primitive te monitor, verseker die aanvaller dat die volgende bladsy ’n PTE-bladsy is, skakel die OOB copy om na arbitrary PTE writes, en verkry onbeperkte kernel read/write/execute. Chrome het bereikbaarheid verlaag deur
MSG_OOBvan renderers te blokkeer (6711812), en Linux het die logika-fout reggestel in32ca245464e1enCONFIG_AF_UNIX_OOBbekendgestel om die funksie opsioneel te maak.
Hoofoorzaak: manage_oob() neem net een zero-length SKB aan
unix_stream_read_generic() verwag dat elke SKB wat deur manage_oob() teruggegee word unix_skb_len() > 0 het. Na 93c99f21db36 het manage_oob() die skb == u->oob_skb cleanup-pad oorgeslaan wanneer dit eerstens ’n zero-length SKB verwyder het wat deur recv(MSG_OOB) agtergelaat is. Die daaropvolgende herstel (5aa57d9f2d53) het steeds van die eerste zero-length SKB na skb_peek_next() gevorder sonder om die lengte weer na te gaan. Met twee opeenvolgende zero-length SKBs het die funksie die tweede leë SKB teruggegee; unix_stream_read_generic() het dit toe oorgeslaan sonder om weer manage_oob() te roep, sodat die werklike OOB SKB gedekeurieëer en vrygemaak is terwyl u->oob_skb steeds daarna gewys het.
Minimale trigger-sekwensie
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
Primitives exposed by unix_stream_recv_urg()
- 1-byte arbitrary read (repeatable):
state->recv_actor()voer uiteindelikcopy_to_user(user, skb_sourced_addr, 1)uit. As die dangling SKB heralloceer word in attacker-controlled memory (of in ’n beheerde alias soos ’n pipe page), kopieer elkerecv(MSG_OOB | MSG_PEEK)’n byte van ’n arbitrêre kernel-adres wat deur__check_object_size()toegelaat word na gebruikersruimte sonder om te crash. DeurMSG_PEEKaan te laat, word die dangling pointer behouden vir onbeperkte reads. - Constrained write: Wanneer
MSG_PEEKuit is, verhoogUNIXCB(oob_skb).consumed += 1die 32-bit veld by offset0x44. Op 0x100-geïntegreerde SKB-allokasies sit dit vier bytes bo ’n 8-byte-uitgelijnde woord, wat die primitive omskakel in ’n +4 GiB increment van die woord by offset0x40. Om dit ’n kernel write te maak, verg dit om ’n sensitiewe 64-bit waarde by daardie offset te plaas.
Reallocating the SKB page for arbitrary read
- Drain order-0/1 unmovable freelists: Map ’n reuse read-only anonymous VMA en fault elke bladsy om page-table allokasie te dwing (order-0 unmovable). Vul ~10% van RAM met page tables om te verseker dat opvolgende
skbuff_head_cacheallokasies vars buddy pages trek sodra order-0 lists uitgeput is. - Spray SKBs and isolate a slab page: Gebruik dosyne stream socketpairs en queue honderde klein messages per socket (~0x100 bytes per SKB) om
skbuff_head_cachete bevolk. Free gekose SKBs om ’n teiken slab page heeltemal onder attacker control te plaas en monitor systruct pagerefcount via die verkrygde read primitive. - Return the slab page to the buddy allocator: Free elke object op die bladsy, en voer dan genoeg addisionele allocations/frees uit om die bladsy uit SLUB per-CPU partial lists en per-CPU page lists te stoot sodat dit ’n order-1 bladsy op die buddy freelist word.
- Reallocate as pipe buffer: Skep honderde pipes; elke pipe reserveer minstens twee 0x1000-byte data bladsye (
PIPE_MIN_DEF_BUFFERS). Wanneer die buddy allocator ’n order-1 bladsy split, hergebruik een helfte die vrygestelde SKB-bladsy. Om te lokaliseer watter pipe en watter offsetoob_skbalias, skryf unike marker bytes in fake SKBs wat regdeur pipe pages gestoor is en roep herhaalderecv(MSG_OOB | MSG_PEEK)tot die marker teruggegee word. - Forge a stable SKB layout: Vul die aliased pipe page met ’n fake
struct sk_buffwaarvandata/headpointers enskb_shared_infostruktuur na arbitrêre kernel adresse van belang wys. Omdat x86_64 SMAP binnecopy_to_user()uitskakel, kan user-mode adresse as staging buffers dien totdat kernel pointers bekend is. - Respect usercopy hardening: Die copy slaag teen
.data/.bss, vmemmap entries, per-CPU vmalloc ranges, ander threads se kernel stacks, en direct-map pages wat nie oor hoër-orde folio-grense straddle nie. Reads teen.textof gespesialiseerde caches wat deur__check_heap_object()geweier word, gee net-EFAULTterug sonder om die proses te kill.
Introspecting allocators with the read primitive
- Break KASLR: Lees enige IDT descriptor vanaf die fixed mapping by
CPU_ENTRY_AREA_RO_IDT_VADDR(0xfffffe0000000000) en trek die bekende handler offset af om die kernel base te herwin. - SLUB/buddy state: Globale
.datasymboles openbaarkmem_cachebases, terwyl vmemmap entries elke bladsy se type flags, freelist pointer, en eienaar cache blootlê. Skandeer per-CPU vmalloc segmente omstruct kmem_cache_cpuinstansies te vind sodat die volgende allocation adres van sleutel caches (bv.skbuff_head_cache,kmalloc-cg-192) voorspelbaar raak. - Page tables: In plaas daarvan om
mm_structte lees (wat deur usercopy geblokkeer word), loop die globalepgd_list(struct ptdesc) en pas die huidigemm_structviacpu_tlbstate.loaded_mm. Sodra die rootpgdbekend is, kan die primitive elke page table traverseer om PFNs vir pipe buffers, page tables, en kernel stacks te map.
Recycling the SKB page as the top kernel-stack page
- Free die beheerste pipe page weer en bevestig via vmemmap dat sy refcount terugkeer na nul.
- Allokeer onmiddellik vier helper pipe pages en free dit dan in omgekeerde volgorde sodat die buddy allocator se LIFO-gedrag deterministies is.
- Roep
clone()om ’n helper thread te spawn; Linux stacks is vier bladsye op x86_64, so die vier mees onlangs vrygestelde bladsye word sy stack, met die laaste vrygestelde bladsy (die voormalige SKB page) by die hoogste adresse. - Verifieer via page-table walk dat die helper thread se top stack PFN gelyk is aan die gerecyclede SKB PFN.
- Gebruik die arbitrary read om die stack layout te observeer terwyl jy die thread stuur na
pipe_write().CONFIG_RANDOMIZE_KSTACK_OFFSETtrek ’n ewekansige 0x0–0x3f0 (uitgelijnd) vanRSPper syscall; herhaalde writes gekombineer metpoll()/read()van ’n ander thread openbaar wanneer die writer block met die gewenste offset. Wanneer geluk, sit die spilledcopy_page_from_iter()bytesargument (R14) by offset0x40binne die gerecyclede bladsy.
Placing fake SKB metadata on the stack
- Gebruik
sendmsg()op ’n AF_UNIX datagram socket: die kernel kopieer die usersockaddr_unin ’n stack-residentsockaddr_storage(tot 108 bytes) en die ancillary data in ’n ander on-stack buffer voordat die syscall block vir queue space. Dit laat toe om ’n presiese fake SKB struktuur in stack memory te plant. - Detecteer wanneer die copy klaar is deur ’n 1-byte control message te verskaf wat in ’n unmapped user page geleë is;
____sys_sendmsg()fault dit in, so ’n helper thread watmincore()op daardie adres poll, leer wanneer die bestemming-bladsy teenwoordig is. - Zero-initialized padding van
CONFIG_INIT_STACK_ALL_ZEROvul handig die ongebruikte velde, wat ’n geldige SKB header voltooi sonder ekstra skryfwerk.
Timing the +4 GiB increment with a self-looping frag list
- Forge
skb_shinfo(fakeskb)->frag_listom na ’n tweede fake SKB te wys (gestoor in attacker-controlled user memory) watlen = 0ennext = &selfhet. Wanneerskb_walk_frags()hierdie lys iter binne__skb_datagram_iter(), spin uitvoering oneindig want die iterator bereik nooitNULLnie en die copy-lus maak geen vordering nie. - Hou die recv syscall aan die gang binne die kernel deur die tweede fake SKB self-loop te laat. Wanneer dit tyd is om die increment te vuur, verander eenvoudig die tweede SKB se
nextpointer vanaf user space naNULL. Die lus eindig enunix_stream_recv_urg()voer onmiddellikUNIXCB(oob_skb).consumed += 1uit een keer, wat enige object wat tans die gerecyclede stack page by offset0x40huisves, beïnvloed.
Stalling copy_from_iter() without userfaultfd
- Map ’n reuse anonymous RW VMA en fault dit volledig in.
- Punch ’n single-page gap met
madvise(MADV_DONTNEED, hole, PAGE_SIZE)en plaas daardie adres binne dieiov_iterwat virwrite(pipefd, user_buf, 0x3000)gebruik word. - Parallel, roep
mprotect()op die hele VMA vanaf ’n ander thread. Die syscall gryp die mmap write lock en loop elke PTE. Wanneer die pipe writer die gat bereik, blokkeer die page fault handler op die mmap lock wat deurmprotect()gehou word, en pauseercopy_from_iter()op ’n deterministiese punt terwyl die spilledbyteswaarde op die stack segment wat deur die gerecyclede SKB page gehost word, lê.
Turning the increment into arbitrary PTE writes
- Fire the increment: Vrylê die frag loop terwyl
copy_from_iter()gestal is sodat die +4 GiB increment diebytesvariabele tref. - Overflow the copy: Sodra die fault hervat, glo
copy_page_from_iter()dat dit >4 GiB kan kopieer in die huidige pipe page. Na die vulling van die legitime 0x2000 bytes (twee pipe buffers), voer dit nog ’n iterasie uit en skryf die oorblywende user data in watter fisiese bladsy ook al die pipe buffer PFN volg. - Arrange adjacency: Gebruik allocator telemetry om die buddy allocator te dwing om ’n process-owned PTE page onmiddellik na die teiken pipe buffer page te plaas (bv. wissel tussen allocating pipe pages en aanraking van nuwe virtual ranges om page-table allokasie te trigger totdat die PFNs binne dieselfde 2 MiB pageblock uitlijn).
- Overwrite page tables: Kodeer gewenste PTE entries in die ekstra 0x1000 bytes van user data sodat die OOB
copy_from_iter()die aangrensende bladsy met attacker-gekose entries vul, wat RW/RWX user mappings van kernel fisiese geheue gee of bestaande entries oorskryf om SMEP/SMAP uit te skakel.
Mitigations / hardening ideas
- Kernel: Pas
32ca245464e1479bfea8592b9db227fdc1641705toe (properly revalidates SKBs) en oorweeg om AF_UNIX OOB heeltemal te deaktiveer tensy dit streng nodig is viaCONFIG_AF_UNIX_OOB(5155cbcdbf03). Verhardmanage_oob()met addisionele sanity checks (bv. lus totdatunix_skb_len() > 0) en oudit ander socket protocols vir soortgelyke aannames. - Sandboxing: Filter
MSG_OOB/MSG_PEEKflags in seccomp profiles of hoërvlak broker APIs (Chrome change6711812blokkeer nou renderer-sideMSG_OOB). - Allocator defenses: Versterking van SLUB freelist randomization of afdwing van per-cache page coloring sou deterministiese page recycling bemoeilik; pipeline-limiting van pipe buffer tellings verminder ook reallocation betroubaarheid.
- Monitoring: Blootlê high-rate page-table allokasie of abnormale pipe gebruik via telemetry—hierdie exploit verbruik groot hoeveelhede page tables en pipe buffers.
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
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.


