AF_PACKET TPACKET_V3 rx_owner_map double-free (CVE-2021-22600)¶
packet_set_ring()içinde bir double-free: packet-ring teardown'urx_owner_map'i eşleşen birpg_vecolmadan free ettiğinde ortaya çıkar ve local privilege escalation için exploit edilebilir.
Mechanism¶
Root cause: koşulsuz bir bitmap free, koşullu bir ring free ile eşleşiyor
AF_PACKET socket'leri kendi TPACKET mmap ring'lerini bir page-vector
(pg_vec) ile destekler. TPACKET_V3 için kernel, frame başına ownership'i
ayrıca bir bitmap (rx_owner_map) ile takip eder. Kodun korumesı gereken
invariant şudur: rx_owner_map yalnızca bir pg_vec ile birlikte allocate
edilir ve ikisi tek bir birim olarak ring'e birlikte takılıp birlikte çıkarılır.
Bug bu invariant'ı teardown path'inde kırar: rx_owner_map koşulsuz olarak free
edilirken free_pg_vec() bir if (pg_vec) ile korunuyordu. Bir kullanıcı hiç
ring allocate etmeyen bir PACKET_RX_RING isteği gönderdiğinde (tp_block_nr == 0,
yani pg_vec == NULL) — örneğin versiyonlar arasında geçiş yaparken — swap, ardından
bir sonraki işlemde tekrar free edilen stale bir rx_owner_map pointer'ı bırakır.
Sonuç, boyutu ve içeriği attacker'ın kısmen kontrol ettiği bir kernel heap
object'inin double-free'sidir (CWE-415); bu da
use-after-free tarzı bir heap-grooming
escalation'ın klasik ön koşuludur.
Walkthrough¶
Açıklı kod net/packet/af_packet.c içindeki packet_set_ring() fonksiyonunda yer
alır. Yeni ve eski ring state'i swap edildikten sonra eski kaynaklar serbest
bırakılır. Patch öncesi cleanup, bir page-vector var olup olmadığına bakmaksızın
bitmap'i free ediyordu:
/* vulnerable: rx_owner_map freed even when pg_vec == NULL */
bitmap_free(rx_owner_map);
if (pg_vec)
free_pg_vec(pg_vec, order, req->tp_block_nr);
rx_owner_map ve pg_vec birlikte swap edildiği için, NULL bir pg_vec bu path'te
bu ring ile hiçbir bitmap'in eşleştirilmediği anlamına gelir — yine de bitmap_free()
yine çalışır ve hâlâ canlı bir ring'e ait olan bir pointer'ı serbest bırakır (ya da onu
ikinci kez serbest bırakır). Upstream commit ec6af094ea28 ("net/packet: rx_owner_map
depends on pg_vec") iki free'yi birbirine bağlar; böylece bitmap yalnızca ait olduğu
ring de free edilirken free edilir:
packet_set_ring() içindeki patch'lenmiş teardown
Herhangi bir ayrıcalıksız local kullanıcı tarafından erişilebilir
Eski CAP_NET_RAW ile kapılanan AF_PACKET bug'larının aksine, bu path bir local
kullanıcının sıradan setsockopt(PACKET_RX_RING) dizileriyle erişilebilir; bu yüzden
CISA'nın Known Exploited Vulnerabilities kataloğuna eklendi. Patch'lenmemiş bir
kernel'de gözlemlenebilir davranış, bir KASAN double-free splat'ından, takip eden bir
spray'in controlled write'a dönüştürdüğü sessiz heap corruption'a kadar değişir.
Detection¶
- KASAN / SLUB_DEBUG: free stack'i
af_packet.c'yi gösteren birBUG: KASAN: double-free or invalid-free in bitmap_free(ya dapacket_set_ring) splat'ı, debug bir kernel'de en yüksek doğruluktaki sinyaldir. - Syscall telemetry (auditd/EDR):
socket(AF_PACKET, …)açan ve ardındanPACKET_VERSION'ı (TPACKET_V3'e/dan geçiş yaparak) vetp_block_nr == 0olanPACKET_RX_RING'i sıfır olmayan isteklerle iç içe geçirerek hızlıca döngüye sokansetsockoptçağrıları yapan process'leri arayın. Tek bir packet socket üzerinde tekrar eden ring-setup/teardown döngüleri normal uygulamalar için anormaldir. - Heap-spray companions: corruption genellikle komşu object spray'leriyle
weaponize edilir (bkz. sk-buff spray ve
universal heap spray); bir EDR, free'nin kendisinden çok
spray pattern'ini (toplu
sendmsg/msgsnd/keyring allocation'ları) daha kolay gözlemleyebilir. - Crash signature: production kernel'lerde tetiklenen bir double-free çoğu zaman
SLUB allocator içinde bir
general protection faultya da list-corruption oops'u olarak yüzeye çıkar.
Mitigation¶
- Upstream fix: commit
ec6af094ea28f0f2dda1a6a33b14cd57e36a9755— stable tree'ler genelinde backport edildi. Distro'nuzun patch'lenmiş kernel'ini uygulayın. - Attack-surface reduction: packet socket oluşturmayı kısıtlayın. Bir workload raw
packet erişimine ihtiyaç duymuyorsa,
socket()syscall'unu seccomp ile filtreleyerek (domain == AF_PACKET'i bloklayarak), bir LSM ile ya da systemd'ninRestrictAddressFamilies=direktifiyleAF_PACKET'i reddedin. - Defense-in-depth: freelist corruption ve double-free exploitation'ını
zorlaştırmak için
CONFIG_SLAB_FREELIST_HARDENEDveCONFIG_INIT_ON_FREE_DEFAULT_ON'ı etkinleştirin; aynı duruşun parçası olarakkernel.unprivileged_bpf_disabled/ genel LPE hardening'i de uygulayın.