AF_UNIX MSG_OOB UAF & SKB-based kernel primitives
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
TL;DR
- Linux >=6.9 introduced a flawed
manage_oob()refactor (5aa57d9f2d53) for AF_UNIXMSG_OOBhandling. Gestapelte zero-length SKBs umgingen die Logik, dieu->oob_skblöschen soll, sodass ein normalesrecv()das Out-of-band-SKB freigeben konnte, während der Pointer weiterhin live war — daraus resultierte CVE-2025-38236. - Ein erneutes Auslösen von
recv(..., MSG_OOB)dereferenziert das hängendestruct sk_buff. MitMSG_PEEKwird der Pfadunix_stream_recv_urg() -> __skb_datagram_iter() -> copy_to_user()zu einem stabilen 1-Byte-arbiträren Kernel-Lese-Primitive; ohneMSG_PEEKerhöht das PrimitiveUNIXCB(oob_skb).consumedbei Offset0x44, d. h. es addiert +4 GiB zum oberen DWORD eines beliebigen 64-Bit-Werts, der bei Offset0x40im neu allozierten Objekt liegt. - Durch Drainen von order-0/1 nicht verschiebbaren Seiten (page-table spray), erzwungenes Freigeben einer SKB-Slab-Seite in den buddy-Allocator und Wiederverwendung der physischen Seite als pipe buffer fälscht der Exploit SKB-Metadaten in kontrolliertem Speicher, um die hängende Seite zu identifizieren und das Lese-Primitive in
.data, vmemmap, per-CPU- und page-table-Regionen zu pivotieren — trotz usercopy hardening. - Dieselbe Seite kann später als oberste Kernel-Stack-Seite eines frisch geklonten Threads recycelt werden.
CONFIG_RANDOMIZE_KSTACK_OFFSETwird so zu einem Orakel: durch Abtasten des Stack-Layouts währendpipe_write()blockiert, wartet der Angreifer, bis die ausgelagertecopy_page_from_iter()-Länge (R14) bei Offset0x40landet, und löst dann die +4 GiB-Inkrementierung aus, um den Stack-Wert zu korruptieren. - Eine selbstschleifende
skb_shinfo()->frag_listhält den UAF-Syscall im Kernel-Raum in einer Schleife, bis ein kooperierender Threadcopy_from_iter()verzögert (viamprotect()über ein VMA mit einem einzelnenMADV_DONTNEED-Loch). Das Aufbrechen der Schleife gibt die Inkrementierung genau dann frei, wenn das Stack-Ziel live ist, wodurch dasbytes-Argument aufgeblasen wird undcopy_page_from_iter()über die pipe buffer-Seite hinaus in die nächste physische Seite schreibt. - Durch Überwachen der pipe-buffer-PFNs und der Page Tables mit dem Lese-Primitive stellt der Angreifer sicher, dass die folgende Seite eine PTE-Seite ist, wandelt den OOB-Copy in beliebige PTE-Schreibvorgänge um und erzielt uneingeschränkten Kernel read/write/execute. Chrome verringerte die Erreichbarkeit, indem es
MSG_OOBfür Renderer blockierte (6711812), und Linux behob den Logikfehler in32ca245464e1und führte zudemCONFIG_AF_UNIX_OOBein, um die Funktion optional zu machen.
Root cause: manage_oob() assumes only one zero-length SKB
unix_stream_read_generic() erwartet, dass jedes von manage_oob() zurückgegebene SKB unix_skb_len() > 0 hat. Nach 93c99f21db36 übersprang manage_oob() den Cleanup-Pfad skb == u->oob_skb, wann immer es zuerst ein von recv(MSG_OOB) übriggelassenes zero-length SKB entfernte. Der nachfolgende Fix (5aa57d9f2d53) setzte zwar vom ersten zero-length SKB zu skb_peek_next() fort, prüfte aber die Länge nicht erneut. Bei zwei aufeinanderfolgenden zero-length SKBs gab die Funktion das zweite leere SKB zurück; unix_stream_read_generic() übersprang es dann, ohne manage_oob() erneut aufzurufen, sodass das echte OOB-SKB dequeued und freigegeben wurde, während u->oob_skb weiterhin darauf zeigte.
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
Vom unix_stream_recv_urg() bereitgestellte Primitive
- 1-byte arbitrary read (repeatable):
state->recv_actor()führt letztlichcopy_to_user(user, skb_sourced_addr, 1)aus. Wenn das dangling SKB in vom Angreifer kontrollierten Speicher (oder in ein kontrolliertes Alias wie eine pipe-Seite) neu alloziert wird, kopiert jederrecv(MSG_OOB | MSG_PEEK)ein Byte aus einer beliebigen Kernel-Adresse, die von__check_object_size()erlaubt ist, in den Userspace, ohne abzustürzen. Das Setzen vonMSG_PEEKerhält den dangling Pointer und erlaubt unbegrenzte Reads. - Constrained write: Wenn
MSG_PEEKnicht gesetzt ist, erhöhtUNIXCB(oob_skb).consumed += 1das 32-Bit-Feld bei Offset0x44. Bei 0x100-ausgerichteten SKB-Allokationen liegt dieses vier Bytes oberhalb eines 8-Byte-ausgerichteten Wortes und verwandelt die Primitive in eine +4 GiB-Inkrement-Operation des Wortes an Offset0x40. Um dies in einen Kernel-Write zu verwandeln, muss ein sensibles 64-Bit-Wert an diesem Offset positioniert werden.
Reallocating the SKB page for arbitrary read
- Drain order-0/1 unmovable freelists: Mappe ein großes read-only anonymes VMA und fault jede Seite, um Page-Table-Allokation zu erzwingen (order-0 unmovable). Das Auffüllen von ~10% des RAM mit Page-Tables stellt sicher, dass nach Erschöpfung der order-0-Listen
skbuff_head_cachefrische Buddy-Seiten zieht. - Spray SKBs and isolate a slab page: Verwende Dutzende Stream-Socketpairs und queue Hunderte kleiner Nachrichten pro Socket (~0x100 Bytes pro SKB), um
skbuff_head_cachezu füllen. Freee ausgewählte SKBs, um eine Ziel-Slab-Seite vollständig unter Angreifer-Kontrolle zu bringen, und überwache derenstruct page-Refcount mittels der entstehenden Read-Primitive. - Return the slab page to the buddy allocator: Freee jedes Objekt auf der Seite und führe dann genug zusätzliche Allokationen/Frees durch, um die Seite aus den SLUB per-CPU partial lists und per-CPU page lists zu drücken, sodass sie als order-1-Seite in die Buddy-Freeliste gelangt.
- Reallocate as pipe buffer: Erzeuge Hunderte Pipes; jede Pipe reserviert mindestens zwei 0x1000-Byte-Datenseiten (
PIPE_MIN_DEF_BUFFERS). Wenn der Buddy-Allocator eine order-1-Seite splittet, benutzt eine Hälfte die freigegebene SKB-Seite wieder. Um zu finden, welche Pipe und welcher Offsetoob_skbaliasiert, schreibe eindeutige Marker-Bytes in fake SKBs, die in den Pipe-Seiten verteilt sind, und rufe wiederholtrecv(MSG_OOB | MSG_PEEK)auf, bis der Marker zurückgegeben wird. - Forge a stable SKB layout: Fülle die aliasierte Pipe-Seite mit einem gefälschten
struct sk_buff, dessendata/head-Pointer undskb_shared_info-Struktur auf beliebige Kernel-Adressen von Interesse zeigen. Da x86_64 SMAP innerhalb voncopy_to_user()deaktiviert, können User-Mode-Adressen als Staging-Buffer dienen, bis Kernel-Pointer bekannt sind. - Respect usercopy hardening: Der Copy gelingt gegen
.data/.bss, vmemmap-Einträge, per-CPU vmalloc-Bereiche, Kernel-Stacks anderer Threads und direct-map-Seiten, die keine höheren Folio-Grenzen überschreiten. Reads gegen.textoder spezialisierte Caches, die von__check_heap_object()abgelehnt werden, liefern einfach-EFAULTzurück, ohne den Prozess zu killen.
Introspecting allocators with the read primitive
- Break KASLR: Lese beliebige IDT-Deskriptoren aus dem fixed mapping bei
CPU_ENTRY_AREA_RO_IDT_VADDR(0xfffffe0000000000) und subtrahiere den bekannten Handler-Offset, um die Kernel-Base wiederherzustellen. - SLUB/buddy state: Globale
.data-Symbole offenbarenkmem_cache-Basen, während vmemmap-Einträge die Typ-Flags jeder Seite, Freelist-Pointer und die besitzende Cache offenlegen. Das Scannen per-CPU vmalloc-Segmente decktstruct kmem_cache_cpu-Instanzen auf, sodass die nächste Allokationsadresse wichtiger Caches (z. B.skbuff_head_cache,kmalloc-cg-192) vorhersagbar wird. - Page tables: Anstatt
mm_structzu lesen (durch usercopy blockiert), durchlaufe die globalepgd_list(struct ptdesc) und gleiche das aktuellemm_structübercpu_tlbstate.loaded_mmab. Sobald das Root-pgdbekannt ist, kann die Primitive jede Page-Table traversieren, um PFNs für Pipe-Buffers, Page-Tables und Kernel-Stacks zu ermitteln.
Recycling the SKB page as the top kernel-stack page
- Freee die kontrollierte Pipe-Seite erneut und bestätige via vmemmap, dass ihr Refcount wieder null ist.
- Alloziere sofort vier Helfer-Pipe-Seiten und freee sie dann in umgekehrter Reihenfolge, sodass das LIFO-Verhalten des Buddy-Allocators deterministisch ist.
- Rufe
clone()auf, um einen Helper-Thread zu erzeugen; Linux-Stacks sind auf x86_64 vier Seiten groß, also werden die vier zuletzt freigegebenen Seiten sein Stack, wobei die zuletzt freigegebene Seite (die ehemalige SKB-Seite) an den höchsten Adressen liegt. - Verifiziere per Page-Table-Walk, dass die top stack PFN des Helper-Threads der rekonstruierten SKB-PFN entspricht.
- Nutze den arbitrary read, um das Stack-Layout zu beobachten, während du den Thread in
pipe_write()lenkst.CONFIG_RANDOMIZE_KSTACK_OFFSETsubtrahiert pro Syscall einen zufälligen 0x0–0x3f0 (aligned) Wert vomRSP; wiederholte Writes kombiniert mitpoll()/read()von einem anderen Thread zeigen, wann der Writer mit dem gewünschten Offset blockiert. Mit etwas Glück liegt das verschüttetecopy_page_from_iter()bytes-Argument (R14) bei Offset0x40innerhalb der rekonstruierten Seite.
Placing fake SKB metadata on the stack
- Verwende
sendmsg()auf einem AF_UNIX datagram socket: der Kernel kopiert das user-sockaddr_unin ein stack-residentessockaddr_storage(bis zu 108 Bytes) und die ancillary data in einen weiteren On-Stack-Buffer, bevor der Syscall blockiert und auf Queue-Platz wartet. Das erlaubt das Platzieren einer präzisen Fake-SKB-Struktur im Stack-Speicher. - Erkenne, wann der Copy abgeschlossen ist, indem du eine 1-Byte-Control-Message lieferst, die sich in einer unmapped User-Seite befindet;
____sys_sendmsg()faultet diese ein, sodass ein Helper-Thread, dermincore()auf dieser Adresse polled, erkennt, wann die Zielseite präsent ist. - Zero-initialisierte Padding durch
CONFIG_INIT_STACK_ALL_ZEROfüllt ungenutzte Felder bequem auf, wodurch ein gültiger SKB-Header ohne zusätzliche Writes entsteht.
Timing the +4 GiB increment with a self-looping frag list
- Forged
skb_shinfo(fakeskb)->frag_listzeigt auf ein zweites Fake-SKB (im vom Angreifer kontrollierten User-Speicher), daslen = 0undnext = &selfhat. Wennskb_walk_frags()diese Liste innerhalb von__skb_datagram_iter()iteriert, dreht die Ausführung in einer Endlosschleife, weil der Iterator nieNULLerreicht und die Copy-Schleife keinen Fortschritt macht. - Halte den recv-Syscall im Kernel laufen, indem das zweite Fake-SKB sich selbst referenziert. Wenn es Zeit ist, das Inkrement auszulösen, ändere einfach aus dem Userspace den
next-Pointer des zweiten SKB aufNULL. Die Schleife beendet sich undunix_stream_recv_urg()führt sofortUNIXCB(oob_skb).consumed += 1aus, was das Objekt betrifft, das gerade die rekonstruierten Stack-Seite bei Offset0x40belegt.
Stalling copy_from_iter() without userfaultfd
- Mappe ein riesiges anonymes RW-VMA und fault es vollständig ein.
- Punch ein Single-Page-Hole mit
madvise(MADV_DONTNEED, hole, PAGE_SIZE)und setze diese Adresse in deniov_iter, der fürwrite(pipefd, user_buf, 0x3000)verwendet wird. - Parallel rufe
mprotect()auf dem gesamten VMA von einem anderen Thread auf. Der Syscall nimmt den mmap write lock und traversiert jede PTE. Wenn der Pipe-Writer das Hole erreicht, blockiert der Page-Fault-Handler am vommprotect()gehaltenen mmap-Lock und pausiertcopy_from_iter()an einem deterministischen Punkt, während der verschüttetebytes-Wert auf dem Stack-Segment liegt, das von der rekonstruierten SKB-Seite gehostet wird.
Turning the increment into arbitrary PTE writes
- Fire the increment: Löse die Frag-Schleife, während
copy_from_iter()gestallt ist, sodass das +4 GiB-Inkrement diebytes-Variable trifft. - Overflow the copy: Sobald der Fault fortgesetzt wird, glaubt
copy_page_from_iter(), es könne >4 GiB in die aktuelle Pipe-Seite kopieren. Nachdem die legitimen 0x2000 Bytes (zwei Pipe-Buffers) gefüllt sind, führt es eine weitere Iteration aus und schreibt die verbleibenden User-Daten in welche physische Seite auch immer der Pipe-Buffer-PFN folgt. - Arrange adjacency: Verwende Allocator-Telemetrie, um den Buddy-Allocator dazu zu bringen, eine prosesseigene PTE-Seite unmittelbar nach der Ziel-Pipe-Buffer-Seite zu platzieren (z. B. abwechselnd Pipe-Seiten allozieren und neue virtuelle Bereiche touchen, um Page-Table-Allokation zu triggern, bis die PFNs innerhalb desselben 2 MiB pageblocks ausgerichtet sind).
- Overwrite page tables: Kode gewünschte PTE-Einträge in den zusätzlichen 0x1000 Bytes User-Daten, sodass der OOB
copy_from_iter()die benachbarte Seite mit vom Angreifer gewählten Einträgen füllt und RW/RWX-User-Mappings von Kernel-physischem Speicher gewährt oder bestehende Einträge so umschreibt, dass SMEP/SMAP deaktiviert werden.
Mitigations / hardening ideas
- Kernel: Wende
32ca245464e1479bfea8592b9db227fdc1641705an (validiert SKBs korrekt nach) und erwäge, AF_UNIX OOB komplett zu deaktivieren, sofern nicht strikt benötigt, viaCONFIG_AF_UNIX_OOB(5155cbcdbf03). Härtetmanage_oob()mit zusätzlichen Sanity-Checks (z. B. Schleife bisunix_skb_len() > 0) und auditiere andere Socket-Protokolle auf ähnliche Annahmen. - Sandboxing: Filtere
MSG_OOB/MSG_PEEK-Flags in seccomp-Profilen oder höherstufigen Broker-APIs (Chrome-Änderung6711812blockiert jetzt renderer-seitigesMSG_OOB). - Allocator defenses: Das Verstärken von SLUB-Freelist-Randomisierung oder das Erzwingen von Per-Cache-Page-Coloring würde deterministisches Page-Recycling erschweren; eine Limitierung der Pipe-Buffer-Anzahl reduziert ebenfalls die Realloc-Reliabilität.
- Monitoring: Exponiere hohe Raten von Page-Table-Allokationen oder abnormales Pipe-Usage via Telemetrie — dieser Exploit verbraucht große Mengen an Page-Tables und Pipe-Buffern.
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
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks

