Skip to content

Paravirtualized device descriptor confusion (virtio used-ring metadata abuse)

Split-ring'in bir tarafının, diğer tarafın sağladığı ring metadata'sına bounds-check yapmadan güvendiği bir virtio bug sınıfı — sahte bir used-ring entry'sinin id'si ya da len'i doğrudan bir array index'i ya da copy length'i olarak kullanılır ve trust boundary boyunca out-of-bounds memory corruption üretir.

Mechanism

Note

virtio bir split virtqueue kullanır: bir descriptor table, bir available ring (driver -> device: hangi buffer'lar hazır) ve bir used ring (device -> driver: hangi buffer'lar tüketildi ve kaç byte yazıldı). Her struct vring_used_elem device tarafından yazılan iki field taşır: id (tamamlanan chain'in head descriptor index'i) ve len (yazılan byte'lar).

Güvenlik kontratı, her tarafın diğer tarafın kontrol ettiği metadata'yı validate etmesidir. Bug sınıfı bu validation eksik olduğunda ortaya çıkar:

  • id confusion: bir consumer used ring'den id'yi okur ve id < queue->num kontrolünü yapmadan onu doğrudan sabit boyutlu bir per-descriptor info array'ini (info[id], recv_events[id], ...) index'lemek için kullanır. Aralık dışı bir id bir out-of-bounds array access'ine (read ya da write) dönüşür.
  • len underflow: kod len - header_size gibi bir payload boyutu hesaplar; sahte bir len header'dan küçükse, unsigned çıkarma kocaman bir değere underflow eder, bu da sonra fazla büyük bir memcpy'yi sürer — bir out-of-bounds write.

Kırılan invariant ring-metadata, paravirtual boundary boyunca untrusted input'tur. Simetrik olarak, host/QEMU tarafında aynı tehlike driver tarafından kontrol edilen descriptor-table/available-ring field'ları (length'ler, index'ler, zincirlenmiş next pointer'lar) için vardır: guest tarafından sağlanan bir descriptor length/index'e güvenen emulated bir device OOB'a sürülebilir — bu confusion'ın device-emulation biçimi ve bir guest-to-host escape vektörü.

Walkthrough

Public reference: used-ring id/len validation boşluklarını belgeleyen RT-Thread advisory'si (RT-Thread/rt-thread#11326); ring layout'u için OASIS virtio spec'i. Kavramsal reprodüksiyon (consumer tarafı, id confusion):

  1. Kötü niyetli producer (ele geçirilmiş bir backend ya da host tarafı aynada kötü niyetli bir guest driver), id >= queue size olan bir vring_used_elem yazar.
  2. Consumer onu dequeue eder ve hiç bound check'i olmadan info[id] yapar:
    struct vring_used_elem e = used->ring[used_idx % qsz];
    handle(&dev->info[e.id]);     // e.id unchecked  -> OOB
    
  3. Aralık dışı index sabit array'in ötesini okur/yazar ve komşu state'i corrupt eder.

len underflow varyantı (virtio-net tarzı):

payload = e.len - VIRTIO_NET_HDR_SIZE;   // e.len < HDR_SIZE -> unsigned wrap
rt_memcpy(dst, src, payload);            // huge length -> OOB write

Beklenen gözlemlenebilir: hazırlanmış bir used ring ile consumer crash eder ya da komşu veri yapıları corrupt olur — "doğrudan ve güvenilir" bir cross-trust-boundary corruption primitive'i.

Warning

Yalnızca kontrol ettiğin sistemlere karşı test et. Aynı pattern host tarafında (guest descriptor length'lerine/index'lerine güvenen QEMU/vhost emulated device'ları) klasik bir VM-escape yüzeyidir — bu KB'deki QEMU virtio CVE'lerine bak (virtio-net descriptor UAF, virtio DMA reentrancy double-free).

Detection

  • Code audit: used-ring id/len'inin (ya da device tarafında descriptor-table length/index'inin) her kullanımı, bir index ya da copy size olarak kullanılmadan önce bounds-check'lenmelidir.
  • Ring metadata'sını (aralık dışı id, sub-header len) driver/device'a karşı fuzz'la ve OOB fault'ları için izle (ASAN/KASAN).

Mitigation

  • Index'lemeden önce id < queue_size'ı validate et; reddet ya da clamp'le.
  • len'den türetilen boyutlar için checked arithmetic kullan; herhangi bir copy'den önce len >= header_size'ı ve len <= gerçek descriptor capacity'sini doğrula.
  • Diğer taraftan gelen tüm ring metadata'sını düşmanca input olarak ele al; etkilenen virtio driver'ları/device'ları için vendor fix'lerini uygula.

References

  • RT-Thread advisory — "Malicious virtio backend can trigger guest-kernel memory corruption through unvalidated used-ring ids and lengths" (issue #11326). https://github.com/RT-Thread/rt-thread/issues/11326
  • OASIS — "Virtual I/O Device (VIRTIO) Version 1.1" (split virtqueue, used ring, vring_used_elem). https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html