Skip to content

multiq qdisc preempt-disabled OOB write (CVE-2024-36978)

tc/qdisc konfigürasyon path'inden ulaşılabilen multiq qdisc'inde (net/sched/sch_multiq.c) bir out-of-bounds write; burada multiq_tune() bir allocation'ı stale q->bands değerine göre boyutlandırır.

Mechanism

Invariant: allocation boyutu eski değil, yeni band sayısını takip etmelidir

multiq (multiqueue) packet scheduler'ı per-band bir array tutar. Bir qdisc multiq_tune() üzerinden yeniden tune edildiğinde, yeni band sayısı qopt->bands'te gelir ve kodun per-band slot'lara yazmadan önce o yeni sayı için storage allocate etmesi beklenir. Bug (CVE-2024-36978) bir ordering/boyut uyuşmazlığıdır: q->bands, sonraki loop mantığını sürmek için qopt->bands'ten atanır, ama per-band bölgeyi boyutlandıran kmalloc() eski q->bands'ten hesaplanır. Upstream fix'in belirttiği gibi, "the old q->bands should not be used in kmalloc. Otherwise, an out-of-bounds write will occur."

Yeni band sayısı eskisini aştığında, sonraki kod under-sized allocation'ın sonunun ötesini index'ler — kapsamı iki band sayısı arasındaki farkla kontrol edilen bir kernel-heap OOB write. Bir multiq qdisc'i yapılandırmak CAP_NET_ADMIN gerektirir; varsayılan distro config'lerinde unprivileged bir kullanıcı bunu taze bir user+network namespace içinde elde edebilir; bug'ı privilege escalation için yerel olarak exploit edilebilir kılan da budur.

"preempt-disabled" çerçevesi, qdisc/scheduler OOB primitive'leri için daha geniş exploitation stratejisini yansıtır: komşu slab object'lere düşen heap write'lar, corrupt edilen object'in deterministik biçimde reclaim edilip kullanılabilmesi için cross-CPU / preempt-disabled allocation teknikleriyle groom edilir — ilgili cross-CPU race writeup'larına bak.

Walkthrough

Yalnızca yetkili test

Yalnızca yamalanmamış bir kernel (pre-6.10-rc3 / distro backport'larından önce) çalıştıran tek kullanımlık bir VM'de reprodüksiyon yap. Config path'i CAP_NET_ADMIN ile ulaşılabilir.

OOB tamamen qdisc konfigürasyon interface'inden sürülür; kavramsal olarak trigger, bir multiq qdisc'ini oluşturulduğundan daha büyük bir band sayısına yeniden tune eder:

# inside an unprivileged user+net namespace that grants CAP_NET_ADMIN
unshare -Urn
# create a multiq qdisc with a small band count, then re-tune larger
tc qdisc add dev lo root handle 1: multiq
tc qdisc change dev lo root handle 1: multiq   # re-tune drives multiq_tune()
/* the buggy shape (paraphrased from the fix): size from the NEW band count */
/* BAD:  q->bands = qopt->bands; ... kmalloc(sizeof(*q->...) * q->bands_old) */
/* FIX:  allocate against qopt->bands BEFORE assigning q->bands              */
Debug kernel'de beklenen sinyal

# with KASAN enabled, the re-tune trips a slab-out-of-bounds report:
BUG: KASAN: slab-out-of-bounds in multiq_tune+0x... [net/sched/sch_multiq]
Write of size N at addr ffff8881... by task tc/...
...
Allocated by task tc: __kmalloc ... multiq_tune
Kesin offset'ler kernel build'ine bağlıdır; report, kmalloc boyutundaki bir per-band bölgesinin ötesine yazan multiq_tune()'u işaret eder.

Detection

  • multiq_tune() kaynaklı KASAN slab-out-of-bounds report'ları.
  • multiq scheduler'ını yapılandıran unprivileged ya da namespace'lenmiş process'lerden gelen beklenmedik tc qdisc/RTM_NEWQDISC netlink aktivitesi.

Mitigation

  • Patch: upstream fix commit affc18fdc694190ca7575b9a86632a73b9fe043d (6.10-rc3'te merge edildi) allocation'ı yeni band sayısına göre boyutlandırır; distro backport'ları takip etti (örn. Debian bookworm 6.1.99-1).
  • Kullanılmıyorsa sch_multiq'i blacklist'le: /etc/modprobe.d/'ye ekle.
  • CAP_NET_ADMIN dayanağını kaldırmak için unprivileged namespace'leri kısıtla: sysctl user.max_user_namespaces=0.

Bu OOB'yi kullanılabilir bir primitive'e çevirmenin heap-grooming tarafı, perf events race-condition LPE ve cross-cache attack reclaim teknikleriyle örtüşür.

References