Skip to content

Commit 54c89ff

Browse files
committed
fix(usb_host_hid): Changed the handling of reallocating ctrl_xfer buffer on large report descriptors
- Made all the null checks before any dereference - Fixed the unlock path on usb_host_transfer_alloc() error - Clamped req->wLength to some sane maximum (2048 bytes)
1 parent 889e749 commit 54c89ff

File tree

2 files changed

+70
-28
lines changed

2 files changed

+70
-28
lines changed
Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,47 @@
1-
## 1.0.4
1+
All notable changes to this project will be documented in this file.
2+
3+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
4+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5+
6+
## [Unreleased]
7+
8+
### Fixed
9+
10+
- Fixed a vulnerability with overwrite freed heap memory during `hid_host_get_report_descriptor()`
11+
12+
## [1.0.4] - 2025-09-24
13+
14+
### Added
15+
216
- Added support for ESP32-H4
317

4-
## 1.0.3
18+
## [1.0.3] - 2024-08-20
19+
20+
### Fixed
21+
522
- Fixed a bug with interface mismatch on EP IN transfer complete while several HID devices are present.
623
- Fixed a bug during device freeing, while detaching one of several attached HID devices.
724

8-
## 1.0.2
25+
## [1.0.2] - 2024-01-25
26+
27+
### Added
928

1029
- Added support for ESP32-P4
1130
- Fixed device open procedure for HID devices with multiple non-sequential interfaces.
1231

13-
## 1.0.1
32+
## [1.0.1] - 2023-10-04
33+
34+
### Added
35+
36+
- Added `hid_host_get_device_info()` to get the basic information of a connected USB HID device.
37+
38+
### Fixed
1439

1540
- Fixed a bug where configuring the driver with `create_background_task = false` did not properly initialize the driver. This lead to `the hid_host_uninstall()` hang-up.
1641
- Fixed a bug where `hid_host_uninstall()` would cause a crash during the call while USB device has not been removed.
17-
- Added `hid_host_get_device_info()` to get the basic information of a connected USB HID device.
1842

19-
## 1.0.0
43+
## [1.0.0] - 2023-06-22
44+
45+
### Added
2046

2147
- Initial version

host/class/hid/usb_host_hid/hid_host.c

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919

2020
#include "usb/hid_host.h"
2121

22+
// We are allowing realloc ctrl_xfer buffer, so max report desc size is limited by sane value
23+
// based on very large, exotic devices: can go into the low kilobytes
24+
#define HID_MIN_REPORT_DESC_LEN 512u
25+
#define HID_MAX_REPORT_DESC_LEN 2048u
26+
2227
// HID spinlock
2328
static portMUX_TYPE hid_lock = portMUX_INITIALIZER_UNLOCKED;
2429
#define HID_ENTER_CRITICAL() portENTER_CRITICAL(&hid_lock)
@@ -771,33 +776,40 @@ static esp_err_t hid_control_transfer(hid_device_t *hid_device,
771776
*/
772777
static esp_err_t usb_class_request_get_descriptor(hid_device_t *hid_device, const hid_class_request_t *req)
773778
{
774-
esp_err_t ret;
775-
usb_transfer_t *ctrl_xfer = hid_device->ctrl_xfer;
776-
const size_t ctrl_size = hid_device->ctrl_xfer->data_buffer_size;
777-
778779
HID_RETURN_ON_INVALID_ARG(hid_device);
779780
HID_RETURN_ON_INVALID_ARG(hid_device->ctrl_xfer);
780781
HID_RETURN_ON_INVALID_ARG(req);
781782
HID_RETURN_ON_INVALID_ARG(req->data);
782783

784+
if (req->wLength > HID_MAX_REPORT_DESC_LEN) {
785+
ESP_LOGE(TAG, "Requested descriptor size exceeds maximum");
786+
return ESP_ERR_INVALID_SIZE;
787+
}
788+
783789
HID_RETURN_ON_ERROR( hid_device_try_lock(hid_device, DEFAULT_TIMEOUT_MS),
784790
"HID Device is busy by other task");
785791

786-
if (ctrl_size < (USB_SETUP_PACKET_SIZE + req->wLength)) {
792+
esp_err_t ret;
793+
const uint32_t ctrl_size = hid_device->ctrl_xfer->data_buffer_size;
794+
const uint32_t required_size = USB_SETUP_PACKET_SIZE + req->wLength;
795+
796+
// Reallocate control transfer buffer if necessary
797+
if (ctrl_size < required_size) {
787798
usb_device_info_t dev_info;
788799
ESP_ERROR_CHECK(usb_host_device_info(hid_device->dev_hdl, &dev_info));
789-
// reallocate the ctrl xfer buffer for new length
790-
ESP_LOGD(TAG, "Change HID ctrl xfer size from %d to %d",
791-
(int) ctrl_size,
792-
(int) (USB_SETUP_PACKET_SIZE + req->wLength));
800+
801+
ESP_LOGD(TAG, "Change HID ctrl xfer size from %"PRIu32" to %"PRIu32"", ctrl_size, required_size);
793802

794803
usb_host_transfer_free(hid_device->ctrl_xfer);
795-
HID_RETURN_ON_ERROR( usb_host_transfer_alloc(USB_SETUP_PACKET_SIZE + req->wLength,
796-
0,
797-
&hid_device->ctrl_xfer),
798-
"Unable to allocate transfer buffer for EP0");
804+
805+
if (usb_host_transfer_alloc(required_size, 0, &hid_device->ctrl_xfer) != ESP_OK) {
806+
ESP_LOGE(TAG, "Unable to re-allocate transfer buffer for EP0");
807+
hid_device_unlock(hid_device);
808+
return ESP_ERR_NO_MEM;
809+
}
799810
}
800811

812+
usb_transfer_t *ctrl_xfer = hid_device->ctrl_xfer;
801813
usb_setup_packet_t *setup = (usb_setup_packet_t *)ctrl_xfer->data_buffer;
802814

803815
setup->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN |
@@ -808,16 +820,20 @@ static esp_err_t usb_class_request_get_descriptor(hid_device_t *hid_device, cons
808820
setup->wIndex = req->wIndex;
809821
setup->wLength = req->wLength;
810822

811-
ret = hid_control_transfer(hid_device,
812-
USB_SETUP_PACKET_SIZE + req->wLength,
813-
DEFAULT_TIMEOUT_MS);
823+
ret = hid_control_transfer(hid_device, required_size, DEFAULT_TIMEOUT_MS);
814824

815825
if (ESP_OK == ret) {
816-
ctrl_xfer->actual_num_bytes -= USB_SETUP_PACKET_SIZE;
817-
if (ctrl_xfer->actual_num_bytes <= req->wLength) {
818-
memcpy(req->data, ctrl_xfer->data_buffer + USB_SETUP_PACKET_SIZE, ctrl_xfer->actual_num_bytes);
819-
} else {
826+
if (ctrl_xfer->actual_num_bytes < USB_SETUP_PACKET_SIZE) {
820827
ret = ESP_ERR_INVALID_SIZE;
828+
} else {
829+
ctrl_xfer->actual_num_bytes -= USB_SETUP_PACKET_SIZE;
830+
if (ctrl_xfer->actual_num_bytes <= req->wLength) {
831+
memcpy(req->data,
832+
ctrl_xfer->data_buffer + USB_SETUP_PACKET_SIZE,
833+
ctrl_xfer->actual_num_bytes);
834+
} else {
835+
ret = ESP_ERR_INVALID_SIZE;
836+
}
821837
}
822838
}
823839

@@ -999,9 +1015,9 @@ esp_err_t hid_host_install_device(uint8_t dev_addr,
9991015
/*
10001016
* TIP: Usually, we need to allocate 'EP bMaxPacketSize0 + 1' here.
10011017
* To take the size of a report descriptor into a consideration,
1002-
* we need to allocate more here, e.g. 512 bytes.
1018+
* we need to allocate more here.
10031019
*/
1004-
HID_GOTO_ON_ERROR(usb_host_transfer_alloc(512, 0, &hid_device->ctrl_xfer),
1020+
HID_GOTO_ON_ERROR(usb_host_transfer_alloc(HID_MIN_REPORT_DESC_LEN, 0, &hid_device->ctrl_xfer),
10051021
"Unable to allocate transfer buffer");
10061022

10071023
HID_ENTER_CRITICAL();

0 commit comments

Comments
 (0)