All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] hw/usb: Fix USB MTP heap OOB read via dlen underflow
@ 2026-09-25  9:23 Tommaso Califano
  2026-09-29 10:09 ` Luigi Leonardi
  0 siblings, 1 reply; 3+ messages in thread
From: Tommaso Califano @ 2026-09-25  9:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Philippe Mathieu-Daudé, Paolo Bonzini, Tommaso Califano

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



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] hw/usb: Fix USB MTP heap OOB read via dlen underflow
  2026-09-25  9:23 [PATCH] hw/usb: Fix USB MTP heap OOB read via dlen underflow Tommaso Califano
@ 2026-09-29 10:09 ` Luigi Leonardi
  2026-10-05 14:24   ` Tommaso Califano
  0 siblings, 1 reply; 3+ messages in thread
From: Luigi Leonardi @ 2026-09-29 10:09 UTC (permalink / raw)
  To: Tommaso Califano; +Cc: qemu-devel, Philippe Mathieu-Daudé, Paolo Bonzini

Ciao Tommaso,

On Fri, Sep 25, 2026 at 11:23:14AM +0200, Tommaso Califano wrote:
>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
>
>

Thanks for this patch!

I ran checkpatch `./scripts/checkpatch.pl HEAD~1..HEAD` and there is a
style error:

`
ERROR: suspect code indent for conditional statements (4, 9)
#34: FILE: hw/usb/dev-mtp.c:1709:
+    if (dlen < offsetof(ObjectInfo, filename)) {
+         usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, d->trans,
`

Please fix it :)

Also, do we need a Fixes tag?

I think:
Fixes: 90c1a74271ce ("usb-mtp: Limit filename to object information size")

Probably we should also CC QEMU stable.

That said: I'm definitely not a USB expert by any means but I _think_
that we should not use `dlen`, but `d->length`.

Correct me if I'm wrong, but IIUC a transfer can be split across
multiple descriptors, each sized `dlen`. Using `dlen` there, means that we are
checking against the last one. It could happen that dlen is smaller than
d->length, triggering the check.

Does this make sense to you?

Thanks,
Luigi



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] hw/usb: Fix USB MTP heap OOB read via dlen underflow
  2026-09-29 10:09 ` Luigi Leonardi
@ 2026-10-05 14:24   ` Tommaso Califano
  0 siblings, 0 replies; 3+ messages in thread
From: Tommaso Califano @ 2026-10-05 14:24 UTC (permalink / raw)
  To: Luigi Leonardi; +Cc: qemu-devel, Philippe Mathieu-Daudé, Paolo Bonzini

Ciao Luigi,

>
>Thanks for this patch!
>

Thank you for the review!

>I ran checkpatch `./scripts/checkpatch.pl HEAD~1..HEAD` and there is a
>style error:
>
>`
>ERROR: suspect code indent for conditional statements (4, 9)
>#34: FILE: hw/usb/dev-mtp.c:1709:
>+    if (dlen < offsetof(ObjectInfo, filename)) {
>+         usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, d->trans,
>`
>
>Please fix it :)
>

Ops, I am sorry. Solved :)

>Also, do we need a Fixes tag?
>
>I think:
>Fixes: 90c1a74271ce ("usb-mtp: Limit filename to object information size")
>

Probably yes, but I was not aware of its existence. Thanks for pointing
me out.

>Probably we should also CC QEMU stable.
>

I'll cc it in V2.

>That said: I'm definitely not a USB expert by any means but I _think_
>that we should not use `dlen`, but `d->length`.
>
>Correct me if I'm wrong, but IIUC a transfer can be split across
>multiple descriptors, each sized `dlen`. Using `dlen` there, means that we are
>checking against the last one. It could happen that dlen is smaller than
>d->length, triggering the check.
>
>Does this make sense to you?
>

Yes, you are right. After studying better the code I think the best
solution is to remove dlen and use d->length for computing filename_chars.

Many thanks,
Tommaso



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-05 14:25 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-25  9:23 [PATCH] hw/usb: Fix USB MTP heap OOB read via dlen underflow Tommaso Califano
2026-09-29 10:09 ` Luigi Leonardi
2026-10-05 14:24   ` Tommaso Califano

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.