Skip to content

XFRM xfrmi_changelink UAF (CVE-2025-38500)

xfrmi_changelink(), bir collect_md xfrm interface üzerindeki değişiklikleri reddetmiyordu; bu da o özel device'ın, hâlâ per-netns collect_md pointer'ı tarafından sahiplenilirken normal xfrmi hash'ine eklenmesine yol açıyordu — network-namespace teardown sırasında bir double free (use-after-free).

CVE identifier note

Burada anlatılan xfrmi_changelink / collect_md use-after-free, NVD'de CVE-2025-38500 olarak takip ediliyor ve mainline commit a90b2a1aaacbcf0f91d7e4868ad6c51c5dee814b ile düzeltilmiş. CVE-2025-39965 alias'ı ise bazı tracker'larda komşu bir xfrm fix için kullanılıyor; asıl referans olarak bug'ı (collect_md üzerinde xfrmi_changelink) kabul et ve numaraya güvenmeden önce kesin CVE-to-commit eşleşmesini kendi dağıtımının advisory'sine karşı doğrula.

Mechanism

Invariant: a collect_md xfrm interface is owned by exactly one pointer

collect_md property'siyle oluşturulan bir xfrm interface, her network namespace için bir singleton'dır. Yalnızca xfrmi_net->collect_md_xfrmi üzerinden erişilebilir ve normal xfrmi_net->xfrmi hash'inin dışında bilinçli olarak tutulur. collect_md property'si sadece device creation sırasında ayarlanabilir; dolayısıyla xfrmi_changelink() (link-change path'i) böyle bir interface'i değiştirmeye yönelik her girişimi reddetmek zorundadır.

Bug şu: bunu zorlayan guard yalnızca interface'in xfrmi_locate() ile bulunduğu branch'te çalışıyordu — ve xfrmi_locate() bilinçli olarak collect_md interface'ini döndürmüyor. Yani changelink, collect_md device'ı üzerinde çağrıldığında check atlanıyordu. Kod da singleton'ı, hâlâ collect_md_xfrmi tarafından referans edilmesine ek olarak xfrmi_net->xfrmi hash'ine yerleştiriyordu. Artık iki owner tek bir struct xfrm_if'e işaret ediyor.

Network namespace teardown edildiğinde her iki owner da aynı object'i free eder: hash walk onu free eder, ardından collect_md teardown onu tekrar free eder — bir double free, device unregistration sırasında UAF / kernel panic olarak gözlenir. Genel şekli için refcount-imbalance-uaf'ye bak.

Fix, collect_md check'ini daha erkene taşır ve netdev_priv()'den zaten elde edilebilen xi'yi kullanır; böylece hedef bir collect_md interface olduğunda xfrmi_changelink(), herhangi bir list insertion'dan önce başarısız olur. Etkilenen dosya net/xfrm/xfrm_interface_core.c.

Walkthrough

Bu, bir network namespace üzerinde CAP_NET_ADMIN'e sahip bir context tarafından tetiklenebilir (örneğin netns'in sahibi olan unprivileged bir user namespace içindeki root). Yalnızca yetkili bir lab ortamında çalıştır.

  1. Taze bir network namespace içinde bir collect_md xfrm interface oluştur:
# ip netns add lab
# ip netns exec lab ip link add xfrm-md type xfrm if_id 1 collect_md
# ip netns exec lab ip -d link show xfrm-md
xfrm-md@NONE: <NOARP> ... xfrm if_id 0x1 collect_md ...
  1. Vulnerable bir kernel'de link'i "change" et. Guard atlandığı için bu, -EINVAL döndürmek yerine başarılı olur ve singleton'ı double-list eder:
# ip netns exec lab ip link set xfrm-md type xfrm if_id 2

Patched bir kernel'de aynı komut temiz şekilde başarısız olur:

RTNETLINK answers: Invalid argument
  1. Double free'yi patlatmak için namespace'i free et. Netns'i silmek, artık çift sahipli olan interface'i iki kez free eden teardown path'ini çalıştırır:
# ip netns del lab

KASAN'lı bir kernel, unregistration sırasında double free / UAF'i raporlar:

BUG: KASAN: slab-use-after-free in xfrmi_dev_uninit / netdev teardown
Call Trace:
 ...
 xfrmi_exit_batch_rtnl
 cleanup_net
Turning the double free into a primitive

Sabit boyutlu bir struct xfrm_if object'inin double free'si, alışılmış heap teknikleriyle escalate edilebilir: free edilmiş iki slot'tan birini kontrollü bir object ile reclaim et (slab-grooming, kmalloc-cache-feng-shui), ya da bir cross-cache page-level primitive'e dönüştür (cross-cache-attack). Kontrol path'i, root için alışıldık commit-creds ile sonlanır.

Detection

  • KASAN/CONFIG_SLUB_DEBUG, netns teardown sırasında slab-use-after-free'yi işaretler.
  • Davranışsal olarak: bir user+net namespace oluşturan, bir collect_md xfrm interface ekleyen, onun üzerinde bir RTM_NEWLINK change yapan ve ardından namespace'i silen unprivileged bir process, tam olarak bu trigger dizisidir.

Mitigation

  • Fix'i (a90b2a1aaacbcf0f91d7e4868ad6c51c5dee814b) ve onun stable backport'larını uygula; bu değişiklik xfrmi_changelink()'in collect_md interface'lerini reddetmesini sağlar.
  • Unprivileged user namespace'lerin gerekmediği yerlerde onları kısıtla (bunları sunan dağıtımlarda kernel.unprivileged_userns_clone=0); böylece CAP_NET_ADMIN-in-namespace path'i ortadan kalkar.
  • Genel slab hardening (CONFIG_SLAB_FREELIST_HARDENED, init_on_free=1), free edilmiş object'i weaponize etmenin maliyetini artırır.

References