io_uring provided-buffer ring UAF (CVE-2024-0582)¶
IOU_PBUF_RING_MMAPile bir provided buffer ring register edip onu map'ledikten sonra unregister etmek, ring'in page'lerini free eder ama userspace mapping geçerli kalır — bir freed-page read/write primitive.
Mechanism¶
Bir provided buffer ring IORING_REGISTER_PBUF_RING ile register edilir. IOU_PBUF_RING_MMAP flag'iyle ring'in backing page'lerini (uygulamanın sağlaması yerine) kernel allocate eder ve userspace bunları mmap'ler.
Note
İhlal edilen invariant: canlı bir userspace virtual mapping hâlâ ona işaret ederken bir page page allocator'a geri verilmemeli. io_register_pbuf_ring() → io_alloc_pbuf_ring() üzerinden register, __get_free_pages() çağırır ve io_buffer_list üzerinde bl->is_mapped/bl->is_mmap'i set eder. User mapping, io_uring_mmap() tarafından remap_pfn_range() ve VM_PFNMAP flag'iyle oluşturulur; bu da kernel'a bu page'leri reference-count etmemesini söyler. Unregister sırasında io_unregister_pbuf_ring() → __io_remove_buffers() page'leri free_compound_page() ile free eder — ama hiçbir şey userspace'in onları hâlâ map'li tutup tutmadığını kontrol etmez. VM_PFNMAP refcounting'i bastırdığından, free edilmiş page'ler userspace'ten map'li ve yazılabilir kalır: tüm page'leri kapsayan bir UAF. (Adı "race" geçen sibling not'un aksine bu bir lifetime/refcount hatasıdır, bir TOCTOU yarışı değil.)
Warning
Page-granularity UAF read/write, tipik bir object UAF'tan çok daha güçlüdür — allocator free edilmiş page'leri yeni object'ler için yeniden kullandıkça attacker birden çok free edilmiş page'i okumaya ve yazmaya devam eder.
Walkthrough¶
Exodus Intelligence yazısından:
IOU_PBUF_RING_MMAPile bir provided buffer ring register et.- Ring'i userspace'e
mmap()'le. - Ring'i unregister et — page'ler free edilir ama mapping geçerli kalır (freed-page R/W).
- Free edilmiş page'leri yeniden allocate et: çocuk process'ler boyunca
/etc/passwd'yi defalarca açarakfilpcache'i tüket, böylece page allocator free edilmiş page'leri yenistruct fileobject'leri için backing olarak geri verir. - Hâlâ geçerli olan mapping üzerinden bir
struct filebul (ext4_file_operationspointer'ını ara), sonra read-only açılmış bir dosyada write'ı etkinleştirmek içinf_mode'u çevir ve append içinf_pos'u ayarla — data-only bir privilege escalation.
Bug, stable 6.6.5'te (8 Aralık 2023) patch'lendi ama Ubuntu'nun kernel'ına 6.5.0-21'e (22 Şubat 2024) kadar taşınmadı; bu da ~2.5 aylık bir "patch gap" 0day penceresi bıraktı. Zafiyetli aralık: Linux 6.4–6.6.4. Mainline fix commit c392cbecd8eca4c53f2bf508731257d9d0a21c2d, io_uring context'ine bir io_buf_list ekler ve ring page'lerini free etmeyi io_uring context'in kendisi yok edilene kadar — yani hiçbir userspace mapping artık var olamayana kadar — erteler.
Detection¶
Bir object reclaim edilmiş page'lere allocate edildiğinde KASAN o page'ler üzerinde use-after-free işaretler. IOU_PBUF_RING_MMAP ile bir pbuf ring register edip onu map'lemek ve mapping'i tutarak unregister etmek gözlemlenebilir dizidir.
Mitigation¶
IOU_PBUF_RING_MMAP ring'leri için mapping/free ilişkisini doğrulayan bir kernel'a güncelle. Unprivileged io_uring'i kısıtlamak (io_uring_disabled) register path'ini ortadan kaldırır. Genel page-spray hardening, reclaim adımının güvenilirliğini azaltır.