From: sashiko-bot@kernel.org
To: "Noah Weinberger" <NoahWeinberger2003@proton.me>
Cc: "linux-input@vger.kernel.org" <linux-input@vger.kernel.org>,
dmitry.torokhov@gmail.com
Subject: Re: [PATCH] HID: nintendo-switch2-usb: check URB before use and reset state on free
Date: Sun, 08 Nov 2026 22:40:49 +0000 [thread overview]
Message-ID: <sashiko-outbox-204122@kernel.org> (raw)
In-Reply-To: <HP2LhXZGIipAd2XxKx7dDh8q3SopkJRAxo8IQkuyMxTlR0YfO3rS3CT9NqUkg3ispO72yfhC7Oa4MoZdXgo6lNIEjC1WvQFlrKreFzCnmFM=@proton.me>
Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [High] HID: nintendo-switch2-usb: TOCTOU race in
switch2_usb_message_in_work()
- [Low] HID: nintendo-switch2-usb: misleading indentation in
switch2_usb_message_in_work()
- [Low] HID: nintendo-switch2-usb: missing Fixes and Signed-off-by
trailers in changelog
--
commit ad9c19b8222174b67d5185145f7040b445c19cb7
Author: Noah Weinberger <NoahWeinberger2003@proton.me>
> HID: nintendo-switch2-usb: check URB before use and reset state on free
>
> Hello,
>
> Proposed-fix limitation: the checks below do not establish URB or
> interface lifetime across the pointer check, lock release, and subsequent
> use. These proposed changes may therefore not resolve the teardown race
> or the late-work use-after-free described below. Please review the
> locking and work/interface lifetime before treating this as a complete
> fix; this is an incomplete proposal for maintainer review, not a
> validated resolution.
>
> switch2_bulk_in() calls schedule_work() after dropping bulk_in_lock, so
> the work can be queued after switch2_usb_free_in_urbs() has returned
> from cancel_work_sync(). free_in_urbs() NULLs bulk_in[i].urb but never
> resets bulk_in[i].state, so the late work still sees NS2_URB_IN and
> dereferences urb->urb->transfer_buffer / urb->urb->actual_length on a
> NULL pointer - the existing !urb->urb check sits after those
> dereferences:
>
> if (urb->state != NS2_URB_IN)
> continue;
> spin_unlock_irqrestore(...);
> if (ns2_usb->cfg.parent) {
> err = switch2_receive_command(..., urb->urb->transfer_buffer,
> urb->urb->actual_length); <-- NULL deref
> ...
> if (!urb->urb) <-- too late
>
> A malicious or misbehaving controller (or an unplug racing active
> traffic) wins a narrow window to trigger this; the outcome is an oops
> in workqueue context, and a use-after-free if the work runs after the
> interface data is released. The patch re-checks urb->urb under the lock
> before using it and resets the URB state when freeing, mirroring what
> switch2_usb_shutdown() already does.
>
> Affected version/commit: mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07), drivers/hid/hid-nintendo-switch2-usb.c:51-121 (completion), 209-240 (free path), 288-316 (work).
> New driver merged in this window (zero prior field exposure).
>
> This was found during an assisted (AI-supported) static source review of
> mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07); every code path cited below was re-verified by the
> reporter against that tree. The patch below has NOT been compiled and has
> NOT been runtime tested, and no reproducer was produced - the triggering
> conditions are described above instead. Please treat this as a report for
> verification rather than a battle-tested fix.
>
> Reported-by: Noah Weinberger <noahweinberger2003@proton.me>
[Severity: Low]
The commit message is missing a Signed-off-by: trailer, includes conversational
report boilerplate in the changelog body, and should include:
Fixes: 9417132df63e ("HID: nintendo: Add preliminary Switch 2 controller driver")
> diff --git a/drivers/hid/hid-nintendo-switch2-usb.c b/drivers/hid/hid-nintendo-switch2-usb.c
> index 8b3b6841035d0..c103cedc181ff 100644
> --- a/drivers/hid/hid-nintendo-switch2-usb.c
> +++ b/drivers/hid/hid-nintendo-switch2-usb.c
[ ... ]
> @@ -298,6 +299,11 @@ static void switch2_usb_message_in_work(struct work_struct *work)
> urb = &ns2_usb->bulk_in[i];
> if (urb->state != NS2_URB_IN)
> continue;
> + /* urb->urb is NULLed by switch2_usb_free_in_urbs() while we
> + * may still run; re-check under the lock before using it.
> + */
> + if (!urb->urb)
> + continue;
[Severity: Low]
Does this over-indent the comment and if (!urb->urb) check by one tab level
after the unbraced continue? This triggers a -Wmisleading-indentation
compiler warning (and a build failure with CONFIG_WERROR=y).
> spin_unlock_irqrestore(&ns2_usb->bulk_in_lock, flags);
>
> if (ns2_usb->cfg.parent) {
[Severity: High]
Can switch2_usb_free_in_urbs() still clear and free urb->urb right after
switch2_usb_message_in_work() drops bulk_in_lock here?
switch2_bulk_in() calls schedule_work(&ns2_usb->message_in_work) after
releasing bulk_in_lock, and switch2_usb_free_in_urbs() calls
cancel_work_sync() before killing the URBs, so message_in_work can still be
scheduled and run concurrently with teardown:
CPU0 CPU1 (kworker)
switch2_bulk_in()
lock(&ns2_usb->bulk_in_lock)
urb->state = NS2_URB_IN
unlock(&ns2_usb->bulk_in_lock)
switch2_usb_free_in_urbs()
ns2_usb->shutdown = true
cancel_work_sync()
usb_kill_anchored_urbs()
switch2_bulk_in() (resumes)
schedule_work(&message_in_work)
switch2_usb_message_in_work()
lock(&ns2_usb->bulk_in_lock)
if (!urb->urb)
unlock(&ns2_usb->bulk_in_lock)
lock(&ns2_usb->bulk_in_lock)
ns2_usb->bulk_in[i].urb = NULL
unlock(&ns2_usb->bulk_in_lock)
usb_free_coherent(...)
usb_free_urb(urb)
switch2_receive_command(...,
urb->urb->transfer_buffer, ...)
<-- NULL dereference / UAF
If message_in_work runs after switch2_usb_disconnect() or the
switch2_usb_probe() error path frees ns2_usb, it also dereferences freed
ns2_usb memory, and when re-acquiring bulk_in_lock at the end of the loop it
does not check ns2_usb->shutdown before resubmitting the URB. Killing the
URBs before cancel_work_sync() (or moving schedule_work() inside bulk_in_lock
while checking ns2_usb->shutdown) would prevent new work from being queued
after cancel_work_sync() completes.
--
Sashiko AI review · https://sashiko.dev/#/patchset/HP2LhXZGIipAd2XxKx7dDh8q3SopkJRAxo8IQkuyMxTlR0YfO3rS3CT9NqUkg3ispO72yfhC7Oa4MoZdXgo6lNIEjC1WvQFlrKreFzCnmFM=@proton.me?part=1
next prev parent reply other threads:[~2026-11-08 22:40 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-08 22:29 [PATCH] HID: nintendo-switch2-usb: check URB before use and reset state on free Noah Weinberger
2026-11-08 22:40 ` sashiko-bot [this message]
2026-11-10 2:38 ` Vicki Pfau
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=sashiko-outbox-204122@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=NoahWeinberger2003@proton.me \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox