[PATCH v2] nfc: st21nfca: validate received frame before unstuffing
From: Pengpeng Hou
Date: Fri Aug 14 2026 - 04:15:13 EST
st21nfca_hci_i2c_repack() trims a frame at EOF and then assumes the
remaining data contains the LLC header and CRC bytes. Its byte-unstuffing
loop also reads the byte after every escape marker without checking that
one remains.
Validate the minimum frame before and after unstuffing, use separate
input and output cursors, and reject a trailing escape before CRC
processing.
Fixes: 3096e25a3e40 ("NFC: st21nfca: Fix incorrect byte stuffing revocation")
Assisted-by: Codex:gpt-5
Signed-off-by: Pengpeng Hou <pengpeng@xxxxxxxxxxx>
---
Changes since v1: https://lore.kernel.org/all/20260715084405.41546-1-pengpeng@xxxxxxxxxxx/
- no source-code changes
- rebase on the current NFC sources and tighten the commit message
- add the coding-assistant disclosure
The start, EOF, stuffing and CRC extents were reviewed statically; no
ST21NFCA hardware or malformed frame test was performed.
drivers/nfc/st21nfca/i2c.c | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c
index aa5f4922b6b0..11ba4fb49828 100644
--- a/drivers/nfc/st21nfca/i2c.c
+++ b/drivers/nfc/st21nfca/i2c.c
@@ -289,27 +289,36 @@ static int check_crc(u8 *buf, int buflen)
*/
static int st21nfca_hci_i2c_repack(struct sk_buff *skb)
{
- int i, j, r, size;
+ int read, write, r, size;
- if (skb->len < 1 || (skb->len > 1 && skb->data[1] != 0))
+ if (skb->len < ST21NFCA_FRAME_HEADROOM ||
+ !IS_START_OF_FRAME(skb->data))
return -EBADMSG;
size = get_frame_size(skb->data, skb->len);
if (size > 0) {
+ if (size < ST21NFCA_FRAME_HEADROOM + 2)
+ return -EBADMSG;
+
skb_trim(skb, size);
/* remove ST21NFCA byte stuffing for upper layer */
- for (i = 1, j = 0; i < skb->len; i++) {
- if (skb->data[i + j] ==
+ for (read = 1, write = 1; read < skb->len;) {
+ if (skb->data[read] ==
(u8) ST21NFCA_ESCAPE_BYTE_STUFFING) {
- skb->data[i] = skb->data[i + j + 1]
- | ST21NFCA_BYTE_STUFFING_MASK;
- i++;
- j++;
+ if (read + 1 == skb->len)
+ return -EBADMSG;
+
+ skb->data[write++] = skb->data[read + 1]
+ | ST21NFCA_BYTE_STUFFING_MASK;
+ read += 2;
+ } else {
+ skb->data[write++] = skb->data[read++];
}
- skb->data[i] = skb->data[i + j];
}
/* remove byte stuffing useless byte */
- skb_trim(skb, i - j);
+ skb_trim(skb, write);
+ if (skb->len < ST21NFCA_FRAME_HEADROOM + 2)
+ return -EBADMSG;
/* remove ST21NFCA_SOF_EOF from head */
skb_pull(skb, 1);
--
2.50.1 (Apple Git-155)