mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [BUG] usb: gadget: u_serial: use-after-free of gserial in gs_write()/gs_flush_chars() remote-wakeup path
@ 2026-10-19  3:34 Yu Zhang
  2026-10-19  6:44 ` Greg Kroah-Hartman
  0 siblings, 1 reply; 2+ messages in thread
From: Yu Zhang @ 2026-10-19  3:34 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-usb, linux-kernel

Hi,

gs_write() and gs_flush_chars() cache

	struct gserial *gser = port->port_usb;

at function entry, before taking port->port_lock. In the
"if (port->suspended)" branch they drop port_lock and call
gserial_wakeup_host(gser) on that cached pointer, with no re-check of
port->port_usb -- unlike the sibling gs_start_tx() path in the very same
functions, which is guarded by "if (port->port_usb)" after re-acquiring
the lock.

gserial_wakeup_host() dereferences gser->func.config->cdev->gadget. A
concurrent gserial_disconnect() clears port->port_usb (under port_lock),
and the following unbind / function teardown frees the enclosing
struct f_acm / struct f_gser (which embeds the gserial) via ->free_func.
The cached gser is then used after free:

  BUG: KASAN: slab-use-after-free in gs_write+0x120/0x240
  Read of size 8 at addr ffff888006c5d430 by task ...
   gs_write+0x120/0x240
   n_tty_write+0x355/0xc30
   file_tty_write.isra.0+...
   vfs_write+...
   ksys_write+...
  Allocated by task ...:
   acm_alloc_func+0x34/0x1f0
   config_usb_cfg_link+0x15c/0x220
   configfs_symlink+...
  Freed by task ...:
   kfree+...
   acm_free_func+0x29/0x60
   config_usb_cfg_unlink+0x1a9/0x240
   configfs_unlink+...
   __x64_sys_unlink+0x34/0x50

gs_flush_chars() has the identical shape.

== Reproduction ==

acm gadget on dummy_hcd (CONFIG_USB_DUMMY_HCD, CONFIG_USB_U_SERIAL,
CONFIG_USB_CONFIGFS_ACM), KASAN. Put the bus into suspend so
port->suspended is set: write "auto" to the gadget's host-side
.../power/control with autosuspend_delay_ms=0, which makes dummy_hcd
suspend the port and run the gadget ->suspend / gserial_suspend. Then:

  - task A: write to /dev/ttyGS0  (enters the gs_write() suspended branch)
  - task B: echo "" > g1/UDC ; rm g1/configs/c.1/acm.0 ; rmdir g1/functions/acm.0
            (unbind + drop the acm function -> frees the gserial)

The gserial_wakeup_host(gser) call in task A then touches freed memory.
(I widened the window after the port_lock drop with a debug mdelay to make
it deterministic; without it this is a narrow race.)

The sibling gs_start_tx() call in the same two functions is guarded with
"if (port->port_usb)" after re-acquiring port_lock; the suspended/wakeup
branch dereferences the pre-lock cached gser with no equivalent check.

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [BUG] usb: gadget: u_serial: use-after-free of gserial in gs_write()/gs_flush_chars() remote-wakeup path
  2026-10-19  3:34 [BUG] usb: gadget: u_serial: use-after-free of gserial in gs_write()/gs_flush_chars() remote-wakeup path Yu Zhang
@ 2026-10-19  6:44 ` Greg Kroah-Hartman
  0 siblings, 0 replies; 2+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-19  6:44 UTC (permalink / raw)
  To: Yu Zhang; +Cc: linux-usb, linux-kernel

On Mon, Oct 19, 2026 at 01:34:46PM +1000, Yu Zhang wrote:
> Hi,
> 
> gs_write() and gs_flush_chars() cache
> 
> 	struct gserial *gser = port->port_usb;
> 
> at function entry, before taking port->port_lock. In the
> "if (port->suspended)" branch they drop port_lock and call
> gserial_wakeup_host(gser) on that cached pointer, with no re-check of
> port->port_usb -- unlike the sibling gs_start_tx() path in the very same
> functions, which is guarded by "if (port->port_usb)" after re-acquiring
> the lock.

Great, can you submit a patch for this after testing this on linux-next
to verify it's not already resolved?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-19  6:44 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-19  3:34 [BUG] usb: gadget: u_serial: use-after-free of gserial in gs_write()/gs_flush_chars() remote-wakeup path Yu Zhang
2026-10-19  6:44 ` Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®