From: Pengpeng Hou <pengpeng@iscas.ac.cn>
To: Srinivasan Raju <srini.raju@purelifi.com>
Cc: Pengpeng Hou <pengpeng@iscas.ac.cn>,
linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] wifi: plfxlc: validate packed firmware file extents
Date: Sun, 30 Aug 2026 21:35:16 +0800 [thread overview]
Message-ID: <20260830133516.7267-1-pengpeng@iscas.ac.cn> (raw)
The XL firmware loader reads an offset table and copies fixed-size chunks
without first proving that the table and each subfile lie inside the
firmware image. Padding a short first-stage chunk can also make the final
copy read beyond its subfile.
Validate the table and monotonic subfile offsets, bind each range to the
firmware size, and zero-pad partial chunks instead of reading padding from
the image.
Fixes: 68d57a07bfe5 ("wireless: add plfxlc driver for pureLiFi X, XL, XC devices")
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
drivers/net/wireless/purelifi/plfxlc/firmware.c | 60 +++++++++++++++++--------
1 file changed, 42 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/purelifi/plfxlc/firmware.c b/drivers/net/wireless/purelifi/plfxlc/firmware.c
index 8a3529d07927d..b017c7bb71465 100644
--- a/drivers/net/wireless/purelifi/plfxlc/firmware.c
+++ b/drivers/net/wireless/purelifi/plfxlc/firmware.c
@@ -166,8 +166,13 @@ int plfxlc_download_xl_firmware(struct usb_interface *intf)
dev_err(&intf->dev, "Request_firmware failed (%d)\n", r);
return -EINVAL;
}
+ if (fwp->size < sizeof(u32) || fwp->size > U32_MAX) {
+ r = -EINVAL;
+ goto out_release;
+ }
+
file.total_files = get_unaligned_le32(&fwp->data[0]);
- file.total_size = get_unaligned_le32(&fwp->size);
+ file.total_size = fwp->size;
dev_dbg(&intf->dev, "XL Firmware (%d, %d)\n",
file.total_files, file.total_size);
@@ -178,18 +183,32 @@ int plfxlc_download_xl_firmware(struct usb_interface *intf)
return -ENOMEM;
}
- if (file.total_files > 10) {
+ if (file.total_files > 10 ||
+ file.total_files > (file.total_size - sizeof(u32)) / sizeof(u32)) {
dev_err(&intf->dev, "Too many files (%d)\n", file.total_files);
- release_firmware(fwp);
- kfree(buf);
- return -EINVAL;
+ r = -EINVAL;
+ goto out_free;
}
/* Download firmware files in multiple steps */
for (s = 0; s < file.total_files; s++) {
+ u32 copy_len, end_addr;
+
buf[0] = s;
r = send_vendor_command(udev, PLF_VNDR_XL_FILE_CMD, buf,
PLF_XL_BUF_LEN);
+ if (r)
+ goto out_free;
+
+ file.start_addr = get_unaligned_le32(&fwp->data[4 + (s * 4)]);
+ if (s < file.total_files - 1)
+ end_addr = get_unaligned_le32(&fwp->data[4 + ((s + 1) * 4)]);
+ else
+ end_addr = file.total_size;
+ if (file.start_addr > end_addr || end_addr > file.total_size) {
+ r = -EINVAL;
+ goto out_free;
+ }
if (s < file.total_files - 1)
file.size = get_unaligned_le32(&fwp->data[4 + ((s + 1) * 4)])
@@ -200,35 +219,41 @@ int plfxlc_download_xl_firmware(struct usb_interface *intf)
if (file.size > file.total_size || file.size > 60000) {
dev_err(&intf->dev, "File size is too large (%d)\n", file.size);
- break;
+ r = -EINVAL;
+ goto out_free;
}
- file.start_addr = get_unaligned_le32(&fwp->data[4 + (s * 4)]);
-
- if (file.size % PLF_XL_BUF_LEN && s < 2)
- file.size += PLF_XL_BUF_LEN - file.size % PLF_XL_BUF_LEN;
-
- file.control_packets = file.size / PLF_XL_BUF_LEN;
+ if (s < 2)
+ file.control_packets =
+ DIV_ROUND_UP(file.size, PLF_XL_BUF_LEN);
+ else
+ file.control_packets = file.size / PLF_XL_BUF_LEN;
for (i = 0; i < file.control_packets; i++) {
+ copy_len = min_t(u32, PLF_XL_BUF_LEN,
+ file.size - i * PLF_XL_BUF_LEN);
+ memset(buf, 0, PLF_XL_BUF_LEN);
memcpy(buf,
&fwp->data[file.start_addr + (i * PLF_XL_BUF_LEN)],
- PLF_XL_BUF_LEN);
+ copy_len);
r = send_vendor_command(udev, PLF_VNDR_XL_DATA_CMD, buf,
PLF_XL_BUF_LEN);
+ if (r)
+ goto out_free;
}
dev_dbg(&intf->dev, "fw-dw step=%d,r=%d size=%d\n", s, r,
file.size);
}
- release_firmware(fwp);
- kfree(buf);
-
/* Code for single pack file download ends fw download finish */
r = send_vendor_command(udev, PLF_VNDR_XL_EX_CMD, NULL, 0);
dev_dbg(&intf->dev, "Download fpga (4) (%d)\n", r);
- return 0;
+out_free:
+ kfree(buf);
+out_release:
+ release_firmware(fwp);
+ return r;
}
int plfxlc_upload_mac_and_serial(struct usb_interface *intf,
@@ -273,4 +298,3 @@ int plfxlc_upload_mac_and_serial(struct usb_interface *intf,
return 0;
}
-
base-commit: 08dbfad3f5040f5bdb6c529da20d6d4e81fefd72
--
2.50.1
reply other threads:[~2026-08-30 13:35 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260830133516.7267-1-pengpeng@iscas.ac.cn \
--to=pengpeng@iscas.ac.cn \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=srini.raju@purelifi.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