AF_VSOCK transport-reassignment UAF LPE (CVE-2024-50264)¶
AF_VSOCK'ta
connect()ile bir POSIX signal arasındaki bir race, dangling birvsk->transpointer'ı bırakır ve bir kworker'ın hâlâ yazdığı birvirtio_vsock_sockobject'ini free eder — local privilege escalation için exploit edilebilir bir use-after-free.
Mechanism¶
Invariant: bir worker hâlâ reference ederken bir transport yeniden atanmamalıdır
AF_VSOCK socket'leri, connection'ın send/receive defter tutmasını destekleyen
bir transport object'i tutar (vsk->trans, burada bir virtio_vsock_sock).
Invariant şu: virtio TX/RX kworker'ı dahil herhangi bir kernel context'i ona
hâlâ ulaşabildiği sürece bu object hayatta kalmalıdır.
CVE-2024-50264 bu invariant'i connect() syscall'ı ile bir POSIX signal
arasındaki bir race üzerinden kırar. Bir signal blocking bir connect()'i
kesintiye uğratırsa, socket TCP_CLOSING'e geçebilir; ardından farklı
parametrelerle ikinci bir connect(), vsock_assign_transport()'u sürer ve
bu da bir worker hâlâ reference tutarken mevcut virtio_vsock_sock'u free
eder. Freed object 80 byte'tır ve kmalloc-96'ya düşer. Bug 2016'da
06a8fc78367d commit'iyle (v4.8) tanıtıldı ve stale pointer'ın yeniden
kullanılamaması için vsk->trans'ı NULL'a initialize ederek düzeltildi.
UAF write, bir kworker'da çalışan virtio_transport_space_update() freed
object'e 4-byte field'lar (peer_buf_alloc, peer_fwd_cnt) yazdığında
gerçekleşir. Pratik bir kısıt: object'in tx_lock field'ı sıfırdan farklıysa
worker spin_lock_bh()'te spin'ler, dolayısıyla reclaim eden spray bir hang'i
önlemek için o field'ı sıfır tutmalıdır. ("perf/vsock" alias'ı, bu UAF'in çoğu
zaman perf-event race UAF'leriyle birlikte kataloglanmasını yansıtır; gerçek
subsystem virtio vsock'tur.)
Walkthrough¶
Yalnızca yetkili test
Yalnızca vmw_vsock_virtio_transport yüklü tek kullanımlık bir VM'de
reprodüksiyon yap. Bug, namespace yetkisi olmayan unprivileged bir kullanıcı
tarafından ulaşılabilir.
Yayımlanan analiz (Alexander Popov, PT SWARM) signal-driven bir race'i bir heap-spray reclaim ile zincirler:
/* 1. interrupt a blocking connect() with a timer-fired signal so the socket
* drops into TCP_CLOSING without creating the paired object */
/* signal 33 (NPTL-reserved) is used to interrupt connect() cleanly */
/* 2. second connect() with a different svm_cid -> vsock_assign_transport()
* frees the virtio_vsock_sock (kmalloc-96) while a kworker still refs it */
struct sockaddr_vm addr2 = { .svm_family = AF_VSOCK, .svm_cid = OTHER_CID };
connect(s, (struct sockaddr *)&addr2, sizeof(addr2)); /* UAF window opens */
# reclaim the freed kmalloc-96 chunk with a controlled object (msg_msg),
# keeping the byte at the tx_lock offset zero so the kworker does not hang;
# the kworker's 4-byte writes (peer_buf_alloc/peer_fwd_cnt) then corrupt the
# reclaimer for a write primitive.
Debug kernel'de beklenen sinyal
BUG: KASAN: slab-use-after-free in virtio_transport_space_update+0x...
Write of size 4 at addr ffff8881........ by task kworker/...
Freed by task <pid>: kfree ... virtio_transport_destruct ... vsock_assign_transport
CONFIG_RANDOM_KMALLOC_CACHES ve CONFIG_SLAB_BUCKETS'i,
tipik olarak bir page-level cross-cache attack ile yenmek zorundadır.
Detection¶
vsock_assign_transport()/virtio_transport_destruct()üzerinden free edilen, birkworkertarafından yazılanvirtio_transport_space_update()içinde KASAN slab-use-after-free.- Self-directed signal'lerle iç içe geçmiş olağandışı AF_VSOCK
connect()fırtınaları.
Mitigation¶
- Patch: upstream fix, transport assignment path'inde
vsk->trans = NULLinitialize eder ve dangling-pointer reuse'unu kapatır. Distro backport'larını uygula. - Kullanılmadığı yerlerde (container'lar/hypervisor guest'leri) vsock'u kısıtla:
vsock/vmw_vsock_virtio_transport'u blacklist'le. - Slab hardening (
CONFIG_RANDOM_KMALLOC_CACHES,CONFIG_SLAB_BUCKETS) çıtayı yükseltir amaSLAB_VIRTUALyokluğunda cross-cache reclaim'i engellemez.
Bu UAF reclaim/cross-cache akışı, vsock UAF, transport-reassignment refcount UAF ve cross-cache attack grooming'iyle örtüşür.