Re: [PATCH v3 2/6] HID: steam: Initial 2026 Steam Controller support
[email protected] Fri, 07 Aug 2026 02:07:05 +0000
| Newsgroups | org.kernel.vger.linux-input |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: Pre-existing issues: - [High] Concurrent execution of `steam_register` between `steam_probe` and `steam_work_connect_cb` leads to data races, double registration, memory leaks, and Use-After-Free (UAF). - [High] Teardown ordering in `steam_remove` incorrectly cancels works before stopping hardware events, leading to Use-After-Free. -- --- Patch [2]: [PATCH v3 2/6] HID: steam: Initial 2026 Steam Controller support --- commit d704660582137e2d95967bceb5a602df38e73e5e Author: Vicki Pfau <[email protected]> Subject: HID: steam: Initial 2026 Steam Controller support This commit brings support for the 2026 Steam Controller, adding new capabilities comparable to the Steam Deck. It also includes cleanup of the registration flow to make it cleaner and avoid potential pitfalls. > diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c > index 967f12c7a599a..ec7ccbe5aba09 100644 > --- a/drivers/hid/hid-steam.c > +++ b/drivers/hid/hid-steam.c [ ... ] > @@ -1139,61 +1371,49 @@ static void steam_battery_unregister(struct steam_device *steam) > static int steam_register(struct steam_device *steam) > { > int ret; > - unsigned long client_opened; > - unsigned long flags; > - bool do_add; > > /* > * This function can be called several times in a row with the > * wireless adaptor, without steam_unregister() between them, because > * another client send a get_connection_status command, for example. > - * The battery and serial number are set just once per device. > */ > - if (!steam->serial_no[0]) { > - /* > - * Unlikely, but getting the serial could fail, and it is not so > - * important, so make up a serial number and go on. > - */ > - if (steam_get_serial(steam) < 0) > - 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); > + if (steam->registered) > + return 0; [Severity: High] This is a pre-existing issue, but does this lockless check allow concurrent registration? When hid_hw_open() is called in steam_probe(), the hardware can immediately generate a wireless connect event. This triggers steam_do_connect_event(), which schedules steam_work_connect_cb() to run on a workqueue concurrently with the remainder of steam_probe(). Both threads call steam_register(), which performs a lockless check of this registration state. Both threads can see it as false and concurrently execute the registration sequence. This results in multiple concurrency bugs: steam_battery_register() concurrently allocates and frees steam->battery_desc.name using devm_kasprintf()/devm_kfree(), causing the power supply subsystem to access freed memory (UAF). Additionally, input_allocate_device() is called twice with the first pointer leaked via RCU pointer overwrite. Does this need a lock around the registration check to prevent double registration and memory corruption? [ ... ] > @@ -1219,7 +1440,6 @@ static void steam_unregister(struct steam_device *steam) > mutex_lock(&steam_devices_lock); > list_del_init(&steam->list); > mutex_unlock(&steam_devices_lock); > - steam->serial_no[0] = 0; > } [Severity: High] This is a pre-existing issue, but does the teardown ordering in steam_remove() incorrectly cancel works before stopping hardware events, leading to a UAF? During device removal, cancel_work_sync(&steam->work_connect) and steam_unregister() are called before hid_hw_stop(hdev): static void steam_remove(struct hid_device *hdev) { ... cancel_work_sync(&steam->work_connect); ... steam_unregister(steam); hid_hw_stop(hdev); } While hid_hw_close(hdev) is called earlier, it only drops the logical open count and does not reliably guarantee the immediate cessation of all incoming hardware events across all possible low-level transport drivers. Because hid_hw_stop() is the definitive function for stopping the underlying transport and killing pending events, an incoming interrupt can trigger steam_raw_event() in the window after the works are canceled but before the hardware is stopped. If a connect or disconnect event is received, steam_raw_event() calls steam_do_connect_event(), which queues steam->work_connect. After steam_remove() completes, devres frees the steam_device structure. When the newly scheduled work executes, it accesses the freed steam_device, resulting in a UAF memory corruption. Should hid_hw_stop() be called before canceling the workqueues? -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=2