Skip to content

AF_PACKET TPACKET_V2/V3 LPE (CVE-2020-14386)

tpacket_rcv() içindeki bir netoff integer 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 (veya tpacket_rcv'den ulaşılan virtio_net_hdr_from_skb içinde) kesin debug-kernel imzasıdır.
  • Syscall telemetry: socket(AF_PACKET, …) ile oluşturulan, setsockopt ile alışılmadık derecede büyük bir PACKET_RESERVE değeri ayarlayan ve ardından PACKET_RX_RING kurulumu gelen socket'leri işaretleyin. Meşru kullanıcılar tp_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_PACKET socket 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_PACKET socket oluşturmak CAP_NET_RAW gerektirir. 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 da user.max_user_namespaces=0 ile devre dışı bırakın.
  • Attack-surface reduction: raw socket'e ihtiyaç duymayan servisler için AF_PACKET'i seccomp veya systemd RestrictAddressFamilies= ile bloklayın.
  • Defense-in-depth: CONFIG_SLAB_FREELIST_HARDENED ve yapısal layout/redzone hardening, heap overwrite'ın güvenilirliğini azaltır.

References