nf_tables UAF and double-free leading to LPE (CVE-2024-26808/26925)¶
2024'ten iki netfilter use-after-free bug'ı: bir inet/ingress basechain hook'unda bırakılan eski bir
net_devicepointer'ı (CVE-2024-26808) ve GC sequence critical section'ı içinde serbest bırakılan bircommit_mutex(async GC worker'ın set element'lerini double-free etmesine neden olur, CVE-2024-26925) — ikisi de CAP_NET_ADMIN ile erişilebilir ve root'a exploit edilebilir.
Mechanism¶
Two lifetime invariants, two breaks
İki bug da nf_tables'ta object-lifetime başarısızlıklarıdır, ama farklı subsystem'lerde.
CVE-2024-26808 — stale device hook. netdev'e bağlı bir base chain, hook'unun içinde bir struct net_device'a raw pointer saklar (nft_netdev_hook_alloc() ops.dev'i tutar). İki ingress hook type'ı vardır: NF_NETDEV_INGRESS (klasik netdev ingress) ve NF_INET_INGRESS. Bir device unregister edildiğinde, nf_tables_netdev_event() ona referans veren her hook'u sökmesi gerekir. NF_NETDEV_INGRESS chain'lerini ele aldı ama NF_INET_INGRESS chain'lerini değil, bu yüzden bir inet/ingress basechain, device free edildikten sonra bir dangling net_device * tuttu (free edilen net_device kmalloc-cg-4k'da yaşar). "Bir hook, işaret ettiği device'tan asla daha uzun yaşamaz" invariant'ı ihlal edilir.
CVE-2024-26925 — GC sequence under a dropped lock. Asenkron set garbage collection lockless'tır: başlangıçta nft_net->gc_seq'i örnekler (nft_gc_seq_begin) ve sonunda yeniden doğrular (nft_gc_seq_end / nft_trans_gc_work_done) ki eşzamanlı bir transaction'ı tespit etsin. Bu yalnızca commit_mutex tüm gc_seq_begin..gc_seq_end penceresi boyunca tutulursa çalışır. Autoload path'inde nf_tables_abort(), nf_tables_module_autoload()'u çağırdı; bu da userspace'ten modül yüklemek için pencere ortasında commit_mutex'i serbest bıraktı. Başka bir CPU'daki bir GC worker o zaman aynı gc_seq epoch'u içinde zaten ele alınmış element'leri toplayıp staleness kontrolünden geçebilirdi — bir double free.
Walkthrough¶
İkisi de tamamen netlink (NFNL_SUBSYS_NFTABLES) üzerinden CAP_NET_ADMIN ile sürülür, unshare -Urn aracılığıyla unprivileged bir kullanıcıdan erişilebilir.
CVE-2024-26808 (free edilen bir net_device'ın use-after-free'i):
- Bir device'a bağlı
ingresshook tipinde bir netdev-family base chain oluştur (NFT_MSG_NEWCHAIN,NFTA_HOOK_DEV), bir inet/ingress basechain üzerinde. - Altındaki device'ı sil/unregister et (
rtnl_dellink). INET-ingress hook'u temizlenmez, bu yüzdenops.devdangle eder. - Free edilen
net_deviceslab'ını kontrollü bir object ile reclaim et (heap spray). - Leak: chain'i dump et —
nft_dump_basechain_hook()nla_put_string(skb, NFTA_DEVICE_NAME, hook->ops.dev->name)yapar ve reclaim edilen belleği userspace'e geri okur. - Free primitive:
__nf_unregister_net_hook()daha sonra eski pointer üzerinde işlem yapar ve attacker-etkili belleğin bir free'sini mümkün kılar.
CVE-2024-26925 (GC race aracılığıyla double free):
- Async GC'ye uygun element'lere (timeout'lar) sahip bir set inşa et ki
nft_rhash_gc()/nft_trans_gc_*aktif olsun. - Abort path'i
NFNL_ABORT_AUTOLOADalan bir transaction batch gönder; bu danf_tables_module_autoload()'ungc_seqpenceresi içindecommit_mutex'i serbest bırakmasına neden olur. - Async GC worker ile yarış ki artık geçersiz kılınmış
gc_seqepoch'u içinde element'leri toplasın → aynı element iki kez free edilir.
From UAF to root via core_pattern (CVE-2024-26808 PoC shape)
Google kernelCTF write-up'ı bug'ı data-only bir privilege escalation'a zincirler:
UAF leak -> recover kernel addresses
reclaim freed page as pipe_buffer objects
vmsplice() to map kernel pages into the pipe
overwrite core_pattern with "|/path/to/payload"
trigger a crash -> payload runs as root
Different root causes, same family
Bu iki CVE burada bir araya getiriliyor çünkü ikisi de 2024 nf_tables UAF→LPE bug'ı, ama bağımsız fix'leri ve farklı primitive'leri var (dangling device hook vs. GC double free). Birini yamalamanın diğerini ele aldığını varsaymayın.
Detection¶
nf_hook_entry_head/nft_dump_basechain_hook(26808) veya async GC path'lerinft_rhash_gc/nft_trans_gc_work_done(26925) içinde KASAN use-after-free raporları.- Unprivileged userns oluşturmayı izleyip ardından netdev basechain churn'ü veya hızlı transaction abort/autoload batch'leri.
Mitigation¶
- CVE-2024-26808: fix,
NETDEV_UNREGISTER'da inet/ingress basechain'lerinden netdevice'leri kaldırır ve eski hook reference'ını temizler (6.x serisinin stable update'lerinde düzeltildi). - CVE-2024-26925: fix,
nf_tables_module_autoload()'ugc_seqcritical section'ının dışına taşır —nft_gc_seq_end()'den sonra — böylececommit_mutexasla pencere ortasında serbest bırakılmaz (regression ~v6.5'te tanıtıldı, v6.9-rc3'te düzeltildi). CAP_NET_ADMIN'i kesmek için unprivileged user namespace'leri kısıtlayın (örn.kernel.unprivileged_userns_clone=0); nf_tables'i trusted context'lere kısıtlayın. Distro backport'ları mevcuttur (örn. CVE-2024-26808 için RHSA-2024:5256/5257).