All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Derek J. Clark" <derekjohn.clark@gmail.com>
Cc: dmitry.torokhov@gmail.com, linux-input@vger.kernel.org
Subject: Re: [PATCH v2 2/4] HID: hid-msi: Add M-key mapping attributes
Date: Thu, 14 May 2026 12:22:00 +0000	[thread overview]
Message-ID: <20260514122200.E52C4C2BCB3@smtp.kernel.org> (raw)
In-Reply-To: <20260513231445.3213501-3-derekjohn.clark@gmail.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] The `cfg_mutex` guard in `claw_hw_output_report()` is scoped to an `if` block, releasing the lock before the critical section executes.
- [High] Lockless concurrent access to `profile_pending` between process and interrupt contexts causes data corruption and sequence mismatches on delayed responses.
- [High] Unsafe assumption of USB transport in `claw_probe()` causes type confusion and invalid pointer dereference for non-USB devices.
- [High] Returning an error from `claw_profile_event()` for a spurious event unconditionally triggers `complete()`, causing premature wakeups of unrelated commands.
- [Medium] The function `claw_buttons_store()` illegally mixes scope-based `guard()` cleanup with `goto`-based error handling.
--

commit 42be71c046dc9b6b31d28598f5e0bb568d78b7a1
Author: Derek J. Clark <derekjohn.clark@gmail.com>

HID: hid-msi: Add M-key mapping attributes

Adds attributes that allow for remapping the M-keys with up to 5 values
when in macro mode.

> diff --git a/drivers/hid/hid-msi.c b/drivers/hid/hid-msi.c
> index 8915942af15e6..13ba2747fdb66 100644
> --- a/drivers/hid/hid-msi.c
> +++ b/drivers/hid/hid-msi.c

[ ... ]

> @@ -125,6 +294,31 @@ static int claw_gamepad_mode_event(struct claw_drvdata *drvdata,
>  	return 0;
>  }
>  
> +static int claw_profile_event(struct claw_drvdata *drvdata, struct claw_command_report *cmd_rep)
> +{
> +	u8 *codes;
> +	int i;
> +
> +	switch (drvdata->profile_pending) {
> +	case CLAW_M1_PENDING:
> +	case CLAW_M2_PENDING:
> +		codes = (drvdata->profile_pending == CLAW_M1_PENDING) ?
> +			drvdata->m1_codes : drvdata->m2_codes;
> +		/* Extract key codes; replace disabled (0xff) with 0x00, which is (null) in _show */
> +		for (i = 0; i < CLAW_KEYS_MAX; i++)
> +			codes[i] = (cmd_rep->data[6 + i] != 0xff) ? cmd_rep->data[6 + i] : 0x00;
> +		break;

Is it safe to read and modify profile_pending locklessly here in the
interrupt handler?

Since claw_buttons_show() modifies this state in process context under
profile_mutex, if a sysfs request times out and a subsequent request starts,
could the delayed ACK from the first request cause this handler to see the
new profile_pending state and corrupt the new request's buffer?

> +	default:
> +		dev_warn(&drvdata->hdev->dev,
> +			 "Got profile event without changes pending from command: %x\n",
> +			 cmd_rep->cmd);
> +		return -EINVAL;
> +	}
> +	drvdata->profile_pending = CLAW_NO_PENDING;
> +
> +	return 0;
> +}
> +
>  static int claw_raw_event(struct claw_drvdata *drvdata, struct hid_report *report,
>  			  u8 *data, int size)
>  {

[ ... ]

> @@ -146,6 +340,9 @@ static int claw_raw_event(struct claw_drvdata *drvdata, struct hid_report *repor
>  	case CLAW_COMMAND_TYPE_GAMEPAD_MODE_ACK:
>  		ret = claw_gamepad_mode_event(drvdata, cmd_rep);
>  		break;
> +	case CLAW_COMMAND_TYPE_READ_PROFILE_ACK:
> +		ret = claw_profile_event(drvdata, cmd_rep);
> +		break;
>  	case CLAW_COMMAND_TYPE_ACK:
>  		break;
>  	default:

When claw_profile_event() returns -EINVAL for a spurious event,
claw_raw_event() breaks from the switch and unconditionally calls
complete(&drvdata->send_cmd_complete).

Could this prematurely wake up a thread waiting on a completely different
command, such as WRITE_PROFILE_DATA?

[ ... ]

> @@ -366,6 +563,161 @@ static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
>  }
>  static DEVICE_ATTR_WO(reset);
>  
> +static int button_mapping_name_to_code(const char *name)
> +{

[ ... ]

> +static int claw_buttons_store(struct device *dev, const char *buf, u8 mkey_idx)
> +{
> +	struct hid_device *hdev = to_hid_device(dev);
> +	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
> +	u8 data[] = { 0x01, (drvdata->bmap_addr[mkey_idx] >> 8) & 0xff,
> +		      drvdata->bmap_addr[mkey_idx] & 0xff, 0x07,
> +		      0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff };
> +	size_t len = ARRAY_SIZE(data);
> +	int ret, key_count, i;
> +	char **raw_keys;
> +
> +	raw_keys = argv_split(GFP_KERNEL, buf, &key_count);
> +	if (!raw_keys)
> +		return -ENOMEM;
> +
> +	guard(mutex)(&drvdata->rom_mutex); /* all err_free paths must be in scope */
> +	if (key_count > CLAW_KEYS_MAX) {
> +		ret = -EINVAL;
> +		goto err_free;
> +	}
> +
> +	if (key_count == 0)
> +		goto set_buttons;
> +
> +	for (i = 0; i < key_count; i++) {
> +		ret = button_mapping_name_to_code(raw_keys[i]);
> +		if (ret < 0)
> +			goto err_free;
> +
> +		data[6 + i] = ret;
> +	}
> +
> +set_buttons:
> +	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_WRITE_PROFILE_DATA, data, len, 8);

While reviewing the addition of these sysfs attributes, I noticed a
pre-existing issue in claw_hw_output_report() that is exacerbated by
the concurrent sysfs requests added here:

drivers/hid/hid-msi.c:claw_hw_output_report() {
    ...
    if (timeout) {
        guard(mutex)(&drvdata->cfg_mutex);
        reinit_completion(&drvdata->send_cmd_complete);
    }
    ...
}

Since guard() is scoped to the if block, the mutex is immediately released at
the closing brace.

Doesn't this mean hid_hw_output_report() and
wait_for_completion_interruptible_timeout() execute entirely without
the lock, defeating the intended serialization and allowing concurrent
requests to race?

> +	if (ret < 0)
> +		goto err_free;
> +
> +	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_SYNC_TO_ROM, NULL, 0, 8);
> +
> +err_free:
> +	argv_free(raw_keys);
> +	return ret;
> +}

Is it safe to mix goto-based error handling with scope-based guard() cleanup
in the same function?

According to the cleanup guidelines, functions should either convert
entirely to scope-based cleanup, for example by using a DEFINE_FREE
wrapper for argv_free, or not use guard() at all to avoid confusing
ownership semantics.

[ ... ]

> @@ -432,8 +796,31 @@ static void cfg_resume_fn(struct work_struct *work)
>  		dev_err(&drvdata->hdev->dev, "Failed to set gamepad mode settings: %d\n", ret);
>  }
>  
> +static void claw_features_supported(struct claw_drvdata *drvdata)
> +{

[ ... ]

>  static int claw_probe(struct hid_device *hdev, u8 ep)
>  {
> +	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
> +	struct usb_device *udev = interface_to_usbdev(intf);

Is it guaranteed that this device is always connected via USB?

If this driver is bound to a device connected over a non-USB transport like
I2C, Bluetooth, or UHID, hdev->dev.parent would not be a valid USB
interface, which could cause an invalid pointer dereference here.

Could this code check hid_is_usb(hdev) first or read the version from
hdev->version instead?

>  	struct claw_drvdata *drvdata;
>  	int ret;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260513231445.3213501-1-derekjohn.clark@gmail.com?part=2

  reply	other threads:[~2026-05-14 12:22 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 [this message]
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
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=20260514122200.E52C4C2BCB3@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.