QEMU USB usb_process_one out-of-bounds R/W (setup_len) VM escape¶
QEMU'nun USB core'u, guest-controlled bir
setup_len'i validate etmeden önce atadı, böylece bozuk bir USB SETUP packet'i,do_token_in/do_token_out'u 4096-byte'lıkdata_buf'ın ötesine read veya write yapmaya sürükleyebilir ve host memory corruption'ı ile tam bir VM escape'i mümkün kılabilirdi (CVE-2020-14364).
Mechanism¶
İzolasyon invariant'ı: bir guest length alanı, host buffer erişimini geçirmeden önce validate edilmelidir
USB control transfer'leri, wLength alanı device'a kaç data byte'ının takip ettiğini söyleyen 8-byte'lık bir SETUP packet'i taşır. QEMU'nun USB core'u, bu byte'ları sabit bir buffer olan USBDevice->data_buf[4096] içinde saklar ve ilerlemeyi USBDevice->setup_len ile izler. Invariant şu: setup_len, asla sizeof(data_buf)'ı aşmamalıdır, çünkü sonraki data-stage handler'ları (do_token_in, do_token_out, usb_process_one'dan erişilir) data_buf'a/data_buf'tan setup_len byte kopyalar.
Vulnerable kodda, do_token_setup() / do_parameter(), s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6] hesapladı ve bunu struct alanına atadı, ardından if (s->setup_len > sizeof(s->data_buf)) kontrol etti. Kontrol var olsa da, bazı path'lerde aralık dışı değer zaten s->setup_len'e işlenmişti ve etkisiz hâle getirilmeden önce data stage tarafından tüketilebiliyordu, böylece do_token_in/out bir index'i 4096'dan büyük guest tarafından seçilen bir değere kadar ilerletti. Bu, data_buf'a komşu host heap memory'sinin out-of-bounds read ve write'ıdır. data_buf, host QEMU process'inde yaşadığı için, bir guest host memory'sinde bir OOB R/W primitive'ini tamamen kontrol eder — bir VM escape'in temeli (QEMU process olarak arbitrary code execution, QEMU root olarak çalışıyorsa root).
Walkthrough¶
oss-security açıklamasına (Gerd Hoffmann'ın 0001-usb-fix-setup-len-init.patch'i) ve openEuler yazısına dayanır. Ön koşul: VM'in en az bir USB device'ı bağlı.
-
Guest, SETUP stage'i
setup_buf[6..7]içinde 4096'dan büyük birwLength(örn.0xffff) kodlayan bir USB control transfer'i verir. -
do_token_setup(),s->setup_len'i bu byte'lardan hesaplar ve atar. Data stage (usb_process_one→do_token_in/do_token_out) ardındandata_buf'ı indekslemek içinsetup_len'i kullanır. -
setup_len > sizeof(data_buf)ile copy, 4096-byte'lık buffer'ın ötesine — IN'de OOB read, OUT'ta OOB write — komşu host heap'e yürür.Fix'in kavramsal şekli (bir local'e validate et, sonra commit et)
Fix, uzunluğu bir local değişkende validate eder ve overflow'da/* hw/usb/core.c — direction of the upstream fix */ int len = (s->setup_buf[7] << 8) | s->setup_buf[6]; if (len > sizeof(s->data_buf)) { /* reject before it can gate data_buf access */ s->setup_len = 0; s->setup_state = SETUP_STATE_ACK; return; } s->setup_len = len; /* only assigned once known-good */setup_len/setup_state'i clamp eder, böylece data-stage handler'ları asladata_buf'ın ötesini indeksleyemez. -
Gözlemlenebilir sonuç: patch'siz core'da OOB erişimi host heap'i bozar. Özenle hazırlanmış bir layout, kontrollü OOB write'ı bir exploitation primitive'ine çevirir; minimal olarak QEMU'yu crash eder (DoS), en kötü durumda host code execution verir (escape).
Tarihî / patch'li — burada weaponize edilmiş chain yok
Bu kayıt yalnızca bug sınıfını ve public reproduction path'ini belgeler. Kasıtlı olarak heap-grooming, leak veya control-flow-hijack adımları sağlamaz. Yalnızca patch'li lab sistemlerine karşı, yetkili araştırma/savunma için kullan.
Detection¶
- Crash signature: guest USB control transfer'leriyle tetiklenen QEMU SIGSEGV veya heap corruption (glibc "malloc(): corrupted" /
data_bufüzerinde ASan heap-buffer-overflow) doğrudan bu sınıfı işaret eder. - ASan/Valgrind: QEMU'yu AddressSanitizer ile derlemek, fuzzing veya testing sırasında
data_bufüzerindeki OOB read/write'ı hemen işaretler. - Fuzzing: SETUP
wLengthalanını mutate eden USB control-transfer fuzzing'i bunu yeniden üretir; structured device fuzzing harness'leri bu path'i kapsar (bkz. ../hypervisor/snapshot-based-greybox-hypervisor-fuzzing.md). - Guest telemetry: aşırı büyük
wLength(4096'nın çok ötesinde) bildiren tekrarlayan control transfer'leri anormaldir ve device model'inde gözlemlenebilir.
Mitigation¶
- Patch: SETUP uzunluğunu
data_buferişimini geçirmeden önce validate eden Gerd Hoffmann'ınusb: fix setup_len initfix'ini taşıyan QEMU 5.2.0 veya sonrasına güncelle. - Reduce surface: gerekmedikçe USB controller/device'ları güvenilmeyen guest'lere bağlama; bug en az bir USB device'ının mevcut olmasına ihtiyaç duyar.
- Drop host privilege: QEMU'yu asla root olarak çalıştırma — adanmış unprivileged bir uid olarak çalıştır, böylece bir escape root değil, düşük ayrıcalıklı bir context'e düşer.
- Confinement: seccomp (
-sandbox on), sVirt/SELinux ve namespacing'i etkinleştir, böylece bozulmuş bir QEMU process'i sıkıca contained olur ve herhangi bir escape'in blast radius'unu sınırlar.