qemu/hw/usb/canokey.h
Hongren Zheng 664280abdd 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: d7d3491855 ("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>
2025-01-28 18:40:19 +00:00

65 lines
1.7 KiB
C

/*
* CanoKey QEMU device header.
*
* Copyright (c) 2021-2022 Canokeys.org <contact@canokeys.org>
* Written by Hongren (Zenithal) Zheng <i@zenithal.me>
*
* This code is licensed under the GPL v2 or later.
*/
#ifndef CANOKEY_H
#define CANOKEY_H
#include "hw/qdev-core.h"
#define TYPE_CANOKEY "canokey"
#define CANOKEY(obj) \
OBJECT_CHECK(CanoKeyState, (obj), TYPE_CANOKEY)
/*
* State of Canokey (i.e. hw/canokey.c)
*/
/* CTRL INTR BULK */
#define CANOKEY_EP_NUM 3
/* BULK/INTR IN can be up to 1352 bytes, e.g. get key info */
#define CANOKEY_EP_IN_BUFFER_SIZE 2048
typedef enum {
CANOKEY_EP_IN_WAIT,
CANOKEY_EP_IN_READY,
CANOKEY_EP_IN_STALL
} CanoKeyEPState;
typedef struct CanoKeyState {
USBDevice dev;
/* IN packets from canokey device loop */
uint8_t ep_in[CANOKEY_EP_NUM][CANOKEY_EP_IN_BUFFER_SIZE];
/*
* See canokey_emu_transmit
*
* For large INTR IN, receive multiple data from canokey device loop
* in this case ep_in_size would increase with every call
*/
uint32_t ep_in_size[CANOKEY_EP_NUM];
/*
* Used in canokey_handle_data
* for IN larger than p->iov.size, we would do multiple handle_data()
*
* The difference between ep_in_pos and ep_in_size:
* We first increase ep_in_size to fill ep_in buffer in device_loop,
* then use ep_in_pos to submit data from ep_in buffer in handle_data
*/
uint32_t ep_in_pos[CANOKEY_EP_NUM];
CanoKeyEPState ep_in_state[CANOKEY_EP_NUM];
/* OUT pointer to canokey recv buffer */
uint8_t *ep_out[CANOKEY_EP_NUM];
uint32_t ep_out_size[CANOKEY_EP_NUM];
/* Properties */
char *file; /* canokey-file */
} CanoKeyState;
#endif /* CANOKEY_H */