StackRot expand_downwards UAF (CVE-2023-3269)¶
Stack expansion, yalnızca mmap read lock altında bir maple-tree node'unu değiştirir ve RCU reader'larına free edilmiş bir VMA node'una dangling reference bırakır — Linux 6.1–6.4'te local privilege escalation için kullanılabilen bir use-after-free-by-RCU.
Mechanism¶
Note
Linux 6.1'de per-process VMA index'i red-black tree'den maple tree'ye
taşındı. Maple tree, RCU-safe bir B-tree'dir: writer'ların mmap write lock'unu
tutması beklenir, lockless reader'lar ise onu RCU altında yürüyebilir. Kırılan
StackRot invariant'ı şudur: node-replace eden bir write, write lock ile
reader'lara karşı serialize edilmelidir. Stack growth
(expand_downwards() / expand_stack()), caller yalnızca read lock'unu
tutarken bir VMA'nın start address'ini değiştirdi — ve iki VMA arasındaki
gap'i çökertip maple tree'yi bir node'u (yerinde update değil) replace etmeye
zorlayabildi. Eski node ma_free_rcu()'ya verilir ve bir grace period sonrası
free edilir, ama read lock altında (herhangi bir RCU critical section dışında) o
node'a bir pointer elde etmiş eşzamanlı bir reader, free edildikten sonra onu
dereference edebilir: bir use-after-free-by-RCU (UAFBR).
Aşılan sınır, unprivileged bir process tarafından erişilebilen kernel heap state'inin memory safety'sidir: neredeyse her kernel config büyüyebilir bir stack ile build edilir, dolayısıyla bug minimal capability'lerle geniş ölçüde erişilebilir.
Walkthrough¶
High-level, public StackRot advisory'sinden ve upstream fix'inden çıkarılmıştır:
- Büyüyebilir (tipik olarak
MAP_GROWSDOWN/ana) bir stack VMA'sı, aralarında bir gap olan başka bir VMA'nın bitişiğinde durur. - Bir thread stack'in altında fault verir ve
expand_downwards()'i sürükler. Yeni alt sınır VMA'lar arası gap'i sildiğinde, write path'i (mas_wr_modify → mas_wr_node_store → mas_replace) taze bir node allocate eder ve eski node'uma_free_rcu()için kuyruğa alır. - İkinci bir thread eşzamanlı olarak VMA tree'sini yürür (örn.
find_vma_prev()→mas_walk()çağıran bir path üzerinden), yalnızca read lock'unu tutarak, birazdan free edilecek node'a bir pointer cache'ler. - RCU grace period eski node'u free ettikten sonra, 3. adımdaki stale pointer bir dangling reference olur. O slab object'i attacker-controlled veriyle reclaim etmek, UAFBR'yi corrupt bir VMA / kernel object'ine çevirir.
Warning
Orijinal disclosure, weaponize edilmiş bir exploit'i kasıtlı olarak vermedi. UAFBR bug'ları daha önce pratik değil sanılıyordu; StackRot, bunların exploit edilebilir olduğunun ilk public gösterimi olarak dikkat çekicidir, ama dangling node'dan kullanılabilir bir read/write primitive'ine giden zincir kolay değildir ve burada yeniden verilmiyor.
Detection¶
- Kernel log'ları / crash telemetry'si: maple-tree fonksiyonlarına (
mas_*,mt_*) ya da VMA walk path'lerine atıf yapan KASAN "use-after-free" report'ları; meşgul multithreaded bir process'teexpand_downwards/find_vma_prevsırasında oops'lar. - Bir sibling thread'i sıkı bir race loop'unda
/proc/self/maps-tarzı VMA walk'ları iterate ederken agresif biçimde stack belleği fault'layan anormal local process'ler — bir heap-grooming + race pattern'i. - EDR: unprivileged bir process'in kernel'i crash'lemesinin (panic/soft-lockup) ardından bir child process'in privilege değişimi gelmesi, güçlü bir post-exploitation sinyalidir.
- Temmuz 2023 stable fix'i olmadan etkilenen pencerede (6.1–6.4) çalışmak, filo taraması için tek başına bir maruziyet göstergesidir.
Mitigation¶
- Patch: 6.5'te fix'lendi ve stable 6.1.37, 6.3.11, 6.4.1'e backport edildi (Temmuz 2023 başı). Fix, stack expansion'ı write lock'u alacak / growth path'inde lockless node replacement'tan kaçınacak şekilde yeniden düzenler. Kernel'i güncelle.
- Patch'leme geciktiğinde local attack surface'i azalt: untrusted local code execution'ı kısıtla ve containerize et.
- Defense-in-depth allocator hardening (
SLAB_FREELIST_RANDOM,init_on_free, test filolarında KASAN), genel olarak UAF-sınıfı bug'lar için exploitation maliyetini artırır; bkz. slab-freelist-randomization.