[PATCH v2] HID: hid-oxp: fix UAF on pending work in remove()

"Shengzhuo Wei" <[email protected]>
Newsgroups gmane.linux.kernel.input,gmane.linux.kernel,gmane.linux.kernel.stable
Message-ID <[email protected]>
oxp_cfg_probe() arms drvdata.oxp_mcu_init to run 50 ms after probe, and
oxp_mcu_init_fn() dereferences drvdata.hdev to issue MCU output reports
(hid_hw_output_report() followed by msleep(200)). The oxp_rgb_queue and
oxp_btn_queue workers are wired up the same way. oxp_hid_remove()
cancels all three with the non-synchronising cancel_delayed_work(), so a
worker already running is not waited for; removing the device while a
worker is asleep then frees the hid_device underneath it, leaving
drvdata.hdev stale -- a use-after-free when the worker wakes.

Use disable_delayed_work_sync() for all three in oxp_hid_remove(): it
drains a running worker and, unlike cancel_delayed_work_sync(), leaves
the works disabled so they cannot be re-armed by oxp_hid_raw_event_gen_2()
or oxp_rgb_brightness_set() while the device is torn down. Arm
oxp_mcu_init only after devm_device_add_group() succeeds in
oxp_cfg_probe(), so a probe failure can no longer leave it pending to
fire on the hid_device the caller tears down.

Fixes: 84910c459d65 ("HID: hid-oxp: Add OneXPlayer configuration driver")
Fixes: e4c850a6e750 ("HID: hid-oxp: Add Button Mapping Interface")
Fixes: 2f424f28fb39 ("HID: hid-oxp: Add Second Generation Gamepad Mode Switch")
Cc: [email protected]
Signed-off-by: Shengzhuo Wei <[email protected]>
---
Same delayed-work use-after-free class as the 7.2-rc6 sweep
(hid-lenovo-go, hid-lenovo-go-s, hid-lg-g15, hid-appleir, hid-letsketch);
hid-oxp was missed.
---
Changes in v2:
- Use disable_delayed_work_sync() instead of cancel_delayed_work_sync()
  so the works cannot be re-armed (e.g. via oxp_rgb_brightness_set())
  while the device is being torn down (Dmitry Torokhov).
- Arm oxp_mcu_init only after devm_device_add_group() succeeds, so a
  probe failure can no longer leave it pending to fire on a freed
  hid device (sashiko).
- Link to v1: https://lore.kernel.org/r/[email protected]
---
 drivers/hid/hid-oxp.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/hid/hid-oxp.c b/drivers/hid/hid-oxp.c
index 20a54f337220dc2aee3483a14d542b66c487bd60..abd622ff1b26b312ad9c8a4375822832f8371533 100644
--- a/drivers/hid/hid-oxp.c
+++ b/drivers/hid/hid-oxp.c
@@ -1501,14 +1501,14 @@ static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
 	drvdata.gamepad_mode = OXP_GP_MODE_XINPUT;
 	drvdata.rumble_intensity = 5;
 
-	INIT_DELAYED_WORK(&drvdata.oxp_mcu_init, oxp_mcu_init_fn);
-	mod_delayed_work(system_wq, &drvdata.oxp_mcu_init, msecs_to_jiffies(50));
-
 	ret = devm_device_add_group(&hdev->dev, &oxp_cfg_attrs_group);
 	if (ret)
 		return dev_err_probe(&hdev->dev, ret,
 				     "Failed to attach configuration attributes\n");
 
+	INIT_DELAYED_WORK(&drvdata.oxp_mcu_init, oxp_mcu_init_fn);
+	mod_delayed_work(system_wq, &drvdata.oxp_mcu_init, msecs_to_jiffies(50));
+
 	return 0;
 }
 
@@ -1552,9 +1552,9 @@ static int oxp_hid_probe(struct hid_device *hdev,
 
 static void oxp_hid_remove(struct hid_device *hdev)
 {
-	cancel_delayed_work(&drvdata.oxp_rgb_queue);
-	cancel_delayed_work(&drvdata.oxp_btn_queue);
-	cancel_delayed_work(&drvdata.oxp_mcu_init);
+	disable_delayed_work_sync(&drvdata.oxp_rgb_queue);
+	disable_delayed_work_sync(&drvdata.oxp_btn_queue);
+	disable_delayed_work_sync(&drvdata.oxp_mcu_init);
 	hid_hw_close(hdev);
 	hid_hw_stop(hdev);
 }

---
base-commit: 075b74841bd0065a3bda3440873c747938e69b68
change-id: 20260804-oxp-fix-879390c5e47f

Best regards,
-- 
Shengzhuo Wei <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.