Skip to content

io_uring provided-buffer ring UAF (CVE-2024-0582)

IOU_PBUF_RING_MMAP ile 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:

  1. IOU_PBUF_RING_MMAP ile bir provided buffer ring register et.
  2. Ring'i userspace'e mmap()'le.
  3. Ring'i unregister et — page'ler free edilir ama mapping geçerli kalır (freed-page R/W).
  4. Free edilmiş page'leri yeniden allocate et: çocuk process'ler boyunca /etc/passwd'yi defalarca açarak filp cache'i tüket, böylece page allocator free edilmiş page'leri yeni struct file object'leri için backing olarak geri verir.
  5. Hâlâ geçerli olan mapping üzerinden bir struct file bul (ext4_file_operations pointer'ını ara), sonra read-only açılmış bir dosyada write'ı etkinleştirmek için f_mode'u çevir ve append için f_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.

References