From: sashiko-bot@kernel.org
To: "Derek J. Clark" <derekjohn.clark@gmail.com>
Cc: linux-input@vger.kernel.org, dmitry.torokhov@gmail.com
Subject: Re: [PATCH v2 3/4] HID: hid-msi: Add RGB control interface
Date: Thu, 14 May 2026 12:53:37 +0000 [thread overview]
Message-ID: <20260514125337.950E8C2BCB3@smtp.kernel.org> (raw)
In-Reply-To: <20260513231445.3213501-4-derekjohn.clark@gmail.com>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [Critical] The `speed_show` function incorrectly casts the LED class device to a HID device, resulting in an invalid pointer dereference and a guaranteed kernel panic.
- [Critical] Missing bounds check on `frame->frame_count` from the USB device leads to an out-of-bounds read of kernel memory.
- [High] Re-arming `rgb_queue` from sysfs attributes after it has been explicitly cancelled in `claw_remove` leads to a Use-After-Free.
- [High] The `guard(mutex)` macro in `claw_hw_output_report()` is incorrectly used inside a block scope, providing absolutely no synchronization.
- [High] Concurrent modification of shared RGB state without lock protection causes data races and memory corruption.
- [High] Every RGB state change triggers a `SYNC_TO_ROM` command, causing severe flash memory degradation.
- [Medium] An early return in `cfg_setup_fn` silently drops core gamepad sysfs attributes if RGB initialization fails.
--
commit a90ff4a0f03b6df7827bfbcd222f977138b9d280
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.
> --- a/drivers/hid/hid-msi.c
> +++ b/drivers/hid/hid-msi.c
[ ... ]
> @@ -308,15 +368,52 @@ static int claw_profile_event(struct claw_drvdata *drvdata, struct claw_command_
> for (i = 0; i < CLAW_KEYS_MAX; i++)
> codes[i] = (cmd_rep->data[6 + i] != 0xff) ? cmd_rep->data[6 + i] : 0x00;
> break;
> + case CLAW_RGB_PENDING:
> + frame = (struct rgb_report *)cmd_rep->data;
> + rgb_addr = drvdata->rgb_addr;
> + read_addr = be16_to_cpu(frame->read_addr);
> + frame_calc = (read_addr - rgb_addr) / CLAW_RGB_FRAME_OFFSET;
> + if (frame_calc > U8_MAX) {
> + dev_err(drvdata->led_mc.led_cdev.dev, "Got unsupported frame index: %x\n",
> + frame_calc);
> + ret = -EINVAL;
> + goto err_pending;
> + }
> + f_idx = frame_calc;
> +
> + if (f_idx >= CLAW_RGB_MAX_FRAMES) {
> + dev_err(drvdata->led_mc.led_cdev.dev, "Got illegal frame index: %x\n",
> + f_idx);
> + ret = -EINVAL;
> + goto err_pending;
> + }
> +
> + /* Always treat the first frame as the truth for these constants */
> + if (f_idx == 0) {
> + drvdata->rgb_frame_count = frame->frame_count;
drvdata->rgb_frame_count is assigned directly from the hardware packet.
Should there be a bounds check here to ensure it is less than or equal to
CLAW_RGB_MAX_FRAMES?
Later, claw_write_rgb_state() uses drvdata->rgb_frame_count as the upper
bound for a loop reading from drvdata->rgb_frames. If a device sends a
frame count greater than 8, could this read out-of-bounds kernel memory
and send it back to the USB device?
> + /* Invert device speed (20-0) to sysfs speed (0-20) */
> + drvdata->rgb_speed = frame->speed;
> + drvdata->led_mc.led_cdev.brightness = frame->brightness;
> + drvdata->led_mc.subled_info[0].intensity = frame->zone_data.zone[0].red;
> + drvdata->led_mc.subled_info[1].intensity = frame->zone_data.zone[0].green;
> + drvdata->led_mc.subled_info[2].intensity = frame->zone_data.zone[0].blue;
> + }
> +
> + memcpy(&drvdata->rgb_frames[f_idx], &frame->zone_data,
> + sizeof(struct rgb_frame));
claw_profile_event() modifies drvdata->rgb_frames and
drvdata->rgb_frame_count from the HID raw event handler context.
Simultaneously, claw_rgb_queue_fn() runs in a workqueue and calls
functions that overwrite these exact same fields.
Since there are no locks protecting these updates, could a background
worker read torn state or corrupt the frame arrays while they are being
actively updated by the asynchronous device response?
[ ... ]
> @@ -759,6 +856,397 @@ static const struct attribute_group claw_gamepad_attr_group = {
> .is_visible = claw_gamepad_attr_is_visible,
> };
>
> +/* Read RGB config from device */
> +static int claw_read_rgb_config(struct hid_device *hdev)
> +{
[ ... ]
> +/* Send RGB configuration to device */
> +static int claw_write_rgb_state(struct claw_drvdata *drvdata)
> +{
> + struct rgb_report report = { 0x01, 0x0000, CLAW_RGB_FRAME_OFFSET, 0x00,
> + drvdata->rgb_frame_count, 0x09, drvdata->rgb_speed,
> + drvdata->led_mc.led_cdev.brightness };
> + u16 write_addr = drvdata->rgb_addr;
> + size_t len = sizeof(report);
> + int f, ret;
> +
> + if (!drvdata->rgb_addr)
> + return -ENODEV;
> +
> + if (!drvdata->rgb_frame_count)
> + return -EINVAL;
> +
> + guard(mutex)(&drvdata->rom_mutex);
> + /* Loop through (up to) 8 pages of RGB data */
> + for (f = 0; f < drvdata->rgb_frame_count; f++) {
> + report.zone_data = drvdata->rgb_frames[f];
> +
> + /* Set the MCU address to write the frame data to */
> + report.read_addr = cpu_to_be16(write_addr);
> +
> + /* Serialize the rgb_report and write it to MCU */
> + ret = claw_hw_output_report(drvdata->hdev, CLAW_COMMAND_TYPE_WRITE_PROFILE_DATA,
> + (u8 *)&report, len, 8);
> + if (ret)
> + return ret;
> +
> + /* Increment the write addr by the offset for the next frame */
> + write_addr += CLAW_RGB_FRAME_OFFSET;
> + }
> +
> + ret = claw_hw_output_report(drvdata->hdev, CLAW_COMMAND_TYPE_SYNC_TO_ROM, NULL, 0, 8);
Does sending CLAW_COMMAND_TYPE_SYNC_TO_ROM on every RGB state change
cause excessive flash memory degradation?
Because claw_apply_rgb_state() is triggered by unthrottled sysfs writes
(such as rapidly changing a brightness slider), this might cause hundreds
of NVRAM writes per second and potentially degrade the MCU's flash
endurance.
[ ... ]
> +static ssize_t effect_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct led_classdev *led_cdev = dev_get_drvdata(dev);
> + struct led_classdev_mc *led_mc = container_of(led_cdev, struct led_classdev_mc, led_cdev);
> + struct claw_drvdata *drvdata = container_of(led_mc, struct claw_drvdata, led_mc);
> + int ret;
> +
> + ret = sysfs_match_string(claw_rgb_effect_text, buf);
> + if (ret < 0)
> + return ret;
> +
> + drvdata->rgb_effect = ret;
> + mod_delayed_work(system_wq, &drvdata->rgb_queue, msecs_to_jiffies(50));
> +
> + return count;
> +}
Is there a potential use-after-free here if sysfs attributes are written
after the device is removed?
In claw_remove(), the driver attempts to tear down the worker using
cancel_delayed_work_sync(&drvdata->rgb_queue). However, the sysfs files
and LED endpoints remain active because devm cleanup executes after
claw_remove() completes.
A concurrent write to a sysfs attribute like effect_store could call
mod_delayed_work() and re-arm the work item, causing it to execute after
drvdata has been freed.
[ ... ]
> +static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hid_device *hdev = to_hid_device(dev);
> + struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
Is the dev parameter passed to speed_show actually a hid_device?
The rgb_attr_group sysfs group is attached to the LED class device
(led_cdev.dev), not the parent HID device. The macro to_hid_device(dev)
blindly performs a container_of cast, which will yield an invalid pointer
for hdev.
Dereferencing it with hid_get_drvdata(hdev) will likely cause a kernel
panic when this world-readable attribute is accessed.
[ ... ]
> @@ -772,6 +1260,13 @@ static void cfg_setup_fn(struct work_struct *work)
> return;
> }
>
> + ret = claw_read_rgb_config(drvdata->hdev);
> + if (ret) {
> + dev_err(drvdata->led_mc.led_cdev.dev,
> + "Failed to setup device, can't read RGB config: %d\n", ret);
> + return;
> + }
> +
> /* Add sysfs attributes after we get the device state */
> ret = devm_device_add_group(&drvdata->hdev->dev, &claw_gamepad_attr_group);
If claw_read_rgb_config() fails due to a temporary USB error or
unsupported firmware, this early return skips the subsequent
devm_device_add_group call.
Does this unintentionally break the device's core gamepad configuration
interface simply because the RGB initialization failed?
This isn't a new bug introduced by this patch, but does the guard() in
claw_hw_output_report() provide any synchronization?
claw_hw_output_report() {
if (timeout) {
guard(mutex)(&drvdata->cfg_mutex);
reinit_completion(&drvdata->send_cmd_complete);
}
...
}
Because the guard is declared inside the block, the mutex is immediately
released at the closing brace before hid_hw_output_report() and
wait_for_completion_interruptible_timeout() are ever called. This seems
to leave the I/O operations unprotected against concurrent threads, which
this patch introduces via the new RGB workers.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260513231445.3213501-1-derekjohn.clark@gmail.com?part=3
next prev parent reply other threads:[~2026-05-14 12:53 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-13 23:14 [PATCH v2 0/4] Add MSI Claw HID Configuration Driver Derek J. Clark
2026-05-13 23:14 ` [PATCH v2 1/4] HID: hid-msi: Add MSI Claw configuration driver Derek J. Clark
2026-05-14 11:51 ` sashiko-bot
2026-05-14 13:43 ` Derek John Clark
2026-05-13 23:14 ` [PATCH v2 2/4] HID: hid-msi: Add M-key mapping attributes Derek J. Clark
2026-05-14 12:22 ` sashiko-bot
2026-05-14 13:48 ` Derek John Clark
2026-05-13 23:14 ` [PATCH v2 3/4] HID: hid-msi: Add RGB control interface Derek J. Clark
2026-05-14 12:53 ` sashiko-bot [this message]
2026-05-14 13:54 ` Derek John Clark
2026-05-13 23:14 ` [PATCH v2 4/4] HID: hid-msi: Add Rumble Intensity Attributes Derek J. Clark
2026-05-14 16:29 ` sashiko-bot
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=20260514125337.950E8C2BCB3@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=derekjohn.clark@gmail.com \
--cc=dmitry.torokhov@gmail.com \
--cc=linux-input@vger.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.