Thread (74 messages) flat view 74 messages, 3 authors, 16d ago

Re: [RFC PATCH v2 1/2] HID: topping-m62: driver for the M62's vendor controls

From: sashiko-bot@kernel.org
Date: 2026-09-04 14:21:21

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Use-After-Free in topping_bind error path when handling concurrent USB events.
--

commit a582809964c0e1ad990a6ee419fbee8c5cf85dae
Author: Mikhail Gavrilov [off-list ref]

HID: topping-m62: driver for the M62's vendor controls

This commit adds a HID driver for the Topping M62 USB audio interface to
expose vendor-specific controls like analog input gains, output volumes, 
and source selectors. These controls are exposed as ALSA mixer elements on
the sound card created by snd-usb-audio.
quoted hunk ↗ jump to hunk
diff --git a/drivers/hid/hid-topping-m62.c b/drivers/hid/hid-topping-m62.c
new file mode 100644
index 0000000000000..66c037e2b8688
--- /dev/null
+++ b/drivers/hid/hid-topping-m62.c
[ ... ]
+static int topping_raw_event(struct hid_device *hdev,
+			     struct hid_report *report, u8 *data, int size)
+{
[ ... ]
+	guard(spinlock_irqsave)(&m62->lock);
+
+	if (m62->val[idx] == value)
+		return 0;
+	m62->val[idx] = value;
+
+	if (m62->card && m62->kctl[idx])
+		snd_ctl_notify(m62->card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &m62->kctl[idx]->id);
[Severity: High]
If an interrupt packet arrives while the controls are being freed, could
this lead to a use-after-free?

Since hid_device_io_start() was called earlier in probe, topping_raw_event()
can execute concurrently with the error path in topping_bind().
+
+	return 0;
+}
[ ... ]
+static void topping_drop_kctls(struct topping_m62 *m62, struct snd_card *card)
+{
+	int i;
+
+	for (i = 0; i < TOPPING_NUM_KCTLS; i++) {
+		snd_ctl_remove(card, m62->kctl[i]);
+		m62->kctl[i] = NULL;
+	}
+}
[ ... ]
+static int topping_bind(struct device *comp, struct device *master,
+			void *master_data)
+{
+	struct hid_device *hdev = to_hid_device(comp);
+	struct topping_m62 *m62 = hid_get_drvdata(hdev);
+	struct snd_card *card = master_data;
+	int i, err;
+
+	scoped_guard(spinlock_irqsave, &m62->lock)
+		m62->card = card;
+
+	for (i = 0; i < TOPPING_NUM_CTLS; i++) {
+		err = topping_add_kctl(m62, &topping_ctl,
+				       topping_m62_ctls[i].name, i, i,
+				       topping_m62_ctls[i].tlv);
+		if (err < 0)
+			goto err_drop;
+	}
[ ... ]
+err_drop:
+	topping_drop_kctls(m62, card);
+	scoped_guard(spinlock_irqsave, &m62->lock)
+		m62->card = NULL;
+	return err;
+}
[Severity: High]
Could this error path allow the race described above?

If topping_add_kctl() fails, we jump to err_drop and call
topping_drop_kctls(). The controls are removed and freed via snd_ctl_remove()
without holding m62->lock.

Because m62->card is still non-NULL until after topping_drop_kctls() finishes,
a concurrent topping_raw_event() could take the lock, see m62->card is valid,
and access the already-freed m62->kctl[idx]->id.

It looks like topping_unbind() avoids this exact issue by clearing m62->card
under the lock before removing the controls. Should err_drop follow the same
ordering to prevent the race?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260904141158.33398-1-mikhail.v.gavrilov@gmail.com?part=1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help