Packet socket (AF_PACKET) exploitation¶
AF_PACKET,
net/packet/af_packet.ciç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_req3ile 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 vepacket_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ılantpacket_kbdq_coreblock-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-7308 —
packet_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-38617 —
po->bind_lock/po->numetrafındapacket_set_ring()ilepacket_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 veyaCAP_NET_RAWserbestç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.