Linux IIO development
 help / color / mirror / Atom feed
* [BUG] hid-sensor-trigger: poll_value sign unchecked before msleep_interruptible causes ~49.7 day sleep
@ 2026-07-01  2:40 กิตติศักดิ์ บุญมาปะ
  2026-07-01  7:28 ` Joshua Crofts
  0 siblings, 1 reply; 3+ messages in thread
From: กิตติศักดิ์ บุญมาปะ @ 2026-07-01  2:40 UTC (permalink / raw)
  To: linux-iio; +Cc: jic23

KERNEL BUG REPORT
=================
Component : drivers/iio/common/hid-sensors/hid-sensor-trigger.c
Subsystem : IIO / HID Sensor
Severity  : High (device permanently unusable until service restart)
Kernel    : confirmed on 6.17.x; code path present in mainline as of 2025-06

Summary
-------
_hid_sensor_power_state() passes the return value of
hid_sensor_read_poll_value() directly to msleep_interruptible()
without checking for a negative (error) return. When the HID
descriptor does not contain a Report Interval feature field the
function returns -EINVAL (-22). This value is implicitly converted
to unsigned int before being multiplied by 2 and passed to
msleep_interruptible(), producing a sleep duration of
~4,294,967,252 ms (~49.7 days). The process enters
TASK_INTERRUPTIBLE state and appears permanently hung to the user.


Affected Code
-------------
drivers/iio/common/hid-sensors/hid-sensor-trigger.c:

  static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
  {
      ...
      s32 poll_value = 0;
      ...
      poll_value = hid_sensor_read_poll_value(st);   // can return -EINVAL
      ...
      if (state && poll_value)                        // BUG: -22
passes this check
          msleep_interruptible(poll_value * 2);       // -22 * 2 cast
to uint = ~4.29e9 ms
      ...
  }

hid_sensor_read_poll_value() (hid-sensor-attributes.c):

  s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
  {
      s32 value = 0;
      int ret;

      ret = sensor_hub_get_feature(st->hsdev,
                                   st->poll.report_id,   // 0xffffffff
if not found
                                   st->poll.index, sizeof(value), &value);

      if (ret < 0 || value < 0) {
          return -EINVAL;    // returned when Report Interval not in descriptor
      }
      ...
      return value;
  }


Reproduction
------------
Hardware : Seeed XIAO nRF52840 Sense (LSM6DS3 IMU) via USB HID
           VID:PID 2886:8045
OS       : Bazzite (Fedora immutable), kernel 6.17.x
Drivers  : hid-sensor-hub, hid-sensor-accel-3d, iio-sensor-proxy

The device implements a USB HID Sensor (Usage Page 0x20,
Accelerometer 3D, usage 0x200073) with Power State (0x200319),
Report State (0x200316) feature fields — sufficient for probe to
succeed — but without Report Interval (0x20030E).

Steps:
1. Plug the device.
2. Allow iio-sensor-proxy to start and attempt the first read.
3. Observe: iio-sensor-proxy main thread enters D/S state and
   never returns. 'cat in_accel_x_raw' also hangs indefinitely.
4. systemctl restart iio-sensor-proxy unblocks all hung processes
   (SIGTERM interrupts the interruptible sleep).

Kernel stack trace (captured via /proc/<pid>/task/*/stack while
process was hung — iio-sensor-proxy PID 1011, kernel 6.17.x):

  [<0>] msleep_interruptible+0x3b/0x90
  [<0>] _hid_sensor_power_state+0x166/0x1e0 [hid_sensor_trigger]
  [<0>] __rpm_callback+0x48/0x1f0
  [<0>] rpm_callback+0x6d/0x80
  [<0>] rpm_resume+0x4af/0x6d0
  [<0>] __pm_runtime_resume+0x52/0x90
  [<0>] hid_sensor_power_state+0x51/0xe0 [hid_sensor_trigger]
  [<0>] accel_3d_read_raw+0xa8/0x210 [hid_sensor_accel_3d]
  [<0>] iio_read_channel_info+0xed/0x110 [industrialio]
  [<0>] dev_attr_show+0x1f/0x50
  [<0>] sysfs_kf_seq_show+0xcc/0x120
  [<0>] seq_read_iter+0x128/0x480
  [<0>] vfs_read+0x268/0x390
  [<0>] ksys_read+0x73/0xf0
  [<0>] do_syscall_64+0x7e/0x250
  [<0>] entry_SYSCALL_64_after_hwframe+0x76/0x7e

Note: the process is in TASK_INTERRUPTIBLE (wchan=msleep_interruptible,
STAT=S), not TASK_UNINTERRUPTIBLE — it responds to signals. This is
why a service restart (SIGTERM) unblocks it, and why it is easy to
mistake for a runtime PM deadlock rather than an unchecked sleep duration.


Proposed Fix
------------
drivers/iio/common/hid-sensors/hid-sensor-trigger.c:

  --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
  +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
  @@ -143,7 +143,7 @@ static int _hid_sensor_power_state(...)
          poll_value = hid_sensor_read_poll_value(st);
       }
  -    if (state && poll_value)
  +    if (state && poll_value > 0)
           msleep_interruptible(poll_value * 2);

The single-character change (> 0 instead of truthiness check) ensures
that error returns (-EINVAL = -22) and the value 0 are both treated as
"no sleep", which is the correct behaviour when the Report Interval
attribute is absent or unreadable.

Alternatively, hid_sensor_read_poll_value() could be changed to return
0 instead of -EINVAL for the "not found" case, since the caller at this
site treats 0 as "skip the sleep" already. Either fix is sufficient;
fixing the call site is safer as it makes the intent explicit.


Workaround (user-space)
-----------------------
Add the Report Interval feature field (usage 0x20030E, unit Millisecond
0x65 0x19) to the HID report descriptor and return a positive default
value (e.g. 50 ms) from GET_REPORT. This makes hid_sensor_read_poll_value()
return 50 instead of -EINVAL, so msleep_interruptible(100) runs instead
of ~4.29e9 ms.

This workaround confirms the root cause: once the descriptor includes
Report Interval, the hang disappears completely across cold boot,
suspend/resume, and USB re-enumeration cycles.


Additional Notes
----------------
- The bug is latent in all HID sensor drivers that share
  hid-sensor-trigger.c (_hid_sensor_power_state is generic, used by
  gyroscope, magnetometer, pressure, light, etc.) — any HID sensor
  device that omits Report Interval from its descriptor will trigger
  the same hang.

- The dmesg warning "No report with id 0xffffffff found" (from
  sensor_hub_report() in hid-sensor-hub.c) is a reliable signal that
  a descriptor is missing expected feature fields. In this case it
  appeared 3 times per boot for Report Interval, Sensitivity ABS, and
  Sensitivity REL PCT. The Report Interval warning is the one with
  functional impact.

- Tested fix on: Bazzite OS (Fedora immutable), kernel 6.17.x,
  Steam Deck LCD (AMD Van Gogh SoC), iio-sensor-proxy 0.4.x,
  GNOME 46, with USB HID Sensor device (Seeed XIAO nRF52840 Sense).

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [BUG] hid-sensor-trigger: poll_value sign unchecked before msleep_interruptible causes ~49.7 day sleep
  2026-07-01  2:40 [BUG] hid-sensor-trigger: poll_value sign unchecked before msleep_interruptible causes ~49.7 day sleep กิตติศักดิ์ บุญมาปะ
@ 2026-07-01  7:28 ` Joshua Crofts
  2026-07-01 17:43   ` Jonathan Cameron
  0 siblings, 1 reply; 3+ messages in thread
From: Joshua Crofts @ 2026-07-01  7:28 UTC (permalink / raw)
  To: กิตติศักดิ์ บุญมาปะ
  Cc: linux-iio, jic23

On Wed, 1 Jul 2026 09:40:54 +0700
กิตติศักดิ์ บุญมาปะ <goorock.goopop@gmail.com> wrote:

> KERNEL BUG REPORT
> =================
> Component : drivers/iio/common/hid-sensors/hid-sensor-trigger.c
> Subsystem : IIO / HID Sensor
> Severity  : High (device permanently unusable until service restart)
> Kernel    : confirmed on 6.17.x; code path present in mainline as of 2025-06
> 
> Summary
> -------
> _hid_sensor_power_state() passes the return value of
> hid_sensor_read_poll_value() directly to msleep_interruptible()
> without checking for a negative (error) return. When the HID
> descriptor does not contain a Report Interval feature field the
> function returns -EINVAL (-22). This value is implicitly converted
> to unsigned int before being multiplied by 2 and passed to
> msleep_interruptible(), producing a sleep duration of
> ~4,294,967,252 ms (~49.7 days). The process enters
> TASK_INTERRUPTIBLE state and appears permanently hung to the user.
> 
> 
> Affected Code
> -------------
> drivers/iio/common/hid-sensors/hid-sensor-trigger.c:
> 
>   static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
>   {
>       ...
>       s32 poll_value = 0;
>       ...
>       poll_value = hid_sensor_read_poll_value(st);   // can return -EINVAL
>       ...
>       if (state && poll_value)                        // BUG: -22
> passes this check
>           msleep_interruptible(poll_value * 2);       // -22 * 2 cast
> to uint = ~4.29e9 ms
>       ...
>   }
> 
> hid_sensor_read_poll_value() (hid-sensor-attributes.c):
> 
>   s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
>   {
>       s32 value = 0;
>       int ret;
> 
>       ret = sensor_hub_get_feature(st->hsdev,
>                                    st->poll.report_id,   // 0xffffffff
> if not found
>                                    st->poll.index, sizeof(value), &value);
> 
>       if (ret < 0 || value < 0) {
>           return -EINVAL;    // returned when Report Interval not in descriptor
>       }
>       ...
>       return value;
>   }
> 
> 
> Reproduction
> ------------
> Hardware : Seeed XIAO nRF52840 Sense (LSM6DS3 IMU) via USB HID
>            VID:PID 2886:8045
> OS       : Bazzite (Fedora immutable), kernel 6.17.x
> Drivers  : hid-sensor-hub, hid-sensor-accel-3d, iio-sensor-proxy
> 
> The device implements a USB HID Sensor (Usage Page 0x20,
> Accelerometer 3D, usage 0x200073) with Power State (0x200319),
> Report State (0x200316) feature fields — sufficient for probe to
> succeed — but without Report Interval (0x20030E).
> 
> Steps:
> 1. Plug the device.
> 2. Allow iio-sensor-proxy to start and attempt the first read.
> 3. Observe: iio-sensor-proxy main thread enters D/S state and
>    never returns. 'cat in_accel_x_raw' also hangs indefinitely.
> 4. systemctl restart iio-sensor-proxy unblocks all hung processes
>    (SIGTERM interrupts the interruptible sleep).
> 
> Kernel stack trace (captured via /proc/<pid>/task/*/stack while
> process was hung — iio-sensor-proxy PID 1011, kernel 6.17.x):
> 
>   [<0>] msleep_interruptible+0x3b/0x90
>   [<0>] _hid_sensor_power_state+0x166/0x1e0 [hid_sensor_trigger]
>   [<0>] __rpm_callback+0x48/0x1f0
>   [<0>] rpm_callback+0x6d/0x80
>   [<0>] rpm_resume+0x4af/0x6d0
>   [<0>] __pm_runtime_resume+0x52/0x90
>   [<0>] hid_sensor_power_state+0x51/0xe0 [hid_sensor_trigger]
>   [<0>] accel_3d_read_raw+0xa8/0x210 [hid_sensor_accel_3d]
>   [<0>] iio_read_channel_info+0xed/0x110 [industrialio]
>   [<0>] dev_attr_show+0x1f/0x50
>   [<0>] sysfs_kf_seq_show+0xcc/0x120
>   [<0>] seq_read_iter+0x128/0x480
>   [<0>] vfs_read+0x268/0x390
>   [<0>] ksys_read+0x73/0xf0
>   [<0>] do_syscall_64+0x7e/0x250
>   [<0>] entry_SYSCALL_64_after_hwframe+0x76/0x7e
> 
> Note: the process is in TASK_INTERRUPTIBLE (wchan=msleep_interruptible,
> STAT=S), not TASK_UNINTERRUPTIBLE — it responds to signals. This is
> why a service restart (SIGTERM) unblocks it, and why it is easy to
> mistake for a runtime PM deadlock rather than an unchecked sleep duration.
> 
> 
> Proposed Fix
> ------------
> drivers/iio/common/hid-sensors/hid-sensor-trigger.c:
> 
>   --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
>   +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
>   @@ -143,7 +143,7 @@ static int _hid_sensor_power_state(...)
>           poll_value = hid_sensor_read_poll_value(st);
>        }
>   -    if (state && poll_value)
>   +    if (state && poll_value > 0)
>            msleep_interruptible(poll_value * 2);
> 

Yes, this is something that should be fixed. Can you send a patch?

-- 
Kind regards

CJD

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [BUG] hid-sensor-trigger: poll_value sign unchecked before msleep_interruptible causes ~49.7 day sleep
  2026-07-01  7:28 ` Joshua Crofts
@ 2026-07-01 17:43   ` Jonathan Cameron
  0 siblings, 0 replies; 3+ messages in thread
From: Jonathan Cameron @ 2026-07-01 17:43 UTC (permalink / raw)
  To: Joshua Crofts
  Cc: กิตติศักดิ์ บุญมาปะ,
	linux-iio

On Wed, 1 Jul 2026 09:28:24 +0200
Joshua Crofts <joshua.crofts1@gmail.com> wrote:

> On Wed, 1 Jul 2026 09:40:54 +0700
> กิตติศักดิ์ บุญมาปะ <goorock.goopop@gmail.com> wrote:
> 
> > KERNEL BUG REPORT
> > =================
> > Component : drivers/iio/common/hid-sensors/hid-sensor-trigger.c
> > Subsystem : IIO / HID Sensor
> > Severity  : High (device permanently unusable until service restart)
> > Kernel    : confirmed on 6.17.x; code path present in mainline as of 2025-06
> > 
> > Summary
> > -------
> > _hid_sensor_power_state() passes the return value of
> > hid_sensor_read_poll_value() directly to msleep_interruptible()
> > without checking for a negative (error) return. When the HID
> > descriptor does not contain a Report Interval feature field the
> > function returns -EINVAL (-22). This value is implicitly converted
> > to unsigned int before being multiplied by 2 and passed to
> > msleep_interruptible(), producing a sleep duration of
> > ~4,294,967,252 ms (~49.7 days). The process enters
> > TASK_INTERRUPTIBLE state and appears permanently hung to the user.
> > 
> > 
> > Affected Code
> > -------------
> > drivers/iio/common/hid-sensors/hid-sensor-trigger.c:
> > 
> >   static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
> >   {
> >       ...
> >       s32 poll_value = 0;
> >       ...
> >       poll_value = hid_sensor_read_poll_value(st);   // can return -EINVAL
> >       ...
> >       if (state && poll_value)                        // BUG: -22
> > passes this check
> >           msleep_interruptible(poll_value * 2);       // -22 * 2 cast
> > to uint = ~4.29e9 ms
> >       ...
> >   }
> > 
> > hid_sensor_read_poll_value() (hid-sensor-attributes.c):
> > 
> >   s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
> >   {
> >       s32 value = 0;
> >       int ret;
> > 
> >       ret = sensor_hub_get_feature(st->hsdev,
> >                                    st->poll.report_id,   // 0xffffffff
> > if not found
> >                                    st->poll.index, sizeof(value), &value);
> > 
> >       if (ret < 0 || value < 0) {
> >           return -EINVAL;    // returned when Report Interval not in descriptor
> >       }
> >       ...
> >       return value;
> >   }
> > 
> > 
> > Reproduction
> > ------------
> > Hardware : Seeed XIAO nRF52840 Sense (LSM6DS3 IMU) via USB HID
> >            VID:PID 2886:8045
> > OS       : Bazzite (Fedora immutable), kernel 6.17.x
> > Drivers  : hid-sensor-hub, hid-sensor-accel-3d, iio-sensor-proxy
> > 
> > The device implements a USB HID Sensor (Usage Page 0x20,
> > Accelerometer 3D, usage 0x200073) with Power State (0x200319),
> > Report State (0x200316) feature fields — sufficient for probe to
> > succeed — but without Report Interval (0x20030E).
> > 
> > Steps:
> > 1. Plug the device.
> > 2. Allow iio-sensor-proxy to start and attempt the first read.
> > 3. Observe: iio-sensor-proxy main thread enters D/S state and
> >    never returns. 'cat in_accel_x_raw' also hangs indefinitely.
> > 4. systemctl restart iio-sensor-proxy unblocks all hung processes
> >    (SIGTERM interrupts the interruptible sleep).
> > 
> > Kernel stack trace (captured via /proc/<pid>/task/*/stack while
> > process was hung — iio-sensor-proxy PID 1011, kernel 6.17.x):
> > 
> >   [<0>] msleep_interruptible+0x3b/0x90
> >   [<0>] _hid_sensor_power_state+0x166/0x1e0 [hid_sensor_trigger]
> >   [<0>] __rpm_callback+0x48/0x1f0
> >   [<0>] rpm_callback+0x6d/0x80
> >   [<0>] rpm_resume+0x4af/0x6d0
> >   [<0>] __pm_runtime_resume+0x52/0x90
> >   [<0>] hid_sensor_power_state+0x51/0xe0 [hid_sensor_trigger]
> >   [<0>] accel_3d_read_raw+0xa8/0x210 [hid_sensor_accel_3d]
> >   [<0>] iio_read_channel_info+0xed/0x110 [industrialio]
> >   [<0>] dev_attr_show+0x1f/0x50
> >   [<0>] sysfs_kf_seq_show+0xcc/0x120
> >   [<0>] seq_read_iter+0x128/0x480
> >   [<0>] vfs_read+0x268/0x390
> >   [<0>] ksys_read+0x73/0xf0
> >   [<0>] do_syscall_64+0x7e/0x250
> >   [<0>] entry_SYSCALL_64_after_hwframe+0x76/0x7e
> > 
> > Note: the process is in TASK_INTERRUPTIBLE (wchan=msleep_interruptible,
> > STAT=S), not TASK_UNINTERRUPTIBLE — it responds to signals. This is
> > why a service restart (SIGTERM) unblocks it, and why it is easy to
> > mistake for a runtime PM deadlock rather than an unchecked sleep duration.
> > 
> > 
> > Proposed Fix
> > ------------
> > drivers/iio/common/hid-sensors/hid-sensor-trigger.c:
> > 
> >   --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
> >   +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
> >   @@ -143,7 +143,7 @@ static int _hid_sensor_power_state(...)
> >           poll_value = hid_sensor_read_poll_value(st);
> >        }
> >   -    if (state && poll_value)
> >   +    if (state && poll_value > 0)
> >            msleep_interruptible(poll_value * 2);
> >   
> 
> Yes, this is something that should be fixed. Can you send a patch?

True to needing fixing, but not that fix.  Just check poll_value
at point of original assignment and error out if it is negative.

Jonathan

> 


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-07-01 17:43 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-01  2:40 [BUG] hid-sensor-trigger: poll_value sign unchecked before msleep_interruptible causes ~49.7 day sleep กิตติศักดิ์ บุญมาปะ
2026-07-01  7:28 ` Joshua Crofts
2026-07-01 17:43   ` Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox