AF_PACKET TPACKET_V2/V3 LPE (CVE-2020-14386)¶
tpacket_rcv()içindeki birnetoffinteger overflow'u, özel hazırlanmış bir packet ring'in virtio-net header'ını ring frame'in ötesine yazmasına izin vererek kernel heap belleğini bozar ve local root sağlar.
Mechanism¶
Root cause: 32-bit reserve'i tutamayan 16-bit'lik bir offset
Bir AF_PACKET socket'inin TPACKET ring'i olduğunda, receive yolu
tpacket_rcv() MAC header ve network verisinin frame içinde nerede
başladığını hesaplar. macoff/netoff, kopyalanan paketin ring frame
içinde başladığı byte offset'leridir ve po->tp_reserve'i içerirler — bu,
setsockopt(PACKET_RESERVE) ile ayarlanan, kullanıcı tarafından verilen bir
headroom'dur. tp_reserve bir unsigned int'tir, ama netoff unsigned
short olarak tanımlanmıştı.
Eksik olan invariant şudur: "netoff hem frame içinde hem de 16 bit içinde
kalmalı." Büyük bir tp_reserve, hesaplanan netoff'un USHRT_MAX'i
aşmasına yol açar; bunu 16-bit'lik alanda saklamak değeri truncate eder
(wrap-around). Truncate edilmiş küçük netoff aşağı akıştaki boyut
mantığından geçer, ama (saldırgan etkisindeki) virtio-net header'ının ve
paket byte'larının asıl kopyası artık güvenli bir frame-içi konuma karşılık
gelmeyen değerlerle yerleştirilir — kernel heap'e bir out-of-bounds write
(CWE-787) ve bu da local privilege escalation sağlar.
Walkthrough¶
Kusur net/packet/af_packet.c içindeki tpacket_rcv()'dedir. netoff,
unsigned short tanımını macoff/hdrlen ile paylaşıyordu, dolayısıyla 32-bit
reserve onu overflow edebiliyordu. Upstream commit acf69c946233 ("net/packet:
fix overflow in tpacket_rcv") netoff'u unsigned int'e genişletir ve header
yazılmadan önce açık bir bound check ekler:
- unsigned short macoff, netoff, hdrlen;
+ unsigned short macoff, hdrlen;
+ unsigned int netoff;
...
+ if (netoff > USHRT_MAX) {
+ atomic_inc(&po->tp_drops);
+ goto drop_n_restore;
+ }
Neden sınır USHRT_MAX
netoff 32 bit'e genişletilse bile, frame'e göreli offset sonuçta 16-bit
boyutunda bir değerin beklendiği yerde tüketilir (tp_net/tp_mac frame
descriptor alanları ve virtio_net_hdr_from_skb() kopya hedefi). netoff
USHRT_MAX'i aşabildiği andan itibaren tek güvenli seçenek paketi drop
etmek, tp_drops'u artırmak ve restore etmektir — ki patch'in yaptığı tam
olarak budur. Orijinal kodun virtio_net_hdr_from_skb() üzerinden yapacağı
write, savunmasız bir kernel'de out of bounds'a düşen şeydir.
Tetikleme remote etkisinde ama lokal olarak sürülür
Overflow lokal olarak kurulur (PACKET_RESERVE + ring yapılandırması), ama
taşan write alınan paketlerle sürülür, dolayısıyla corruption trafik
socket'e ulaştığında patlar. Kusur 4.6'dan 5.8'e kadar olan kernel'leri
etkiler (5.9-rc4'te düzeltildi).
Detection¶
- KASAN: write erişimiyle gelen bir
BUG: KASAN: slab-out-of-bounds in tpacket_rcv(veyatpacket_rcv'den ulaşılanvirtio_net_hdr_from_skbiçinde) kesin debug-kernel imzasıdır. - Syscall telemetry:
socket(AF_PACKET, …)ile oluşturulan,setsockoptile alışılmadık derecede büyük birPACKET_RESERVEdeğeri ayarlayan ve ardındanPACKET_RX_RINGkurulumu gelen socket'leri işaretleyin. Meşru kullanıcılartp_reserve'i küçük tutar;0xFFFF'e yakın veya üzerindeki değerler güçlü bir overflow girişimi göstergesidir. - EDR/audit: root olmayan, network daemon'ı olmayan bir süreç tarafından
AF_PACKETsocket oluşturulmasını sonradan gelen privilege kazanımıyla (örn. aniden uid 0 olarak çalışan bir child process) ilişkilendirin — packet-socket aktivitesini takip eden commit_creds tarzı escalation deseni. - Crash signature: production kernel'lerde OOB write çoğunlukla ring trafiği başladıktan kısa süre sonra SLUB list corruption ya da bir GPF olarak ortaya çıkar.
Mitigation¶
- Upstream fix: commit
acf69c946233259ab4d64f8869d4037a198c7f06(5.9-rc4'te ve tüm stable backport'larda). Kernel'i patch'leyin. - Capability/namespace hardening: bir
AF_PACKETsocket oluşturmakCAP_NET_RAWgerektirir. Gerçek dünyadaki risk, unprivileged user namespace'lerin bu capability'yi bir userns içinde vermesidir — gerekmeyen yerlerde bunlarısysctl kernel.unprivileged_userns_clone=0(Debian/Ubuntu) ya dauser.max_user_namespaces=0ile devre dışı bırakın. - Attack-surface reduction: raw socket'e ihtiyaç duymayan servisler için
AF_PACKET'i seccomp veya systemdRestrictAddressFamilies=ile bloklayın. - Defense-in-depth:
CONFIG_SLAB_FREELIST_HARDENEDve yapısal layout/redzone hardening, heap overwrite'ın güvenilirliğini azaltır.