summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
authorXingrui Li <baka9@bakabaka9.tech>2026-08-05 18:57:53 +0000
committerJiri Kosina <jkosina@suse.com>2026-08-14 14:55:44 +0200
commitc92693f3ed099401d0383ef35ca1fe1e6ba033de (patch)
tree27c02f4c7ef14faa8af100e4726e064a17dc1634 /drivers/hid
parentce08c5555cabcd444d8b77fa69a7cb68bb05f611 (diff)
HID: sensor-hub: Fix out-of-bounds write in sensor_hub_get_feature
sensor_hub_get_feature() clamps its return value to the caller's buffer size, but the copy loop still copies field->report_size / 8 bytes for each report value. A malicious HID descriptor can advertise a large feature field size while an IIO caller supplies a small stack buffer, such as a single s32, causing an out-of-bounds write. HID core stores parsed report values in __s32 slots and clamps extracted values to 32 bits. Reject feature fields that require more than one slot per value, guard the total byte count calculation, and clamp each per-value copy to the remaining caller buffer. Fixes: 5459ada2b3cd69 ("HID: sensor-hub: Fix packing of result buffer for feature report") Cc: stable@kernel.org Assisted-by: OpenAI:GPT-5.5-Cyber Signed-off-by: Xingrui Li <baka9@bakabaka9.tech> Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Signed-off-by: Jiri Kosina <jkosina@suse.com>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-sensor-hub.c42
1 files changed, 25 insertions, 17 deletions
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 90666ff629de..9bbda38ded96 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -239,12 +239,17 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
u32 field_index, int buffer_size, void *buffer)
{
struct hid_report *report;
+ struct hid_field *field;
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
- int report_size;
+ size_t field_size;
+ size_t report_size;
+ size_t copied = 0;
+ size_t to_copy;
int ret = 0;
- u8 *val_ptr;
- int buffer_index = 0;
- int i;
+ unsigned int i;
+
+ if (!buffer || buffer_size <= 0)
+ return -EINVAL;
memset(buffer, 0, buffer_size);
@@ -258,26 +263,29 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
hid_hw_wait(hsdev->hdev);
+ field = report->field[field_index];
+
/* calculate number of bytes required to read this field */
- report_size = DIV_ROUND_UP(report->field[field_index]->report_size,
- 8) *
- report->field[field_index]->report_count;
- if (!report_size) {
+ field_size = DIV_ROUND_UP(field->report_size, 8);
+ /* HID core stores each parsed report value in a __s32 slot. */
+ if (!field_size || field_size > sizeof(field->value[0])) {
+ ret = -EINVAL;
+ goto done_proc;
+ }
+ if (field->report_count > SIZE_MAX / field_size) {
ret = -EINVAL;
goto done_proc;
}
- ret = min(report_size, buffer_size);
- val_ptr = (u8 *)report->field[field_index]->value;
- for (i = 0; i < report->field[field_index]->report_count; ++i) {
- if (buffer_index >= ret)
- break;
+ report_size = field_size * field->report_count;
+ report_size = min_t(size_t, report_size, buffer_size);
- memcpy(&((u8 *)buffer)[buffer_index], val_ptr,
- report->field[field_index]->report_size / 8);
- val_ptr += sizeof(__s32);
- buffer_index += (report->field[field_index]->report_size / 8);
+ for (i = 0; i < field->report_count && copied < report_size; ++i) {
+ to_copy = min(field_size, report_size - copied);
+ memcpy(&((u8 *)buffer)[copied], &field->value[i], to_copy);
+ copied += to_copy;
}
+ ret = copied;
done_proc:
mutex_unlock(&data->mutex);