The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH] wifi: libertas_tf: Fix slab-out-of-bounds write in if_usb_send_fw_pkt()
@ 2026-08-25  9:24 Yang Zi
  2026-08-25 14:13 ` Johan Hovold
  0 siblings, 1 reply; 2+ messages in thread
From: Yang Zi @ 2026-08-25  9:24 UTC (permalink / raw)
  To: johannes.berg, johan, kees; +Cc: linux-wireless, libertas-dev, linux-kernel

if_usb_send_fw_pkt() copies a firmware block into the driver's
ep_out_buf using the length taken directly from the firmware header
(fwdata->hdr.datalength) without any validation.  That same untrusted
value is also used as the USB transfer length and to advance
cardp->totalbytes.

A crafted or truncated firmware image can set datalength to a huge value,
which makes the memcpy() into fwdata->data write far past the end of the
1574-byte ep_out_buf (KASAN reports a ~3.5 GiB slab-out-of-bounds write)
and, once totalbytes has run away, makes the subsequent header memcpy()
read past the end of the firmware image.

check_fwfile_format() only checks the cumulative length and never bounds
an individual block, and FW_MAX_DATA_BLK_SIZE (600) is never used.

Validate the block length in if_usb_send_fw_pkt(): reject any block whose
datalength exceeds FW_MAX_DATA_BLK_SIZE or the number of bytes remaining
in the firmware image, and return -EINVAL before the memcpy().  Also
enforce the per-block upper bound in check_fwfile_format() so that
invalid images are rejected up front.

Signed-off-by: Yang Zi <2959243019@qq.com>
---
diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
index b85c6d783bf7..f82860b77da2 100644
--- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
@@ -268,6 +268,7 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
 {
     struct fwdata *fwdata = cardp->ep_out_buf;
     u8 *firmware = (u8 *) cardp->fw->data;
+    u32 datalength;
 
     lbtf_deb_enter(LBTF_DEB_FW);
 
@@ -291,17 +292,24 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
     cardp->fwlastblksent = cardp->totalbytes;
     cardp->totalbytes += sizeof(struct fwheader);
 
-    memcpy(fwdata->data, &firmware[cardp->totalbytes],
-           le32_to_cpu(fwdata->hdr.datalength));
+    datalength = le32_to_cpu(fwdata->hdr.datalength);
+    if (datalength > FW_MAX_DATA_BLK_SIZE ||
+        cardp->totalbytes > cardp->fw->size ||
+        datalength > cardp->fw->size - cardp->totalbytes) {
+        lbtf_deb_usb2(&cardp->udev->dev,
+                  "invalid firmware block length %u\n", datalength);
+        return -EINVAL;
+    }
 
-    lbtf_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
-             le32_to_cpu(fwdata->hdr.datalength));
+    memcpy(fwdata->data, &firmware[cardp->totalbytes], datalength);
+
+    lbtf_deb_usb2(&cardp->udev->dev, "Data length = %u\n", datalength);
 
     fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
-    cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
+    cardp->totalbytes += datalength;
 
     usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
-             le32_to_cpu(fwdata->hdr.datalength), 0);
+             datalength, 0);
 
     if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
         lbtf_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
@@ -775,6 +783,10 @@ static int check_fwfile_format(const u8 *data, u32 totlen)
         blksize = le32_to_cpu(fwh->datalength);
         switch (bincmd) {
         case FW_HAS_DATA_TO_RECV:
+            if (blksize > FW_MAX_DATA_BLK_SIZE) {
+                exit = 1;
+                break;
+            }
             offset = sizeof(struct fwheader) + blksize;
             data += offset;
             len += offset;
@@ -782,6 +794,10 @@ static int check_fwfile_format(const u8 *data, u32 totlen)
                 exit = 1;
             break;
         case FW_HAS_LAST_BLOCK:
+            if (blksize > FW_MAX_DATA_BLK_SIZE) {
+                exit = 1;
+                break;
+            }
             exit = 1;
             ret = 0;
             break;


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

end of thread, other threads:[~2026-08-25 14:13 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-25  9:24 [PATCH] wifi: libertas_tf: Fix slab-out-of-bounds write in if_usb_send_fw_pkt() Yang Zi
2026-08-25 14:13 ` Johan Hovold

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