multiq qdisc preempt-disabled OOB write (CVE-2024-36978)¶
tc/qdisc konfigürasyon path'inden ulaşılabilen
multiqqdisc'inde (net/sched/sch_multiq.c) bir out-of-bounds write; buradamultiq_tune()bir allocation'ı staleq->bandsdeğ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
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ı.multiqscheduler'ını yapılandıran unprivileged ya da namespace'lenmiş process'lerden gelen beklenmediktc qdisc/RTM_NEWQDISCnetlink 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_ADMINdayanağı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.