Re: [PATCH] HID: intel-thc-hid: intel-quickspi: bound GET_REPORT response to the caller buffer

[email protected] Thu, 06 Aug 2026 14:11:28 +0000
Newsgroups org.kernel.vger.linux-input
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:

New issues:
- [High] The newly added bounds check for `qsdev->report_len` against `buf_len` is vulnerable to a Time-of-Check to Time-of-Use (TOCTOU) race condition.

Pre-existing issues:
- [Critical] Heap buffer overflow in `write_cmd_to_txdma` due to unbounded userspace input (host to device).
- [High] Missing synchronization around shared DMA buffers leads to data corruption across concurrent HID raw requests.
- [High] Completion flags for report requests are not cleared before sending commands, leading to stale responses.
- [High] Malicious device input can overflow `qsdev->report_buf` due to mismatched maximum bounds (device to host).
- [High] Tearing down DMA before disabling interrupts allows the IRQ thread to access freed scatter-gather lists.
- [High] Missing `dma_sync_sg_for_device` and `dma_sync_sg_for_cpu` calls when accessing long-lived DMA mapped scatterlists.
--

--- Patch [1]: [PATCH] HID: intel-thc-hid: intel-quickspi: bound GET_REPORT response to the caller buffer ---
commit ec62591c11a2dc3339b24ad3e40072aee89c7d83
Author: HyeongJun An <[email protected]>

HID: intel-thc-hid: intel-quickspi: bound GET_REPORT response to the caller buffer

This patch adds a bounds check to quickspi_get_report() to ensure the
device-supplied qsdev->report_len does not exceed the caller-provided
buf_len. It aims to prevent buffer overflows when copying the response to
the caller's buffer.

> diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
> index 91d5807b4a830..a60a0a7f16aad 100644
> --- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
> +++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
> @@ -61,7 +61,7 @@ static int quickspi_hid_raw_request(struct hid_device *hid,
>  
>  	switch (reqtype) {
>  	case HID_REQ_GET_REPORT:
> -		ret = quickspi_get_report(qsdev, rtype, reportnum, buf);
> +		ret = quickspi_get_report(qsdev, rtype, reportnum, buf, len);

[Severity: High]
This is a pre-existing issue, but does this code lack synchronization
around shared DMA buffers? 

Multiple userspace threads can concurrently issue requests through
quickspi_hid_raw_request() lacking any mutual exclusion before touching shared
device buffers. Both GET and SET report paths modify and read the same
qsdev->report_buf locklessly (e.g., via write_cmd_to_txdma()), and the IRQ
handler also writes to this buffer. 

Could this lead to data corruption across concurrent HID raw requests?

>  		break;
>  	case HID_REQ_SET_REPORT:
>  		ret = quickspi_set_report(qsdev, rtype, reportnum, buf, len);

[Severity: Critical]
This is a pre-existing issue, but can unbounded userspace input cause a heap
buffer overflow here? 

The user-controlled len is passed to write_cmd_to_txdma(), which executes:

if (report_buf && report_buf_len > 0)
    memcpy(write_buf->content, report_buf, report_buf_len);

This memcpy lacks bounds checking against the allocated size of
qsdev->report_buf, which could allow a local user writing to the hidraw
device to overwrite adjacent heap objects.

> diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c
> index cb19057f1191b..9c4fce09729d3 100644
> --- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c
> +++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c
[ ... ]
> @@ -372,6 +373,12 @@ int quickspi_get_report(struct quickspi_device *qsdev,
>  	}
>  	qsdev->get_report_cmpl = false;

[Severity: High]
This is a pre-existing issue, but are the completion flags managed correctly
when timeouts occur? 

If wait_event_interruptible_timeout() times out, it returns early and does not
reset qsdev->get_report_cmpl = false. 

If a delayed interrupt then sets this flag, the next call to
quickspi_get_report() will send a command and immediately pass the wait_event,
consuming stale or uninitialized response data.

>  
> +	if (qsdev->report_len > buf_len) {

[Severity: High]
Is there a Time-of-Check to Time-of-Use (TOCTOU) race condition here? 

The qsdev->report_len variable is evaluated in this condition and then
evaluated again in the memcpy below. Because there is no locking, a
concurrent update from quickspi_handle_input_data() could change
qsdev->report_len between the check and the use, leading to a buffer overflow
in the caller's buffer.

> +		dev_err_once(qsdev->dev, "Get report response too big, %u vs %u\n",
> +			     qsdev->report_len, buf_len);
> +		return -EINVAL;
> +	}
> +
>  	memcpy(buf, qsdev->report_buf, qsdev->report_len);
>  
>  	return qsdev->report_len;
> diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.h b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.h
> index 775e29c1ed136..8a2338bee8085 100644
> --- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.h
> +++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.h
> @@ -12,7 +12,7 @@ struct quickspi_device;
>  
>  void quickspi_handle_input_data(struct quickspi_device *qsdev, u32 buf_len);

[Severity: High]
This is a pre-existing issue, but could malicious device input overflow
qsdev->report_buf here? 

In quickspi_handle_input_data(), the incoming data is validated against the
size of qsdev->input_buf, but then copied into qsdev->report_buf:

memcpy(qsdev->report_buf, input_report, qsdev->report_len);

Since qsdev->input_buf can be larger than qsdev->report_buf based on varying
device descriptor fields, could a device send a packet that passes the
input_buf bounds check but overflows report_buf?


[Severity: High]
This is a pre-existing issue, but does quickspi_remove() in pci-quickspi.c
tear down DMA resources before disabling interrupts?

quickspi_remove() {
    ...
    quickspi_dma_deinit();
    quickspi_dev_deinit();
}

The driver destroys DMA structures and SG lists before calling
quickspi_dev_deinit() to quiesce hardware interrupts. If a device interrupt
fires in this window, could the IRQ thread access freed scatter-gather
lists?


[Severity: High]
This is a pre-existing issue, but is the driver missing required DMA API sync
calls in intel-thc-dma.c? 

The driver modifies and reads CPU virtual addresses of SG lists using
sg_copy_from_buffer() (in write_dma_buffer()) and sg_copy_to_buffer() (in
thc_swdma_read()). 

Are calls to dma_sync_sg_for_device() and dma_sync_sg_for_cpu() required here
to prevent silent I/O corruption on systems with SWIOTLB or non-coherent DMA
architectures?

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1