Skip to content

Packet socket (AF_PACKET) exploitation

AF_PACKET, net/packet/af_packet.c içinde büyük, mmap-backed bir ring-buffer ve protocol-hook attack surface'i açar; bu, tekrar tekrar local privilege escalation vermiştir ve unprivileged kullanıcılar tarafından user namespace'ler üzerinden erişilebilir.

Mechanism

Note

AF_PACKET socket'leri userspace'e L2 frame'lere doğrudan erişim verir. Güçlüdürler çünkü (a) kernel ring buffer'larını page allocator'dan allocate edip userspace'e mmap ederler, (b) tpacket_rcv() / tpacket_snd() içinde karmaşık, attacker-influenced parsing'i sürerler ve (c) socket state'ini ring setup ile eşzamanlı değiştiren protocol hook'ları (register_prot_hook() / __unregister_prot_hook()) ve fanout group'ları tutarlar. Bir tane oluşturmak yalnızca mevcut netns içinde CAP_NET_RAW gerektirir — ki CONFIG_USER_NS=y olduğunda unprivileged bir process bunu yeni bir user+network namespace içinde bedavaya elde eder. Zengin state machine + page-granular allocation'lar + namespaced erişilebilirlik kombinasyonu, AF_PACKET'in neden tekrar eden bir LPE surface'i olduğunun sebebidir.

Çekirdek hareketli parçalar:

  • PACKET_RX_RING / PACKET_TX_RING (setsockopt), tpacket_req / tpacket_req3 ile tanımlanan bir ring talep eder (tp_block_size, tp_block_nr, tp_frame_size, tp_sizeof_priv). packet_set_ring() onu validate edip inşa eder.
  • Block'lar alloc_pg_vec() tarafından physically contiguous order-N page'ler olarak allocate edilir ve packet_mmap() (vm_insert_page()) üzerinden userspace'e açılır; bu zero-copy kernel↔user page'leri oluşturur — kendileri de faydalı bir spray/leak primitive'idir.
  • PACKET_VERSION, TPACKET_V1/V2/V3 arasında geçiş yapar; V3, init_prb_bdqc() tarafından kullanılan tpacket_kbdq_core block-descriptor state'ini ekler.
  • PACKET_FANOUT, socket'leri bir load-balancing group'una katar; cross-socket concurrency ekler.

Walkthrough

Çoğu AF_PACKET exploit'inin başladığı minimal bir socket + ring setup'ı:

int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));   /* needs CAP_NET_RAW */

int v = TPACKET_V3;
setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));

struct tpacket_req3 req = {
    .tp_block_size = 0x8000,
    .tp_block_nr   = 1,
    .tp_frame_size = 0x800,
    .tp_frame_nr   = 16,
};
setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));

void *ring = mmap(NULL, 0x8000, PROT_READ|PROT_WRITE, MAP_SHARED, s, 0);

Gerçek ayrıcalık olmadan surface'e ulaşmak standart unprivileged entrypoint'tir:

unshare(CLONE_NEWUSER | CLONE_NEWNET);   /* CAP_NET_RAW inside the new netns */
/* write uid_map/gid_map, then create AF_PACKET sockets as "root" in-ns */

Bu surface'in farklı yönlerini zorlayan kayda değer geçmiş:

  • CVE-2017-7308packet_set_ring() V3 block-size validation'ında bir signedness bug'ı → controlled heap OOB write. Bkz. af-packet-tpacket-v3-ring-heap-oob-write.
  • CVE-2020-14386 — af_packet subsystem'inde (frame parsing) LPE için kullanılabilir bir memory corruption; aynı CAP_NET_RAW-via-userns erişilebilirliği.
  • CVE-2025-38617po->bind_lock / po->num etrafında packet_set_ring() ile packet_notifier() arasında bir race. Bkz. packet-socket-race-within-a-race.
Ring'lerin neden iyi exploit primitive'leri olduğu

Ring block'ları doğrudan page allocator'dan gelir (alloc_pg_vec() üzerinden __get_free_pages), bu yüzden ideal cross-cache / page-spray malzemesidir ve mmap görünümü kernel page'leri üzerinde stabil, attacker-readable/writable bir pencere verir — hem leak'ler hem de freed object'leri overlay etmek için kullanışlıdır.

Warning

AF_PACKET state değişiklikleri (bind, fanout join/leave, ring (re)allocation) bir po->bind_lock ile po->pg_vec_lock karışımı altında olur; buradaki lock-ordering boşlukları tam olarak race-condition bug'larının yaşadığı yerdir. Reconfiguration'ın ortasında bir lock bırakan herhangi bir path'i şüpheli say.

Detection

Unprivileged/namespaced context'lerden AF_PACKET socket'lerinin oluşturulması, alışılmadık PACKET_RX_RING/PACKET_FANOUT setsockopt pattern'leri ve unshare(CLONE_NEWUSER|CLONE_NEWNET)'in ardından raw-socket oluşturma gözlemlenebilir sinyallerdir (seccomp/LSM/auditd).

Mitigation

  • Surface'i kısıtla: socket(AF_PACKET, ...)'i seccomp ile reddet veya CAP_NET_RAW serbestçe elde edilebilir olmasın diye unprivileged user namespace'leri engelle (kernel.unprivileged_userns_clone=0).
  • Kernel'leri patch'li tut; yukarıdaki CVE'lerin her birinin bir upstream fix'i var.
  • KASLR/SMEP/SMAP hardening'i (kptr_restrict, kernel.dmesg_restrict), bu bug'ların dayandığı post-corruption aşamaları için çıtayı yükseltir.

References