[PATCH net v2 2/2] net: usb: lan78xx: reject short register and statistics reads
From: Wei Jie Law
Date: Sun Oct 18 2026 - 02:19:19 EST
From: Wei Jie Law <98lawweijie@xxxxxxxxx>
lan78xx_read_reg() and lan78xx_read_stats() read from the device into
a freshly kmalloc()ed buffer, but only treat a negative return value
from usb_control_msg() as an error. A device that answers with fewer
bytes than requested leaves part or all of the buffer uninitialized,
and those bytes are then used as the register value or the counters.
With an emulated device on a kernel booted with init_on_alloc=0:
- A reply to the statistics request that is shorter than the 188 byte
counter block leaves the rest of the kmalloc-192 buffer stale, and
ethtool -S, which needs no privileges, reports it. Before the
previous patch, a zero-length reply was enough: one counter pair read
back as 0xffffffff8a427800, the address of
usb_api_blocking_completion(), next to several direct map pointers.
With the previous patch a zero-length reply is already harmless, but
a reply of 1 to 187 bytes still gets through.
- A zero-length reply to the RX_ADDRL/RX_ADDRH reads in
lan78xx_init_mac_address() turns uninitialized heap memory into the
MAC address (12:85:1f:dc:2e:bd and e6:93:44:41:9b:9f on two probes).
Both of those are valid unicast addresses, so they are used as they
are: written to MAF_LO(0)/MAF_HI(0) and set as the address of the
net device, where anyone can read it.
Treat a short transfer as -EIO in both helpers. With this change the
same device fails to probe with -EIO, and a short statistics reply
fails with -EIO and, with the previous patch, leaves the counters
unchanged.
This patch needs the previous one. Without it, a failed statistics read
would make lan78xx_update_stats() compute the counters from its
uninitialized on-stack buffer, so the leak would move from the heap to
the stack. Both patches are Cc: stable and should be backported
together.
Found by code review with LLM assistance and reproduced with an
emulated USB device (raw-gadget + dummy_hcd).
Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
---
drivers/net/usb/lan78xx.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index cb8204371f5c..e6be066349de 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -612,6 +612,9 @@ static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
USB_VENDOR_REQUEST_READ_REGISTER,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, buf, 4, USB_CTRL_GET_TIMEOUT);
+ if (ret >= 0 && ret != sizeof(*buf))
+ ret = -EIO;
+
if (likely(ret >= 0)) {
le32_to_cpus(buf);
*data = *buf;
@@ -695,6 +698,9 @@ static int lan78xx_read_stats(struct lan78xx_net *dev,
(void *)stats,
sizeof(*stats),
USB_CTRL_SET_TIMEOUT);
+ if (ret >= 0 && ret != sizeof(*stats))
+ ret = -EIO;
+
if (likely(ret >= 0)) {
src = (u32 *)stats;
dst = (u32 *)data;
--
2.43.0