Linux USB
 help / color / mirror / Atom feed
From: Michal Pecio <michal.pecio@gmail.com>
To: Joseph Bursey <jbursey@uci.edu>
Cc: syzbot <syzbot+ad2aac2febc3bedf0962@syzkaller.appspotmail.com>,
	gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org,
	linux-usb@vger.kernel.org, syzkaller-bugs@googlegroups.com
Subject: Re: [syzbot] [usb?] KASAN: slab-use-after-free Write in iowarrior_write_callback (2)
Date: Sun, 24 May 2026 10:30:53 +0200	[thread overview]
Message-ID: <20260524103053.308501de.michal.pecio@gmail.com> (raw)
In-Reply-To: <32c79569-8001-48d2-9675-b38b1670f285@uci.edu>

On Fri, 22 May 2026 13:38:40 -0700, Joseph Bursey wrote:
> Hello, I believe I have a reproducer for this bug using a combination
> of syz-execprog and eBPF programs.

Hi, could you check if this patch (compile tested only) fixes it?

I admit I'm not an expert on USB core, but I see nothing _reliably_
preventing URB submissions after usb_disable_interface(), which may
be the root cause of this bug (besides the driver sloppiness for
which separate patches have been posted by Johan Hovold).

My patch tries to fix it by updating ep->enabled under a spinlock
which will be held while checking this flag on submission attempts.

Such bug is trouble not only for sloppy drivers, but also for HCDs
which assume that no URBs exist while endpoints are being "dropped".
Syzbot and you apparently found ways to break this assumption:

static int usb_unbind_interface(struct device *dev)
{
	[...]
        /*
         * Terminate all URBs for this interface unless the driver
         * supports "soft" unbinding and the device is still present.
         */
        if (!driver->soft_unbind || udev->state == USB_STATE_NOTATTACHED)
                usb_disable_interface(udev, intf, false);
	// no URBs should be pending on these endpoints now

        driver->disconnect(intf);
	// but one is observed completing concurrently now

I also suspect that more UAF in sloppy drivers is possible due to
usb_hcd_flush_endpoint() failing to wait for pending BH givebacks.
It seems that dummy-hcd doesn't use HCD_BH, so this shouldn't be
a factor here, but it could become an issue on real hardware.

As long as resubmission is prevented reliably, this won't affect
HCDs, but it may cause UAF in buggy class drivers.

---

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index b181b43a35dc..4fee30101e96 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1958,6 +1958,15 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev,
 	return ret;
 }
 
+void usb_hcd_set_endpoint_enabled(struct usb_host_endpoint *ep, int enabled)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hcd_urb_list_lock, flags);
+	ep->enabled = enabled;
+	spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
+}
+
 /* Disables the endpoint: synchronizes with the hcd to make sure all
  * endpoint state is gone from hardware.  usb_hcd_flush_endpoint() must
  * have been called previously.  Use for set_configuration, set_interface,
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 75e2bfd744a9..8d656d7e8f69 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1358,7 +1358,7 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr,
 			dev->ep_in[epnum] = NULL;
 	}
 	if (ep) {
-		ep->enabled = 0;
+		usb_hcd_set_endpoint_enabled(ep, 0);
 		usb_hcd_flush_endpoint(dev, ep);
 		if (reset_hardware)
 			usb_hcd_disable_endpoint(dev, ep);
@@ -1523,7 +1523,7 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep,
 		dev->ep_out[epnum] = ep;
 	if (!is_out || is_control)
 		dev->ep_in[epnum] = ep;
-	ep->enabled = 1;
+	usb_hcd_set_endpoint_enabled(ep, 1);
 }
 
 /**
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 181db044c4d2..de97827a579b 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -437,6 +437,7 @@ extern void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *, struct urb *);
 extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *);
 extern void usb_hcd_flush_endpoint(struct usb_device *udev,
 		struct usb_host_endpoint *ep);
+extern void usb_hcd_set_endpoint_enabled(struct usb_host_endpoint *ep, int enabled);
 extern void usb_hcd_disable_endpoint(struct usb_device *udev,
 		struct usb_host_endpoint *ep);
 extern void usb_hcd_reset_endpoint(struct usb_device *udev,

  parent reply	other threads:[~2026-05-24  8:30 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-19 22:26 [syzbot] [usb?] KASAN: slab-use-after-free Write in iowarrior_write_callback (2) syzbot
2026-05-22 20:38 ` Joseph Bursey
2026-05-23  4:19   ` Greg KH
2026-05-24  8:30   ` Michal Pecio [this message]
2026-05-24 14:45     ` Alan Stern
2026-05-24 16:46       ` Michal Pecio

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=20260524103053.308501de.michal.pecio@gmail.com \
    --to=michal.pecio@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jbursey@uci.edu \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=syzbot+ad2aac2febc3bedf0962@syzkaller.appspotmail.com \
    --cc=syzkaller-bugs@googlegroups.com \
    /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