summary refs log tree commit diff stats
path: root/hw/usb/canokey.c
diff options
context:
space:
mode:
authorHongren Zheng <i@zenithal.me>2025-01-13 17:38:56 +0800
committerPeter Maydell <peter.maydell@linaro.org>2025-01-28 18:40:19 +0000
commit664280abddcb3cacc9c6204706bb739fcc1316f7 (patch)
treeb1e0a2170070e9c598df814bc9ff5888a672efd3 /hw/usb/canokey.c
parente07b48995aaae22fb8aa582b0a53633734bbea92 (diff)
downloadfocaccia-qemu-664280abddcb3cacc9c6204706bb739fcc1316f7.tar.gz
focaccia-qemu-664280abddcb3cacc9c6204706bb739fcc1316f7.zip
hw/usb/canokey: Fix buffer overflow for OUT packet
When USBPacket in OUT direction has larger payload
than the ep_out_buffer (of size 512), a buffer overflow
would occur.

It could be fixed by limiting the size of usb_packet_copy
to be at most buffer size. Further optimization gets rid
of the ep_out_buffer and directly uses ep_out as the target
buffer.

This is reported by a security researcher who artificially
constructed an OUT packet of size 2047. The report has gone
through the QEMU security process, and as this device is for
testing purpose and no deployment of it in virtualization
environment is observed, it is triaged not to be a security bug.

Cc: qemu-stable@nongnu.org
Fixes: d7d34918551dc48 ("hw/usb: Add CanoKey Implementation")
Reported-by: Juan Jose Lopez Jaimez <thatjiaozi@gmail.com>
Signed-off-by: Hongren Zheng <i@zenithal.me>
Message-id: Z4TfMOrZz6IQYl_h@Sun
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/usb/canokey.c')
-rw-r--r--hw/usb/canokey.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/hw/usb/canokey.c b/hw/usb/canokey.c
index fae212f053..e2d66179e0 100644
--- a/hw/usb/canokey.c
+++ b/hw/usb/canokey.c
@@ -197,8 +197,8 @@ static void canokey_handle_data(USBDevice *dev, USBPacket *p)
     switch (p->pid) {
     case USB_TOKEN_OUT:
         trace_canokey_handle_data_out(ep_out, p->iov.size);
-        usb_packet_copy(p, key->ep_out_buffer[ep_out], p->iov.size);
         out_pos = 0;
+        /* segment packet into (possibly multiple) ep_out */
         while (out_pos != p->iov.size) {
             /*
              * key->ep_out[ep_out] set by prepare_receive
@@ -207,8 +207,8 @@ static void canokey_handle_data(USBDevice *dev, USBPacket *p)
              * to be the buffer length
              */
             out_len = MIN(p->iov.size - out_pos, key->ep_out_size[ep_out]);
-            memcpy(key->ep_out[ep_out],
-                    key->ep_out_buffer[ep_out] + out_pos, out_len);
+            /* usb_packet_copy would update the pos offset internally */
+            usb_packet_copy(p, key->ep_out[ep_out], out_len);
             out_pos += out_len;
             /* update ep_out_size to actual len */
             key->ep_out_size[ep_out] = out_len;