CAN BCM UAF (CVE-2023-52922)¶
CAN Broadcast Manager'daki bir teardown-ordering bug'ı, per-op objelerini procfs file'larını unregister etmeden önce free ediyor; bu da bir use-after-free read üzerinden kernel memory'sini sızdırıyor.
Mechanism¶
net/can/bcm.c içinde, CAN Broadcast Manager her operation için tutulan struct bcm_op objelerini BCM socket struct bcm_sock üzerindeki iki linked list'te (bo->tx_ops ve bo->rx_ops) saklıyor; ayrıca /proc/net/can-bcm/ altında bir procfs entry'si (bo->procname) tutuyor.
Note
Bug aslında bcm_release() içindeki bir lifetime/ordering hatası: socket close sırasında önce op list'leri teardown ediyor — her bcm_op'u bcm_remove_op() (kfree(op)) ile free ederek — ve remove_proc_entry()'yi ancak bundan sonra çağırıyor. Bu window boyunca proc file hâlâ register edilmiş durumda, dolayısıyla eşzamanlı (concurrent) bir reader bcm_proc_show()'u tetikliyor; bu fonksiyon op list'leri list_for_each_entry() ile dolaşıp free edilmiş bcm_op memory'sini dereference ediyor. KASAN bunu bir slab-use-after-free read olarak raporluyor.
Fix (commit 55c3b96074f3, "can: bcm: Fix UAF in bcm_proc_show()", Temmuz 2023) bcm_release()'i yeniden sıralayarak remove_proc_entry()'yi op'lar free edilmeden önce çağırıyor.
Walkthrough¶
socket(PF_CAN, SOCK_DGRAM, CAN_BCM)aç, ardından bir CAN interface'ine (örn. birvcan/vxcandevice'ı)connect()yap — connect, socket başına procfs file'ını register ediyor.- Op list'leri doldur:
bcm_sendmsg()üzerinden, opcode'uTX_SETUP(txbcm_op) ya daRX_SETUP(rxbcm_op) olan birstruct bcm_msg_head'isendmsg()ile gönder. - İki thread'i race ettir:
- Thread A sürekli olarak
/proc/net/can-bcm/<entry>'yiread()ediyor →bcm_proc_show()op list'leri dolaşıyor. - Thread B socket'i
close()ediyor →bcm_release(), proc entry'sini unregister etmeden öncebcm_opobjelerini free ediyor.
Bu window içinde A, free edilmiş bcm_op memory'sini dereference ediyor → UAF read.
Race-window timeline (kavramsal — sıralama bug'ını gösterir, boyut/adres yok):
Thread B: bcm_release() Thread A: bcm_proc_show()
--------------------------- --------------------------------
bcm_remove_op() → kfree(op) ─┐
│ list_for_each_entry(op, ...)
<< op artık freed >> ├─► deref op->... ◄── UAF read
│ (freed bcm_op)
remove_proc_entry() ........┘ (proc entry hâlâ register'lı)
Fix: remove_proc_entry() önce çağrılır →
reader, op'lar free edilmeden çıkarılmış olur (window kapanır).
Exploitation primitive
Information disclosure. bcm_proc_show() free edilmiş bcm_op struct'ının field'larını print ediyor; pratik etki (örn. kernel-pointer / KASLR recovery) struct layout'una ve runtime koşullarına bağlıdır ve daha fazla araştırma gerektirir. Unprivileged erişim, user namespace'lere artı virtual CAN'e (CONFIG_CAN_VXCAN) dayanıyor.
Detection¶
KASAN ile bulundu (bcm_proc_show() içinde slab-UAF read). Runtime'da, unprivileged PF_CAN/CAN_BCM kullanımının, socket close ile race eden hızlı /proc/net/can-bcm/ read'leriyle birleşmesi anormaldir.
Mitigation¶
Düzeltilmiş stable sürümlere patch'le (4.14.322, 4.19.291, 5.4.251, 5.10.188, 5.15.123, 6.1.42, 6.4.7+). Kullanılmıyorsa CONFIG_CAN_BCM'i devre dışı bırak ve unprivileged user namespace'leri / vxcan oluşturmayı kısıtla.