Linux Input/HID development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Vicki Pfau" <vi@endrift.com>
Cc: linux-input@vger.kernel.org, dmitry.torokhov@gmail.com
Subject: Re: [PATCH v4 05/11] HID: steam: Add support for sensor events on the Steam Controller (2015)
Date: Wed, 29 Jul 2026 02:09:20 +0000	[thread overview]
Message-ID: <20260729020920.D28A51F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260729015243.1170573-6-vi@endrift.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

New issues:
- [Medium] Enabling lizard mode via gamepad closure implicitly disables the IMU, breaking active sensor listeners.

Pre-existing issues:
- [High] If `steam_register()` fails for a wired controller in `steam_probe()`, the `steam` device is freed while remaining linked in the global `steam_devices` list.
- [High] Concurrent execution of workqueues causes double unregistration of the input and sensors devices due to a TOCTOU race condition.
--

--- Patch [5]: [PATCH v4 05/11] HID: steam: Add support for sensor events on the Steam Controller (2015) ---
commit bb1476f66b80150be67610fe42e5546b316d06ef
Author: Vicki Pfau <vi@endrift.com>

HID: steam: Add support for sensor events on the Steam Controller (2015)

Sensor support was added for the Steam Deck previously, but Steam
Controller sensor events were never added. This adds that missing support,
bringing Steam Controller support much closer to feature parity with things
like SDL and Steam itself.

> diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
> index 8bad79205b570..cabecd250072e 100644
> --- a/drivers/hid/hid-steam.c
> +++ b/drivers/hid/hid-steam.c

[ ... ]

> @@ -625,6 +689,42 @@ static void steam_input_close(struct input_dev *dev)
>  	}
>  }
>  
> +static int steam_sensor_open(struct input_dev *dev)
> +{
> +	struct steam_device *steam = input_get_drvdata(dev);
> +	unsigned long flags;
> +	bool client_opened;
> +
> +	spin_lock_irqsave(&steam->lock, flags);
> +	client_opened = steam->client_opened;
> +	spin_unlock_irqrestore(&steam->lock, flags);
> +	if (client_opened)
> +		return 0;
> +
> +	guard(mutex)(&steam->report_mutex);
> +	steam_write_settings(steam, SETTING_IMU_MODE,
> +			SETTING_IMU_MODE_SEND_RAW_ACCEL | SETTING_IMU_MODE_SEND_RAW_GYRO,
> +			0);

[Severity: Medium]
Does closing the gamepad evdev node implicitly disable the IMU, breaking
active sensor listeners?

When the gamepad evdev node is closed, the driver automatically re-enables
"lizard mode" by calling steam_set_lizard_mode(steam, true) in
steam_input_close(). This function sends the ID_LOAD_DEFAULT_SETTINGS
command to the controller, which performs a hardware state reset.

This reset wipes out the SETTING_IMU_MODE configuration previously requested
by steam_sensor_open() here. Since the driver does not track or coordinate
the IMU state across these logically independent evdev nodes, closing the
gamepad node while the sensor node is still open will cause the controller
to silently stop sending motion data.

> +
> +	return 0;
> +}
> +
> +static void steam_sensor_close(struct input_dev *dev)
> +{

[ ... ]

> @@ -917,9 +1029,6 @@ static void steam_sensors_unregister(struct steam_device *steam)
>  {
>  	struct input_dev *sensors;
>  
> -	if (!(steam->quirks & STEAM_QUIRK_DECK))
> -		return;
> -
>  	rcu_read_lock();
>  	sensors = rcu_dereference(steam->sensors);
>  	rcu_read_unlock();

[Severity: High]
This isn't a bug introduced by this patch, but can concurrent execution of
workqueues cause a double unregistration of the input and sensors devices
due to a TOCTOU race condition?

The workqueues work_connect and unregister_work cache the device state under
a spinlock, drop the lock, and then act on the cached state. Both can run
concurrently on different CPUs and call steam_sensors_unregister() or
steam_input_unregister() simultaneously.

In both unregister functions, the pointers (steam->sensors and steam->input)
are read under rcu_read_lock(), but the lock is dropped immediately before
checking if the pointer is NULL. Because there is no atomic swap or mutex
protecting the RCU_INIT_POINTER assignment, both threads can read the same
non-NULL pointer, wait for RCU, and call input_unregister_device() on the
same device, causing a double-free and list corruption in the input core.

> @@ -967,6 +1076,12 @@ static int steam_register(struct steam_device *steam)
>  			strscpy(steam->serial_no, "XXXXXXXXXX",
>  					sizeof(steam->serial_no));
>  
> +		ret = steam_get_attributes(steam);
> +		if (ret < 0)
> +			hid_err(steam->hdev,
> +				"%s:steam_get_attributes failed with error %d\n",
> +				__func__, ret);
> +

[Severity: High]
This is a pre-existing issue, but if steam_register() fails for a wired
controller in steam_probe(), is the steam device freed while remaining
linked in the global steam_devices list?

In steam_register(), the steam object is added to the global steam_devices
list under a lock. If registration subsequently fails (e.g., due to an
out-of-memory error in steam_input_register()), steam_register() returns an
error code without removing the object from the list.

For a wired controller, steam_probe() catches this error and jumps to
err_hw_close, bypassing err_steam_unregister and the steam_unregister()
function that would normally remove it from the list. When steam_probe()
returns the error, devres frees the steam object.

Any subsequent iteration over steam_devices (e.g., changing lizard mode via
sysfs) will dereference the freed memory, causing a use-after-free and
potential kernel panic.

>  		hid_info(steam->hdev, "Steam Controller '%s' connected",
>  				steam->serial_no);
>

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260729015243.1170573-1-vi@endrift.com?part=5

  reply	other threads:[~2026-07-29  2:09 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-29  1:52 [PATCH v4 00/10] HID: steam: General cleanup and improvements Vicki Pfau
2026-07-29  1:52 ` [PATCH v4 01/11] HID: steam: Update documentation Vicki Pfau
2026-07-29  1:52 ` [PATCH v4 02/11] HID: steam: Refactor and clean up report parsing Vicki Pfau
2026-07-29  1:52 ` [PATCH v4 03/11] HID: steam: Rename some constants that got renamed upstream Vicki Pfau
2026-07-29  1:52 ` [PATCH v4 04/11] HID: steam: Zero-initialize reply in serial lookup Vicki Pfau
2026-07-29  2:10   ` sashiko-bot
2026-07-29  1:52 ` [PATCH v4 05/11] HID: steam: Add support for sensor events on the Steam Controller (2015) Vicki Pfau
2026-07-29  2:09   ` sashiko-bot [this message]
2026-07-29  1:52 ` [PATCH v4 06/11] HID: steam: Coalesce rumble packets Vicki Pfau
2026-07-29  2:13   ` sashiko-bot
2026-07-29  1:52 ` [PATCH v4 07/11] HID: steam: Fully unregister controller when hidraw is opened Vicki Pfau
2026-07-29  2:12   ` sashiko-bot
2026-07-29  1:52 ` [PATCH v4 08/11] HID: steam: Rearrange teardown sequence Vicki Pfau
2026-07-29  2:15   ` sashiko-bot
2026-07-29  1:52 ` [PATCH v4 09/11] HID: steam: Improve logging and other cleanup Vicki Pfau
2026-07-29  2:11   ` sashiko-bot
2026-07-29  1:52 ` [PATCH v4 10/11] HID: steam: Reject short reads Vicki Pfau
2026-07-29  1:52 ` [PATCH v4 11/11] HID: steam: Retry send/recv reports if stale Vicki Pfau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260729020920.D28A51F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dmitry.torokhov@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=vi@endrift.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox