Linux Input/HID development
 help / color / mirror / Atom feed
From: "Derek J. Clark" <derekjohn.clark@gmail.com>
To: sashiko-reviews@lists.linux.dev, sashiko-bot@kernel.org
Cc: linux-input@vger.kernel.org, dmitry.torokhov@gmail.com
Subject: Re: [PATCH v12 3/4] HID: hid-msi: Add RGB control interface
Date: Tue, 14 Jul 2026 20:43:51 +0900	[thread overview]
Message-ID: <426987CB-DA21-403D-903E-153D7BC81F3B@gmail.com> (raw)
In-Reply-To: <20260714104219.AEAE31F000E9@smtp.kernel.org>

On July 14, 2026 7:42:19 PM GMT+09:00, sashiko-bot@kernel.org wrote:
>Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
>- [High] The `rgb_queue` delayed work accesses a freed device pointer `led_cdev.dev` on its error path due to incorrect teardown order in `claw_remove`.
>- [High] Missing cancellation of `cfg_setup` and `cfg_resume` delayed works in `claw_remove()`.
>- [Medium] RGB configuration states and LED class properties are modified and read concurrently without proper synchronization.
>--
>
>--- Patch [3]: [PATCH v12 3/4] HID: hid-msi: Add RGB control interface ---
>commit 2d837d4907cf2b48e7866a46da8d35b754a9f9a6
>Author: Derek J. Clark <derekjohn.clark@gmail.com>
>
>HID: hid-msi: Add RGB control interface
>
>Adds RGB control interface for MSI Claw devices. The MSI Claw uses a
>fairly unique RGB interface. It has 9 total zones (4 per joystick ring
>and 1 for the ABXY buttons), and supports up to 8 sequential frames of
>RGB zone data.
>
>Link: https://patch.msgid.link/20260529072111.7565-4-derekjohn.clark@gmail.com
>
>> diff --git a/drivers/hid/hid-msi.c b/drivers/hid/hid-msi.c
>> index 9d3249fa50291..ddb64adb08b9c 100644
>> --- a/drivers/hid/hid-msi.c
>> +++ b/drivers/hid/hid-msi.c
>> @@ -406,6 +406,38 @@ static int claw_profile_event(struct claw_drvdata *drvdata, struct claw_command_
>>  		for (i = 0; i < CLAW_KEYS_MAX; i++)
>>  			codes[i] = (mkeys->codes[i]);
>>  		break;
>> +	case CLAW_RGB_PENDING:
>> +		frame = (struct claw_rgb_report *)cmd_rep->data;
>> +		rgb_addr = drvdata->rgb_addr;
>> +		read_addr = be16_to_cpu(frame->read_addr);
>> +
>> +		if (read_addr < drvdata->rgb_addr)
>> +			return -EAGAIN;
>> +
>> +		frame_calc = (read_addr - rgb_addr) / CLAW_RGB_FRAME_OFFSET;
>> +		if (frame_calc >= CLAW_RGB_MAX_FRAMES) {
>> +			dev_err(&drvdata->hdev->dev, "Got unsupported frame index: %x\n",
>> +				frame_calc);
>> +			return -EAGAIN;
>> +		}
>> +		f_idx = frame_calc;
>> +
>> +		scoped_guard(spinlock_irqsave, &drvdata->frame_lock) {
>> +			memcpy(&drvdata->rgb_frames[f_idx], &frame->zone_data,
>> +			       sizeof(struct rgb_frame));
>> +
>> +			/* Only use frame 0 for remaining variable assignment */
>> +			if (f_idx != 0)
>> +				break;
>> +
>> +			drvdata->rgb_speed = frame->speed;
>> +			drvdata->led_mc.led_cdev.brightness = frame->brightness;
>
>[Severity: Medium]
>Are there missing locks around rgb_speed and led_cdev.brightness?

Humans reading this dumb bot's reply,
No, they are under scoped_guard 9 lines above this...

>Here in claw_profile_event(), drvdata->rgb_speed and
>drvdata->led_mc.led_cdev.brightness are written to under the frame_lock.
>However, they appear to be read locklessly in claw_write_rgb_state() outside
>of frame_lock. Similarly, speed_store() modifies drvdata->rgb_speed locklessly
>from userspace.
>
>Could this inconsistent locking lead to torn reads or data races between
>sysfs operations, hardware events, and the workqueue?
>
>[ ... ]
>
>> +static void claw_rgb_queue_fn(struct work_struct *work)
>> +{
>> +	struct delayed_work *dwork = container_of(work, struct delayed_work, work);
>> +	struct claw_drvdata *drvdata = container_of(dwork, struct claw_drvdata, rgb_queue);
>> +	int ret;
>> +
>> +	if (!drvdata)
>> +		return;
>> +
>> +	scoped_guard(spinlock_irqsave, &drvdata->registration_lock) {
>> +		/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
>> +		if (!smp_load_acquire(&drvdata->rgb_registered))
>> +			return;
>> +	}
>> +
>> +	ret = claw_apply_rgb_state(drvdata);
>> +	if (ret)
>> +		dev_err(drvdata->led_mc.led_cdev.dev,
>> +			"Failed to apply RGB state: %d\n", ret);
>
>[Severity: High]
>Could this dev_err() access a freed device pointer?
>
>If claw_rgb_queue_fn() starts executing and passes the rgb_registered check,
>but the device is concurrently removed, claw_remove() will set rgb_registered
>to false and call led_classdev_multicolor_unregister(). This drops the final
>reference and frees led_cdev.dev.
>If claw_apply_rgb_state() subsequently fails, this error path will log using
>drvdata->led_mc.led_cdev.dev, which might trigger a use-after-free since the
>work was not canceled prior to unregistration.

Addressed below.

>
>[ ... ]
>
>> @@ -1084,6 +1721,7 @@ static void claw_remove(struct hid_device *hdev)
>>  {
>>  	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
>>  	bool gp_registered;
>> +	bool rgb_registered;
>>  
>>  	if (!drvdata)
>>  		return;
>> @@ -1096,11 +1734,21 @@ static void claw_remove(struct hid_device *hdev)
>>  		gp_registered = smp_load_acquire(&drvdata->gp_registered);
>>  		/* Pairs with smp_load_acquire in attribute show/store functions */
>>  		smp_store_release(&drvdata->gp_registered, false);
>> +		/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
>> +		rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
>> +		/* Pairs with smp_load_acquire in attribute show/store functions */
>> +		smp_store_release(&drvdata->rgb_registered, false);
>>  	}
>>  
>>  	if (gp_registered)
>>  		device_remove_group(&hdev->dev, &claw_gamepad_attr_group);
>>  
>> +	if (rgb_registered) {
>> +		device_remove_group(drvdata->led_mc.led_cdev.dev, &claw_rgb_attr_group);
>> +		led_classdev_multicolor_unregister(&drvdata->led_mc);
>> +	}
>> +	cancel_delayed_work_sync(&drvdata->rgb_queue);
>
>[Severity: High]
>Should cancel_delayed_work_sync() for rgb_queue happen before
>led_classdev_multicolor_unregister()?
>

This suggestion will just reintroduce the bug the reorder was meant to fix. device_remove_group is blocking as far as I'm aware. By canceling the work after that it removes the possibility of re-arming the worker after it is freed. The smp_load_acquire ensures any currently queued thread will abort before the call to the led_classdev in the error message. If it is really a problem I'll swap the device over to hdev.dev, but the probability is nearly zero of this ever happening.

>Canceling the work after unregistering the LED device creates a window
>where the executing work can access freed led_cdev.dev memory (as noted
>in claw_rgb_queue_fn).
>
>>  	hid_hw_close(hdev);
>>  }
>
>[Severity: High]
>Are we missing the cancellation of the cfg_setup and cfg_resume delayed works?
>
>The driver schedules cfg_setup and cfg_resume, but does not seem to explicitly
>cancel them here in claw_remove(). If the device is disconnected while either
>work is pending, could they execute after drvdata has been freed by devres,
>resulting in a use-after-free?
>


cfg_setup & cfg_removed are cancelled in this function above the portion marker cutoff. This is introduced in patch 1/4. Bot is wrong here.

- Derek


  reply	other threads:[~2026-07-14 11:43 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-14 10:26 [PATCH v12 0/4] Add MSI Claw HID Configuration Driver Derek J. Clark
2026-07-14 10:26 ` [PATCH v12 1/4] HID: hid-msi: Add MSI Claw configuration driver Derek J. Clark
2026-07-14 10:38   ` sashiko-bot
2026-07-14 10:26 ` [PATCH v12 2/4] HID: hid-msi: Add M-key mapping attributes Derek J. Clark
2026-07-14 10:44   ` sashiko-bot
2026-07-14 10:26 ` [PATCH v12 3/4] HID: hid-msi: Add RGB control interface Derek J. Clark
2026-07-14 10:42   ` sashiko-bot
2026-07-14 11:43     ` Derek J. Clark [this message]
2026-07-14 10:26 ` [PATCH v12 4/4] HID: hid-msi: Add Rumble Intensity Attributes Derek J. Clark

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=426987CB-DA21-403D-903E-153D7BC81F3B@gmail.com \
    --to=derekjohn.clark@gmail.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=sashiko-bot@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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