Skip to content

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_device pointer'ı (CVE-2024-26808) ve GC sequence critical section'ı içinde serbest bırakılan bir commit_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):

  1. Bir device'a bağlı ingress hook tipinde bir netdev-family base chain oluştur (NFT_MSG_NEWCHAIN, NFTA_HOOK_DEV), bir inet/ingress basechain üzerinde.
  2. Altındaki device'ı sil/unregister et (rtnl_dellink). INET-ingress hook'u temizlenmez, bu yüzden ops.dev dangle eder.
  3. Free edilen net_device slab'ını kontrollü bir object ile reclaim et (heap spray).
  4. 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.
  5. 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):

  1. Async GC'ye uygun element'lere (timeout'lar) sahip bir set inşa et ki nft_rhash_gc() / nft_trans_gc_* aktif olsun.
  2. Abort path'i NFNL_ABORT_AUTOLOAD alan bir transaction batch gönder; bu da nf_tables_module_autoload()'un gc_seq penceresi içinde commit_mutex'i serbest bırakmasına neden olur.
  3. Async GC worker ile yarış ki artık geçersiz kılınmış gc_seq epoch'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
Data-only finisher için bkz. core_pattern overwrite privesc ve page UAF; tam offset'ler build'e özgüdür.

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'leri nft_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()'u gc_seq critical section'ının dışına taşır — nft_gc_seq_end()'den sonra — böylece commit_mutex asla 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).

References