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 08/11] HID: steam: Rearrange teardown sequence
Date: Wed, 29 Jul 2026 02:15:32 +0000 [thread overview]
Message-ID: <20260729021533.370011F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260729015243.1170573-9-vi@endrift.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [High] Calling `hid_hw_start()` before initializing driver data structures exposes the device to events early, leading to crashes from uninitialized locks and work_structs.
- [High] The modified error path in `steam_probe()` skips the cancellation of `work_connect` and `mode_switch`, leaving them dangling on probe failure.
Pre-existing issues:
- [High] Teardown ordering in `steam_remove()` allows `work_connect` to be re-scheduled by raw events after it has been explicitly cancelled.
- [High] `steam->client_hdev` is destroyed before the `client_opened` flag is cleared, allowing asynchronous events to dereference the freed device.
- [High] If `steam_register()` fails during initialization, the `steam` object is freed but remains linked in the global `steam_devices` list.
--
--- Patch [8]: [PATCH v4 08/11] HID: steam: Rearrange teardown sequence ---
commit 4778053b21e62ca367e7570ac85b4132006adade
Author: Vicki Pfau <vi@endrift.com>
HID: steam: Rearrange teardown sequence
This fixes a narrow window during the teardown sequence where callbacks
could still be scheduled during cleanup that would then have a dangling
pointer to the now-freed steam struct. This also puts work canceling
for rumble and mode switch in steam_unregister, as that shouldn't persist
while the client hdev is open.
> diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
> index ff112aa1b0e91..5ab4396a241e0 100644
> --- a/drivers/hid/hid-steam.c
> +++ b/drivers/hid/hid-steam.c
[ ... ]
> @@ -1352,6 +1356,14 @@ static int steam_probe(struct hid_device *hdev,
> if (!steam)
> return -ENOMEM;
>
> + /*
> + * With the real steam controller interface, do not connect hidraw.
> + * Instead, create the client_hid and connect that.
> + */
> + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDRAW);
> + if (ret)
> + return ret;
> +
> steam->hdev = hdev;
> hid_set_drvdata(hdev, steam);
> spin_lock_init(&steam->lock);
[Severity: High]
Does calling hid_hw_start() before initializing driver data structures expose
the device to events early?
Moving hid_hw_start() here makes the input devices visible to userspace.
If a userspace process opens the input node, hid_hw_open() is called, starting
URB polling. An incoming hardware interrupt can then invoke steam_raw_event().
Because hid_set_drvdata() is called right after hid_hw_start(),
steam_raw_event() could access the non-NULL steam pointer and call
steam_do_connect_event(), which might attempt to acquire the uninitialized
spinlock and schedule the uninitialized work_connect, potentially leading to
a crash.
[ ... ]
> @@ -1397,14 +1393,22 @@ static int steam_probe(struct hid_device *hdev,
> hid_err(hdev,
> "%s:steam_register failed with error %d\n",
> __func__, ret);
> - goto err_hw_close;
> + goto err_hw_stop;
[Severity: High]
This is a pre-existing issue, but if steam_register() fails during
initialization, does the steam object remain linked in the global
steam_devices list after being freed?
During steam_register(), the device is added to the global steam_devices list.
If a subsequent step like steam_input_register() fails, the function returns
an error without removing the device from the list.
When this failure jumps to err_hw_stop in steam_probe(), it bypasses
steam_unregister(), which is responsible for removing it from the list.
If devres then frees the object, could a dangling pointer be left in the
global list?
[ ... ]
> err_destroy:
> hid_destroy_device(steam->client_hdev);
> -err_steam_unregister:
> - if (steam->connected)
> - steam_unregister(steam);
> err_hw_close:
> hid_hw_close(hdev);
> -err_hw_stop:
> - hid_hw_stop(hdev);
> -err_cancel_work:
> +err_steam_unregister:
> + spin_lock_irqsave(&steam->lock, flags);
> + steam->client_opened = 0;
> + spin_unlock_irqrestore(&steam->lock, flags);
> cancel_work_sync(&steam->work_connect);
> + if (steam->connected)
> + steam_unregister(steam);
> cancel_delayed_work_sync(&steam->mode_switch);
> +err_hw_stop:
[Severity: High]
Does the modified error path in steam_probe() skip the cancellation of
work_connect and mode_switch when a probe failure jumps to err_hw_stop?
Because hid_hw_start() was moved earlier in the probe, raw events might already
queue work_connect. If the probe fails and jumps directly to err_hw_stop,
bypassing err_steam_unregister, could it leave these work items dangling when
devres frees the steam object?
> cancel_work_sync(&steam->rumble_work);
> cancel_delayed_work_sync(&steam->coalesce_rumble_work);
> + hid_hw_stop(hdev);
>
> return ret;
> }
> @@ -1435,25 +1441,24 @@ static int steam_probe(struct hid_device *hdev,
> static void steam_remove(struct hid_device *hdev)
> {
> struct steam_device *steam = hid_get_drvdata(hdev);
> + unsigned long flags;
>
> if (!steam || hdev->group == HID_GROUP_STEAM) {
> hid_hw_stop(hdev);
> return;
> }
>
> + hid_hw_close(hdev);
> hid_destroy_device(steam->client_hdev);
> - cancel_delayed_work_sync(&steam->mode_switch);
> - cancel_work_sync(&steam->work_connect);
> - cancel_work_sync(&steam->rumble_work);
> - cancel_delayed_work_sync(&steam->coalesce_rumble_work);
> - steam->client_hdev = NULL;
> + spin_lock_irqsave(&steam->lock, flags);
> steam->client_opened = 0;
> + spin_unlock_irqrestore(&steam->lock, flags);
[Severity: High]
This is a pre-existing issue, but is steam->client_hdev destroyed before
the client_opened flag is cleared?
Because steam_raw_event() runs in softirq context without taking a lock around
the client_opened check, there could be a race condition.
If an interrupt sees client_opened > 0 right before hid_destroy_device()
completes, could it pass the freed client_hdev pointer to hid_input_report()?
> + cancel_work_sync(&steam->work_connect);
> if (steam->quirks & STEAM_QUIRK_WIRELESS) {
> hid_info(hdev, "Steam wireless receiver disconnected");
> }
> - hid_hw_close(hdev);
> - hid_hw_stop(hdev);
> steam_unregister(steam);
> + hid_hw_stop(hdev);
[Severity: High]
This is a pre-existing issue, but does the teardown ordering in steam_remove()
allow work_connect to be re-scheduled by raw events after it has been explicitly
cancelled?
cancel_work_sync(&steam->work_connect) is called above, but URB polling is only
guaranteed to stop at the end of the function when hid_hw_stop() is called.
If a hardware event arrives after the cancellation but before hid_hw_stop(),
could it re-queue work_connect via steam_raw_event(), leaving the work pending
after the driver finishes removal and frees the device?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260729015243.1170573-1-vi@endrift.com?part=8
next prev parent reply other threads:[~2026-07-29 2:15 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
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 [this message]
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=20260729021533.370011F000E9@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