[PATCH] hw/usb: Fix USB MTP heap OOB read via dlen underflow

Tommaso Califano posted 1 patch 1 day, 9 hours ago
hw/usb/dev-mtp.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
[PATCH] hw/usb: Fix USB MTP heap OOB read via dlen underflow
Posted by Tommaso Califano 1 day, 9 hours ago
In QEMU’s USB MTP device, usb_mtp_write_metadata() computes
filename_chars = dlen - offsetof(ObjectInfo, filename) where
offsetof(ObjectInfo,filename) = 53. The dlen parameter is the size of the
last USB packet, not the total ObjectInfo size. If the final packet has
fewer than 53 bytes, filename_chars underflows to SIZE_MAX, causing
utf16_to_str() to read far beyond the heap buffer, leaking QEMU host
process memory.

Add a guard to return RES_INVALID_OBJECTINFO, preventing the case.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3992
Signed-off-by: Tommaso Califano <tcalifan@redhat.com>
---
 hw/usb/dev-mtp.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 1d8cfd32dc..704e6c533d 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -1704,7 +1704,15 @@ static void usb_mtp_write_metadata(MTPState *s, uint64_t dlen)
     MTPObject *o;
     MTPObject *p = usb_mtp_object_lookup(s, s->dataset.parent_handle);
     uint32_t next_handle = s->next_handle;
-    size_t filename_chars = dlen - offsetof(ObjectInfo, filename);
+    size_t filename_chars;
+
+    if (dlen < offsetof(ObjectInfo, filename)) {
+         usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, d->trans,
+                            0, 0, 0, 0);
+         return;
+    }
+
+    filename_chars = dlen - offsetof(ObjectInfo, filename);

     /*
      * filename is utf-16. We're intentionally doing
--
2.55.0