hw/usb/canokey: unvalidated endpoint number indexes 3-entry arrays -> out-of-bounds pointer write

hw/usb/canokey: unvalidated endpoint number indexes 3-entry arrays -> out-of-bounds pointer write (ASAN heap-buffer-overflow)

Summary

canokey_handle_data (hw/usb/canokey.c:188-214) takes the endpoint number straight from the USB packet (ep_out = p->ep->nr, guest-selectable 1..15 through any host-controller model) and uses it to index the fixed-size ep_out[] / ep_out_size[] arrays of CanoKeyState, which hold exactly CANOKEY_EP_NUM = 3 entries:

uint8_t ep_out = p->ep->nr;                     /* :193, guest-chosen  */
...
out_len = MIN(p->iov.size - out_pos, key->ep_out_size[ep_out]);  /* :209 OOB read */
usb_packet_copy(p, key->ep_out[ep_out], out_len);                /* :211 OOB ptr write */

No configuration, descriptor or bounds check gates the endpoint number: the USB core's usb_ep_get only asserts ep <= USB_MAX_ENDPOINTS (15) and usb_process_one dispatches non-ep0 packets without consulting p->ep->type. A forged bulk-OUT transfer on any endpoint number >= 3 therefore reads a bogus length from past ep_out_size[] and writes guest data through a wild pointer read from past ep_out[] - a guest-controlled host heap out-of-bounds write primitive.

Note this is distinct from the canokey buffer-capacity issue fixed in 664280ab (2025, "Fix buffer overflow for OUT packet", Stable-7.2.16): that fix restructured the copy to write directly into ep_out buffers of configured endpoints; the endpoint-number indexing defect is untouched and present on v11.1.1 (latest stable) and master 5f664cd3 (2026-09-13) (endpoint arrays indexed without bounds checks); reproduced on a v11.1.1 ASAN build (heap-buffer-overflow in __interceptor_memcpy).

Steps to reproduce

  1. Build QEMU v11.1.1 with ASAN (canokey is built by default).
  2. QEMU=/path/to/qemu-system-x86_64 ./reproduce.sh
  3. Observe:
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5030000cabbc
    #3 usb_packet_copy ../hw/usb/core.c:627
    #4 canokey_handle_data ../hw/usb/canokey.c:211
SUMMARY: AddressSanitizer: heap-buffer-overflow in __interceptor_memcpy

The qtest script acts as a minimal UHCI driver: PCI enable + BAR4, port enable, one OUT TD with pid=OUT / endpoint 5 / device address 1 on the frame list, then clock_step. The canokey is enumerated to address 1 by SeaBIOS during startup; no guest OS is required. Reproduces on a stock -device piix3-usb-uhci -device canokey,file=... machine.

Impact

Guest-controlled heap out-of-bounds write (memory-corruption primitive) in the QEMU host process, reachable on any deployment exposing the canokey device; no prior USB protocol interaction beyond attachment is needed.

Suggested fix

In canokey_handle_data, validate p->ep->nr < CANOKEY_EP_NUM (return USB_RET_STALL otherwise) before any array access, for both IN and OUT directions.

repro.qtest

reproduce.sh