[PATCH v2] HID: sensor-hub: Fail unfinished multi-value reads on removal

From: Yibo Tan

Date: Sat Sep 12 2026 - 01:03:42 EST


sensor_hub_remove() completes pending reads after stopping the HID device,
but does not record why they completed. A successful completion wait
therefore returns zero even if no complete input report was received.
Multi-value IIO callers then format their untouched automatic buffer as a
successful result.

With a valid four-element signed 32-bit quaternion report descriptor, an
unprivileged reader received all 16 bytes of the untouched buffer. Across
11 independent KASLR-enabled boots, four reads exposed exact pointers to
dev_rot_channels or dev_sysfs_ops. Subtracting the matching link-time
symbol address recovered the kernel KASLR slide in all four cases.

The reader ran as UID/GID 65534 with no effective capabilities through the
mode-0644 IIO attribute. The test used a privileged UHID broker to create
and remove the provider; it does not demonstrate unprivileged provider
removal.

Publish -ENODEV through pending.raw_size before completing an unfinished
multi-value request, and propagate the error after a successful wait. A
fully received response already has a positive raw_size and remains
successful; max_raw_size is zero for the separate single-value path.

The Root B-only repair returned -ENODEV with no payload or kernel
diagnostic in 3/3 matching signed-32-bit runs. The source reproducer,
complete vulnerable and fixed serial logs, result tables, and checksums are
available in [1].

Link: https://github.com/kimaiden1984-boop/linux-kernel-poc-collections/tree/main/cases/hid-sensor-quaternion-root-b-kaslr [1]
Fixes: f784fcea4506 ("HID: sensor-hub: Add sensor_hub_input_attr_read_values() for multi-byte reads")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
Signed-off-by: Yibo Tan <lhfff@xxxxxxxxxx>
---
Changes in v2:
- Turn the reproducer URL into a Link trailer and cite it from the text.
- Use the reviewer-requested generic LLM assistance trailer.

v1: https://lore.kernel.org/r/20260911092039.234253-1-lhfff@xxxxxxxxxx/

drivers/hid/hid-sensor-hub.c | 7 ++++++-
include/linux/hid-sensor-hub.h | 2 +-
2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 6470a290ebfc..687f8defa2f0 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -334,6 +334,8 @@ int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev,
ret = -ETIMEDOUT;
else if (cycles < 0)
ret = cycles;
+ else if (hsdev->pending.raw_size < 0)
+ ret = hsdev->pending.raw_size;

hsdev->pending.status = false;
}
@@ -805,8 +807,11 @@ static int sensor_hub_finalize_pending_fn(struct device *dev, void *data)
{
struct hid_sensor_hub_device *hsdev = dev->platform_data;

- if (hsdev->pending.status)
+ if (hsdev->pending.status) {
+ if (hsdev->pending.max_raw_size && !hsdev->pending.raw_size)
+ hsdev->pending.raw_size = -ENODEV;
complete(&hsdev->pending.ready);
+ }

return 0;
}
diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h
index ab5cc8db3fbb..4ad53304bb0b 100644
--- a/include/linux/hid-sensor-hub.h
+++ b/include/linux/hid-sensor-hub.h
@@ -41,7 +41,7 @@ struct hid_sensor_hub_attribute_info {
* @ready: Completion synchronization data.
* @usage_id: Usage id for physical device, e.g. gyro usage id.
* @attr_usage_id: Usage Id of a field, e.g. X-axis for a gyro.
- * @raw_size: Response size for a read request.
+ * @raw_size: Response size or negative error for a read request.
* @raw_data: Place holder for received response.
* @index: Current write index into raw_data for multi-byte reads.
* @max_raw_size: Total buffer size for multi-byte reads; 0 for single-value reads.
--
2.39.5