From: Joas Antonio dos Santos <joasantonio108@gmail.com>
To: David Heidelberg <david@ixit.cz>, Krzysztof Kozlowski <krzk@kernel.org>
Cc: David S. Miller <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
oe-linux-nfc@lists.linux.dev, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH net] nfc: s3fwrn5: validate the firmware image size against the firmware file
Date: Thu, 29 Oct 2026 23:40:02 -0300 [thread overview]
Message-ID: <179332800288.52644.4206885352837613064@gmail.com> (raw)
s3fwrn5_fw_download() hashes and flashes sector_size * image_sectors
bytes starting at fw->image. sector_size comes from the GET_BOOTINFO
response of the controller's bootloader and image_sectors and the image
offset come from the firmware file, and none of them is checked against
the size of the file. s3fwrn5_fw_update_sector() also always sends
16 * 256 bytes from the start of each sector.
The controller decides whether the update runs at all: it reports the
version that s3fwrn5_fw_check_version() compares against in
CORE_INIT_RSP. So on every device up, as long as the firmware file is
installed, a controller that reports a
large sector_size makes sha1() and the update loop read far past the
end of the firmware buffer, and one that reports a small sector_size
gets up to 4 KiB past the end of the image sent to it in
UPDATE_SECTOR data packets.
Check that everything that is hashed and sent lies within the image,
reject a zero sector_size, reject an image offset past the end of the
file, and make sure the GET_BOOTINFO response is long enough before
copying the 10 bytes of boot information out of it.
Fixes: c04c674fadeb ("nfc: s3fwrn5: Add driver for Samsung S3FWRN5 NFC Chip")
Cc: stable@vger.kernel.org
Signed-off-by: Joas Antonio dos Santos <joasantonio108@gmail.com>
Assisted-by: Yaga Agent HackerSec Claude:claude-opus-5-5
---
Tested on arm64 QEMU with KASAN, with a test-only module that registers
s3fwrn5 through s3fwrn5_probe() on a virtual phy and a userspace
emulator for the NCI and bootloader protocols. With a 4156 byte
firmware file (one 4096 byte sector) and the controller reporting an
older version:
- sector_size 0xffff: oops in sha1_ce_transform() from
s3fwrn5_fw_download() without the patch, update refused with it;
- sector_size 16, 2 sectors: KASAN vmalloc-out-of-bounds in
s3fwrn5_fw_prep_msg() while building an UPDATE_SECTOR data packet
without the patch, update refused with it;
- sector_size 4096: the update runs the same with and without it.
Not tested on hardware.
drivers/nfc/s3fwrn5/firmware.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/drivers/nfc/s3fwrn5/firmware.c b/drivers/nfc/s3fwrn5/firmware.c
index 9145deec7..159afb8de 100644
--- a/drivers/nfc/s3fwrn5/firmware.c
+++ b/drivers/nfc/s3fwrn5/firmware.c
@@ -93,7 +93,8 @@ static int s3fwrn5_fw_get_bootinfo(struct s3fwrn5_fw_info *fw_info,
return ret;
hdr = (struct s3fwrn5_fw_header *) rsp->data;
- if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
+ if (hdr->code != S3FWRN5_FW_RET_SUCCESS ||
+ rsp->len < S3FWRN5_FW_HDR_SIZE + 10) {
ret = -EINVAL;
goto out;
}
@@ -307,6 +308,10 @@ int s3fwrn5_fw_request_firmware(struct s3fwrn5_fw_info *fw_info)
memcpy(&fw->sig_size, fw->fw->data + 0x18, 4);
memcpy(&image_off, fw->fw->data + 0x1C, 4);
+ if (image_off > fw->fw->size) {
+ release_firmware(fw->fw);
+ return -EINVAL;
+ }
fw->image = fw->fw->data + image_off;
memcpy(&fw->image_sectors, fw->fw->data + 0x20, 4);
@@ -409,11 +414,26 @@ int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info)
{
struct device *dev = &fw_info->ndev->nfc_dev->dev;
struct s3fwrn5_fw_image *fw = &fw_info->fw;
+ size_t image_avail = fw->fw->data + fw->fw->size -
+ (const u8 *)fw->image;
+ u64 total = (u64)fw_info->sector_size * fw->image_sectors;
u8 hash_data[SHA1_DIGEST_SIZE];
u32 image_size, off;
int ret;
- image_size = fw_info->sector_size * fw->image_sectors;
+ /* sector_size comes from the bootloader and image_sectors from the
+ * firmware file. The whole image is hashed, and
+ * s3fwrn5_fw_update_sector() sends 16 * 256 bytes from the start of
+ * each sector, so all of that must lie within the firmware image.
+ */
+ if (!fw_info->sector_size || total > image_avail ||
+ (fw->image_sectors &&
+ total - fw_info->sector_size + 16 * 256 > image_avail)) {
+ dev_err(dev, "Invalid firmware image size\n");
+ return -EINVAL;
+ }
+
+ image_size = total;
/* Compute SHA of firmware data */
sha1(fw->image, image_size, hash_data);
--
2.43.0
next reply other threads:[~2026-10-30 2:40 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 2:40 Joas Antonio dos Santos [this message]
2026-10-30 2:43 ` netdev-bot+sinfo
2026-10-30 17:22 ` Joas Antonio dos Santos
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=179332800288.52644.4206885352837613064@gmail.com \
--to=joasantonio108@gmail.com \
--cc=davem@davemloft.net \
--cc=david@ixit.cz \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=krzk@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=oe-linux-nfc@lists.linux.dev \
--cc=pabeni@redhat.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
all inboxes | Powered by JetHome®