public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net 0/4] nfc: digital: Fix missing and misplaced length checks
@ 2026-04-09 22:34 Lekë Hapçiu
  2026-04-09 22:34 ` [PATCH net 1/4] nfc: digital: Fix stack buffer overflow in digital_in_recv_sensf_res() Lekë Hapçiu
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Lekë Hapçiu @ 2026-04-09 22:34 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, stable, krzysztof.kozlowski,
	Lekë Hapçiu

This series fixes four length-check bugs in the NFC Digital Protocol stack.
All are reachable from RF without authentication:

  - Patch 1: Missing upper-bound check before memcpy into target.sensf_res
    in the NFC-F initiator polling path.  An oversized SENSF_RES overflows
    an 18-byte stack buffer by up to 235 bytes.  CVSS 8.1.

  - Patch 2: Check-after-read in the NFC-A target receive path.
    resp->data[0] is read before the resp->len != 0 guard fires.
    A zero-length frame triggers a 1-byte OOB read.

  - Patch 3: Missing post-pull length check in the RTOX handler inside
    digital_in_recv_dep_res().  After skb_pull strips the 3-byte DEP
    header, resp->data[0] is read with no guarantee that any payload byte
    remains.

  - Patch 4: DID byte accessed at resp->data[3] after only a
    sizeof(struct digital_dep_req_res) == 3 byte guard in
    digital_tg_recv_dep_req().  An attacker with DID bit set and a 3-byte
    frame triggers a 1-byte OOB read.

Patches 1-4 are independent and can be applied in any order.

Security Research (4):
  nfc: digital: Fix stack buffer overflow in digital_in_recv_sensf_res()
  nfc: digital: Fix check-after-read in digital_tg_recv_sens_req()
  nfc: digital: Fix OOB read of RTOX byte in digital_in_recv_dep_res()
  nfc: digital: Fix OOB read of DID byte in digital_tg_recv_dep_req()

 net/nfc/digital_dep.c        | 10 ++++++++--
 net/nfc/digital_technology.c | 13 ++++++++-----
 2 files changed, 16 insertions(+), 7 deletions(-)

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

* [PATCH net 1/4] nfc: digital: Fix stack buffer overflow in digital_in_recv_sensf_res()
  2026-04-09 22:34 [PATCH net 0/4] nfc: digital: Fix missing and misplaced length checks Lekë Hapçiu
@ 2026-04-09 22:34 ` Lekë Hapçiu
  2026-04-12 20:58   ` Jakub Kicinski
  2026-04-09 22:34 ` [PATCH net 2/4] nfc: digital: Fix check-after-read in digital_tg_recv_sens_req() Lekë Hapçiu
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Lekë Hapçiu @ 2026-04-09 22:34 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, stable, krzysztof.kozlowski,
	Lekë Hapçiu

The function digital_in_recv_sensf_res() validates that the incoming
SENSF_RES frame is at least DIGITAL_SENSF_RES_MIN_LENGTH (17) bytes,
but does not check that it is at most NFC_SENSF_RES_MAXSIZE (18) bytes
before copying into the 18-byte target.sensf_res stack buffer.

After skb_pull(resp, 1) removes the framing byte, resp->len can range
from 16 up to 253 — an NFC-F frame carries a 1-byte length field with
maximum value 255, from which the driver status byte (pulled here) and
the protocol length byte are subtracted.  The memcpy() at line 775 then
writes up to 235 bytes past the end of target.sensf_res, overflowing
into adjacent stack data including saved registers and the return address.

A device in NFC-F polling mode can trigger this condition without any
prior pairing or authentication by responding to a SENSF_REQ with an
oversized frame.  No user interaction is required on the victim device
while NFC discovery is active.

The NCI code path handles this correctly; nci/ntf.c line 508:
  nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE);

Apply the equivalent upper-bound check to the digital protocol path by
rejecting frames whose post-strip length exceeds NFC_SENSF_RES_MAXSIZE.

Fixes: 8c0695e4998d ("NFC Digital: Add NFC-F technology support")
Cc: stable@vger.kernel.org
Signed-off-by: Lekë Hapçiu <snowwlake@icloud.com>
---
 net/nfc/digital_technology.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c
index XXXXXXX..XXXXXXX 100644
--- a/net/nfc/digital_technology.c
+++ b/net/nfc/digital_technology.c
@@ -768,6 +768,11 @@ static void digital_in_recv_sensf_res(struct nfc_digital_dev *ddev, void *arg,

 	skb_pull(resp, 1);

+	if (resp->len > NFC_SENSF_RES_MAXSIZE) {
+		rc = -EIO;
+		goto exit;
+	}
+
 	memset(&target, 0, sizeof(struct nfc_target));

 	sensf_res = (struct digital_sensf_res *)resp->data;
--
2.34.1

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

* [PATCH net 2/4] nfc: digital: Fix check-after-read in digital_tg_recv_sens_req()
  2026-04-09 22:34 [PATCH net 0/4] nfc: digital: Fix missing and misplaced length checks Lekë Hapçiu
  2026-04-09 22:34 ` [PATCH net 1/4] nfc: digital: Fix stack buffer overflow in digital_in_recv_sensf_res() Lekë Hapçiu
@ 2026-04-09 22:34 ` Lekë Hapçiu
  2026-04-09 22:34 ` [PATCH net 3/4] nfc: digital: Fix OOB read of RTOX byte in digital_in_recv_dep_res() Lekë Hapçiu
  2026-04-09 22:34 ` [PATCH net 4/4] nfc: digital: Fix OOB read of DID byte in digital_tg_recv_dep_req() Lekë Hapçiu
  3 siblings, 0 replies; 6+ messages in thread
From: Lekë Hapçiu @ 2026-04-09 22:34 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, stable, krzysztof.kozlowski,
	Lekë Hapçiu

digital_tg_recv_sens_req() reads resp->data[0] into sens_req at line
1092 before the !resp->len guard fires at line 1094.  A zero-length
frame causes an unconditional 1-byte out-of-bounds read before any
length check has taken place.

The root cause is that the assignment and the length check are split
across two statements: resp->data[0] is read unconditionally into
sens_req, and only then is resp->len tested as part of a compound
condition.  Even though the || operator correctly short-circuits, the
read on the previous line is already done.

Move the length guard before the data access by splitting the combined
condition into an early resp->len check followed by the data read and
the command comparison.

Fixes: 2e7a3e7ee80d ("NFC Digital: Add target mode for NFC-A/ISO14443A")
Cc: stable@vger.kernel.org
Signed-off-by: Lekë Hapçiu <snowwlake@icloud.com>
---
 net/nfc/digital_technology.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c
index XXXXXXX..XXXXXXX 100644
--- a/net/nfc/digital_technology.c
+++ b/net/nfc/digital_technology.c
@@ -1090,11 +1090,14 @@ void digital_tg_recv_sens_req(struct nfc_digital_dev *ddev, void *arg,
 	}

-	sens_req = resp->data[0];
-
-	if (!resp->len || (sens_req != DIGITAL_CMD_SENS_REQ &&
-	    sens_req != DIGITAL_CMD_ALL_REQ)) {
+	if (!resp->len) {
 		rc = -EINVAL;
 		goto exit;
 	}
+
+	sens_req = resp->data[0];
+	if (sens_req != DIGITAL_CMD_SENS_REQ && sens_req != DIGITAL_CMD_ALL_REQ) {
+		rc = -EINVAL;
+		goto exit;
+	}

 	rc = digital_tg_send_sens_res(ddev);
--
2.34.1

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

* [PATCH net 3/4] nfc: digital: Fix OOB read of RTOX byte in digital_in_recv_dep_res()
  2026-04-09 22:34 [PATCH net 0/4] nfc: digital: Fix missing and misplaced length checks Lekë Hapçiu
  2026-04-09 22:34 ` [PATCH net 1/4] nfc: digital: Fix stack buffer overflow in digital_in_recv_sensf_res() Lekë Hapçiu
  2026-04-09 22:34 ` [PATCH net 2/4] nfc: digital: Fix check-after-read in digital_tg_recv_sens_req() Lekë Hapçiu
@ 2026-04-09 22:34 ` Lekë Hapçiu
  2026-04-09 22:34 ` [PATCH net 4/4] nfc: digital: Fix OOB read of DID byte in digital_tg_recv_dep_req() Lekë Hapçiu
  3 siblings, 0 replies; 6+ messages in thread
From: Lekë Hapçiu @ 2026-04-09 22:34 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, stable, krzysztof.kozlowski,
	Lekë Hapçiu

In the SUPERVISOR_PDU / timeout (RTOX) branch of digital_in_recv_dep_res(),
the RTOX value byte is read from resp->data[0] after skb_pull() has
stripped the 3-byte DEP_RES header:

  skb_pull(resp, size);   /* size = sizeof(struct digital_dep_req_res) = 3 */
  ...
  case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU:
      ...
      rtox = DIGITAL_NFC_DEP_RTOX_VALUE(resp->data[0]);

If the remote device sends a DEP_RES frame that is exactly the minimum
length (3 bytes -- dir + cmd + pfb only, no payload), the skb_pull leaves
resp->len == 0 and the read of resp->data[0] is a 1-byte out-of-bounds
read of kernel heap memory beyond the socket buffer.

The I-PDU and ACK/NACK branches are not affected because they either
pass resp directly to upper layers or perform a separate minimum-length
check before accessing payload bytes.  Only the RTOX branch is missing
its guard.

Add a resp->len >= 1 check before the RTOX value read.

Fixes: 4b60cfce7aba ("NFC Digital: Implement NFC-DEP initiator TX and RX")
Cc: stable@vger.kernel.org
Signed-off-by: Lekë Hapçiu <snowwlake@icloud.com>
---
 net/nfc/digital_dep.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c
index XXXXXXX..XXXXXXX 100644
--- a/net/nfc/digital_dep.c
+++ b/net/nfc/digital_dep.c
@@ -866,6 +866,12 @@
 			goto error;
 		}
 
+		if (!resp->len) {
+			PROTOCOL_ERR("14.8.4.1");
+			rc = -EIO;
+			goto error;
+		}
+
 		rtox = DIGITAL_NFC_DEP_RTOX_VALUE(resp->data[0]);
 		if (!rtox || rtox > DIGITAL_NFC_DEP_RTOX_MAX) {
 			PROTOCOL_ERR("14.8.4.1");

--
2.34.1

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

* [PATCH net 4/4] nfc: digital: Fix OOB read of DID byte in digital_tg_recv_dep_req()
  2026-04-09 22:34 [PATCH net 0/4] nfc: digital: Fix missing and misplaced length checks Lekë Hapçiu
                   ` (2 preceding siblings ...)
  2026-04-09 22:34 ` [PATCH net 3/4] nfc: digital: Fix OOB read of RTOX byte in digital_in_recv_dep_res() Lekë Hapçiu
@ 2026-04-09 22:34 ` Lekë Hapçiu
  3 siblings, 0 replies; 6+ messages in thread
From: Lekë Hapçiu @ 2026-04-09 22:34 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, stable, krzysztof.kozlowski,
	Lekë Hapçiu

digital_tg_recv_dep_req() guards against short frames with:

  if (resp->len < size ...)   /* size = sizeof(struct digital_dep_req_res) = 3 */

This guarantees resp->len >= 3 (dir + cmd + pfb).  However, when the
DID bit is set in pfb, the code immediately accesses resp->data[3] — the
DID byte — which is one byte past the guaranteed minimum:

  if (DIGITAL_NFC_DEP_DID_BIT_SET(pfb)) {
      if (ddev->did && (ddev->did == resp->data[3])) {

A remote NFC-DEP initiator can trigger this with a 3-byte DEP_REQ frame
that has the DID bit set in the PFB field, causing a 1-byte
out-of-bounds read of kernel heap memory.

Increment the minimum required length to 4 when the DID bit is present
before accessing resp->data[3], mirroring the pattern used for the
size++ / check at the end of the DID block.

Fixes: 7d0911c07b44 ("NFC Digital: Implement NFC-DEP target TX and RX")
Cc: stable@vger.kernel.org
Signed-off-by: Lekë Hapçiu <snowwlake@icloud.com>
---
 net/nfc/digital_dep.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c
index XXXXXXX..XXXXXXX 100644
--- a/net/nfc/digital_dep.c
+++ b/net/nfc/digital_dep.c
@@ -1117,6 +1117,11 @@ static int digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
 	pfb = dep_req->pfb;

 	if (DIGITAL_NFC_DEP_DID_BIT_SET(pfb)) {
+		if (resp->len < size + 1) {
+			rc = -EIO;
+			goto exit;
+		}
+
 		if (ddev->did && (ddev->did == resp->data[3])) {
 			size++;
 		} else {
--
2.34.1

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

* Re: [PATCH net 1/4] nfc: digital: Fix stack buffer overflow in digital_in_recv_sensf_res()
  2026-04-09 22:34 ` [PATCH net 1/4] nfc: digital: Fix stack buffer overflow in digital_in_recv_sensf_res() Lekë Hapçiu
@ 2026-04-12 20:58   ` Jakub Kicinski
  0 siblings, 0 replies; 6+ messages in thread
From: Jakub Kicinski @ 2026-04-12 20:58 UTC (permalink / raw)
  To: Lekë Hapçiu; +Cc: netdev, linux-wireless, stable, krzysztof.kozlowski

On Fri, 10 Apr 2026 00:34:31 +0200 Lekë Hapçiu wrote:
> The function digital_in_recv_sensf_res() validates that the incoming
> SENSF_RES frame is at least DIGITAL_SENSF_RES_MIN_LENGTH (17) bytes,
> but does not check that it is at most NFC_SENSF_RES_MAXSIZE (18) bytes
> before copying into the 18-byte target.sensf_res stack buffer.

Hm, third similar fix we received for this.
struct digital_sensf_res is 19 bytes, you're capping the length at 18
something else is wrong here..

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

end of thread, other threads:[~2026-04-12 20:58 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-09 22:34 [PATCH net 0/4] nfc: digital: Fix missing and misplaced length checks Lekë Hapçiu
2026-04-09 22:34 ` [PATCH net 1/4] nfc: digital: Fix stack buffer overflow in digital_in_recv_sensf_res() Lekë Hapçiu
2026-04-12 20:58   ` Jakub Kicinski
2026-04-09 22:34 ` [PATCH net 2/4] nfc: digital: Fix check-after-read in digital_tg_recv_sens_req() Lekë Hapçiu
2026-04-09 22:34 ` [PATCH net 3/4] nfc: digital: Fix OOB read of RTOX byte in digital_in_recv_dep_res() Lekë Hapçiu
2026-04-09 22:34 ` [PATCH net 4/4] nfc: digital: Fix OOB read of DID byte in digital_tg_recv_dep_req() Lekë Hapçiu

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