linux/drivers/usb
Michael Bommarito 90ccf5fb63 usb: gadget: f_fs: copy only received bytes on short ep0 read
commit 4e036c10e7 upstream.

ffs_ep0_read() allocates its control-OUT data buffer with
kmalloc() (not kzalloc) at the Length value from the Setup
packet, then copies that full len to userspace regardless of
how many bytes were actually received:

    data = kmalloc(len, GFP_KERNEL);
    ...
    ret = __ffs_ep0_queue_wait(ffs, data, len);
    if ((ret > 0) && (copy_to_user(buf, data, len)))
            ret = -EFAULT;

__ffs_ep0_queue_wait() returns req->actual, which on a short
control OUT transfer is strictly less than len.  The
copy_to_user() call still copies len bytes, so on a short OUT
the last (len - ret) bytes of the kmalloc() buffer --
uninitialised slab residue -- are delivered to the FunctionFS
daemon.

Short ep0 OUT completions are specified USB control-transfer
behavior and are produced by in-tree UDCs:

  * dwc2 continues on req->actual < req->length for ep0 DATA OUT
    (short-not-ok is the only ep0-OUT stall path).
  * aspeed_udc ends ep0 OUT on rx_len < ep->ep.maxpacket.
  * renesas_usbf logs "ep0 short packet" and completes the
    request.
  * dwc3 stalls on short IN but not on short OUT.

A short ep0 OUT is therefore not evidence of a broken UDC; it is
a normal condition f_fs has to cope with.  The sibling gadgetfs
implementation in drivers/usb/gadget/legacy/inode.c already does
this correctly via min(len, dev->req->actual) before
copy_to_user().  This patch brings f_fs.c to the same safe
pattern rather than trimming at a defensive layer.

The bug is reached from the FunctionFS device node, which in
real deployments is owned by the privileged gadget daemon
(adbd, UMS, composite gadget services, etc.); it is not
reachable from unprivileged userspace.  Linux host stacks
normally reject short-wLength control OUTs before they reach
the gadget, so reproducing this required a build that
bypasses that host-side check.  With the bypass in place, a
1-byte payload on a 64-byte Setup produces 63 bytes of
non-canary slab residue in the daemon's read buffer.

Fix by copying only ret (actually received) bytes to
userspace.

Fixes: ddf8abd259 ("USB: f_fs: the FunctionFS driver")
Cc: stable <stable@kernel.org>
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Link: https://patch.msgid.link/20260419160359.1577270-1-michael.bommarito@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
History 2026-06-19 13:33:30 +02:00
..
atm usb: atm: cxacru: Merge cxacru_upload_firmware() into cxacru_heavy_init() 2025-08-28 16:24:27 +02:00
c67x00 usb/c67x00: Replace tasklet with work 2021-01-26 18:36:37 +01:00
cdns3 usb: cdns3: plat: fix unbalanced pm_runtime_forbid() call permanently leaks the runtime PM usage counter across bind/unbind cycles 2026-06-19 13:33:27 +02:00
chipidea usb: chipidea: core: convert ci_role_switch to local variable 2026-06-19 13:33:29 +02:00
class usb: usbtmc: reject interrupt endpoints with small wMaxPacketSize 2026-06-19 13:33:30 +02:00
common usb: ulpi: fix memory leak on ulpi_register() error paths 2026-06-01 17:35:20 +02:00
core USB: quirks: add NO_LPM for Lenovo ThinkPad USB-C Dock Gen2 hub controllers 2026-06-19 13:33:29 +02:00
dwc2 usb: dwc2: Fix use after free in debug code 2026-06-19 13:33:27 +02:00
dwc3 usb: dwc3: Check for USB4 IP_NAME 2026-02-06 16:41:48 +01:00
early usb: early: xhci-dbc: Fix early_ioremap leak 2025-08-28 16:24:06 +02:00
gadget usb: gadget: f_fs: copy only received bytes on short ep0 read 2026-06-19 13:33:30 +02:00
host usb: xhci: Make usb_host_endpoint.hcpriv survive endpoint_disable() 2026-06-01 17:35:13 +02:00
image usb: image: mdc800: kill download URB on timeout 2026-04-18 10:33:14 +02:00
isp1760 usb: isp1760: Fix out-of-bounds array access 2022-06-09 10:22:27 +02:00
misc usb: misc: uss720: properly clean up reference in uss720_probe() 2026-04-18 10:33:13 +02:00
mon usb: mon: Increase BUFF_MAX to 64 MiB to support multi-MB URBs 2025-12-07 06:09:22 +09:00
mtu3 usb: mtu3: fix kernel panic at qmu transfer done irq handler 2023-05-11 23:00:33 +09:00
musb usb: musb: omap2430: fix device leak at unbind 2025-08-28 16:24:32 +02:00
phy usb: phy: isp1301: fix non-OF device reference imbalance 2026-01-19 13:09:50 +01:00
renesas_usbhs usb: renesas_usbhs: fix use-after-free in ISR during device removal 2026-04-18 10:33:14 +02:00
roles usb: roles: set switch registered flag early on 2025-03-13 12:50:37 +01:00
serial USB: serial: mct_u232: fix missing interrupt-in transfer sanity check 2026-06-19 13:33:30 +02:00
storage usb: storage: Add quirks for PNY Elite Portable SSD 2026-06-19 13:33:29 +02:00
typec usb: typec: wcove: don't write past struct pd_message in wcove_read_rx_buffer() 2026-06-19 13:33:26 +02:00
usbip usbip: vudc: Fix use after free bug in vudc_remove due to race condition 2026-06-19 13:33:30 +02:00
Kconfig usb: remove reference to deleted config STB03xxx 2021-08-18 15:32:19 +02:00
Makefile usb: host: remove line for obsolete config USB_HWA_HCD 2021-08-18 15:32:19 +02:00
usb-skeleton.c USB: usb-skeleton: drop redundant in-urb check 2019-10-10 12:41:19 +02:00