From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from outbound.qs.icloud.com (qs-2006l-snip4-5.eps.apple.com [57.103.85.246]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C66783A3806 for ; Thu, 9 Apr 2026 23:36:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=57.103.85.246 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775777763; cv=none; b=CE58h7mgqt9DbuxTjMOXn6hyJjgv39DMAw14jLAbWxSb9sBAWhcqgpsOdKU2zpQ/wYgf4If32eNw6AleKDHLCWZgz+rXGAIUMvokyzP4hK4m25cFlJKspHj0BXmhxchnjVrcuCjcJl9xVUcP8GLxAzkDZ53dk5X+x9qRK6zDUFQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775777763; c=relaxed/simple; bh=RYbFDhdX7fkWoG806yqB7SHMv6+YWj33EAnCq2ZdDzc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=A2x5/abgPpDw/JmlIbZmpbxLy4En3w+nRWBNUyTzp3Z/Fmqd3sFgYEo9lkaTnjELbv4+x7a6siid2P3BVoFX9NAF68KRYKqzgxtPRj8rdHCerhiLyI1PkTBNKc2uV8wuCM3Axk8D7ycatxfiN7moArJM96aOYNgB9vJGb8R3KTc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=icloud.com; spf=pass smtp.mailfrom=icloud.com; dkim=pass (2048-bit key) header.d=icloud.com header.i=@icloud.com header.b=s2xoKGca; arc=none smtp.client-ip=57.103.85.246 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=icloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=icloud.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=icloud.com header.i=@icloud.com header.b="s2xoKGca" Received: from outbound.qs.icloud.com (unknown [127.0.0.2]) by p00-icloudmta-asmtp-us-east-2d-60-percent-5 (Postfix) with ESMTPS id AF76E180011B; Thu, 09 Apr 2026 23:35:57 +0000 (UTC) Dkim-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=icloud.com; s=1a1hai; t=1775777760; x=1778369760; bh=jxNonVp/UZyij6iyYk46/5gMGC8iDxkJH/YjjyLjCmE=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type:x-icloud-hme; b=s2xoKGcaVB7y8E69GDBRXbW1NWH3ViMzOnVmXxHC6obN+bKzvMpc3Qpt9vw0ck/QhjHJngFBnFanXwHEWpLqH1F7rTrREKY0oHhLIHbz3a7g2FWmIjkla2JnddHmmNG6Dai3GcqTxTH+pHN0FIC2E2odbrvN0au3gug/iOyyeJfoAKGIclgTU7ZvbDeXbbLCkoy4E47mC6PxKcpw/wlpL9biQEYEosiGchXabpjv4mLE8fmDhfEMKMNQX/jp/TfFoOHilAomRUwh14rKNsXaAMK3A3FOZ5iRNjxr3cXFeXJ4l8t4i6ybCS3yBGeLUaRkhcNqy+nDNUTJ/YneQsf2MQ== Received: from mainframe.tailfb0f7b.ts.net (unknown [17.57.155.37]) by p00-icloudmta-asmtp-us-east-2d-60-percent-5 (Postfix) with ESMTPSA id 75D8518000BF; Thu, 09 Apr 2026 23:35:55 +0000 (UTC) From: =?UTF-8?q?Lek=C3=AB=20Hap=C3=A7iu?= To: netdev@vger.kernel.org Cc: linux-nfc@lists.01.org, stable@vger.kernel.org, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, =?UTF-8?q?Lek=C3=AB=20Hap=C3=A7iu?= Subject: [PATCH net 2/3] nfc: llcp: fix TLV parsing OOB and length underflow in nfc_llcp_recv_snl Date: Fri, 10 Apr 2026 01:35:15 +0200 Message-ID: <20260409233517.1891497-3-snowwlake@icloud.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260409233517.1891497-1-snowwlake@icloud.com> References: <20260409233517.1891497-1-snowwlake@icloud.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Proofpoint-ORIG-GUID: Y90yU5F4X2-y1St_1MqM43KIuaP9Avsk X-Proofpoint-GUID: Y90yU5F4X2-y1St_1MqM43KIuaP9Avsk X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNDA5MDIxOCBTYWx0ZWRfX1DpB2RQdMcDb 47TSRa5wNw7Nrr0sKjRtsuG9md5OoQb3cLSoTjcQcjbCBNNFUR/fauySopdYY3HjbeCLcKbWhG8 pbAnSwm7Of4CpkHEy17xrYPKP6Zvzu7fhwZbAX6tv+5CZOXn4o1hsPa5zazceNdXahVN63qScBW CgHikQt4ptavt48YT+TrD0/pgtCIl8/3OPhTmqT0hKXKNlu234XggKUfRMd0J5OtHoRipkj1HJY ojxbigmGt9bv2oC1wStNv53Qwa2id9BAWK3eT2sIVl+b9Knl8cyWyl0+jgUE0TCrcPkZoA7nIWI pQ4CgPuFL9pbMHuyq3AL24V2/unTVfASsIp/8M5s1e1TkcmGKqn/ckqB15jyNM= X-Authority-Info-Out: v=2.4 cv=RpvI7SmK c=1 sm=1 tr=0 ts=69d837de cx=c_apl:c_pps:t_out a=bsP7O+dXZ5uKcj+dsLqiMw==:117 a=bsP7O+dXZ5uKcj+dsLqiMw==:17 a=IkcTkHD0fZMA:10 a=A5OVakUREuEA:10 a=M51BFTxLslgA:10 a=x7bEGLp0ZPQA:10 a=LbuW6tbUWPcA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VwQbUJbxAAAA:8 a=v3ZZPjhaAAAA:8 a=h198WebNHr3hihf7tCMA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=JKcXVnpmuwdQ7RL0mgk_:22 a=5Q-93EyGrU3sW_9myDOF:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-04-09_04,2026-04-09_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=0 lowpriorityscore=0 spamscore=0 mlxscore=0 phishscore=0 bulkscore=0 clxscore=1015 malwarescore=0 mlxlogscore=999 adultscore=0 classifier=spam authscore=0 adjust=0 reason=mlx scancount=1 engine=8.22.0-2601150000 definitions=main-2604090218 nfc_llcp_recv_snl() contains four distinct vulnerabilities. Issue 1 - missing minimum-length guard on skb: nfc_llcp_dsap() and nfc_llcp_ssap() access pdu->data[0] and pdu->data[1] unconditionally. The subsequent computation: tlv_len = skb->len - LLCP_HEADER_SIZE; /* LLCP_HEADER_SIZE = 2 */ truncates to u16. If skb->len < 2, the unsigned subtraction wraps at unsigned int width and the truncation to u16 yields up to 65534, causing the while loop to iterate far beyond the skb data. No guard exists at the dispatch path to prevent this. Fix: add `if (skb->len < LLCP_HEADER_SIZE) return;` before any skb->data access, matching the pattern already used in nfc_llcp_recv_agf(). Issue 2 - missing per-iteration TLV header guard: The loop reads tlv[0] and tlv[1] with no prior check that two bytes remain. When one byte remains, tlv[1] is one byte past the array end. Fix: `if (tlv_len - offset < 2) break;` Issue 3 - peer-controlled `length` field advances tlv past skb end: `length` (tlv[1]) is advanced unconditionally into `offset` and `tlv` without verifying that `length` bytes of TLV value exist. A malicious peer sets `length` large enough that `offset` remains below `tlv_len` on the next iteration while `tlv` points into adjacent kernel heap. Fix: `if (tlv_len - offset - 2 < length) break;` Issue 4 - per-type minimum-length hazards: LLCP_TLV_SDREQ: `service_name_len = length - 1` is u8 arithmetic. When length == 0 this wraps to 255, causing a 255-byte kernel memory scan via strncmp. tlv[2] (tid) is also accessed unconditionally. Fix: require length >= 1 before the tid/service_name access. LLCP_TLV_SDRES: tlv[2] and tlv[3] are accessed without verifying length >= 2. Unlike the GB/connection parsers, SDREQ/SDRES are not processed via llcp_tlv8/16, so the llcp_tlv_length[] table provides no protection here. Fix: require length >= 2 before the tlv[2]/tlv[3] accesses. In both cases a `break` from the inner switch falls through to the unconditional `offset += length + 2; tlv += length + 2` at the loop tail, correctly advancing past the malformed TLV. The outer two guards break from the while loop entirely. Reachability: SNL PDUs are processed during LLCP service discovery, before any connection is established, from any NFC peer within ~4 cm with no authentication or pairing. Fixes: 7a06f0ee2823 ("NFC: llcp: Service Name Lookup implementation") Cc: stable@vger.kernel.org Signed-off-by: Lekë Hapçiu --- net/nfc/llcp_core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index db5bc6a87..16acf7c2b 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -1284,6 +1284,11 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, size_t sdres_tlvs_len; HLIST_HEAD(nl_sdres_list); + if (skb->len < LLCP_HEADER_SIZE) { + pr_err("Malformed SNL PDU\n"); + return; + } + dsap = nfc_llcp_dsap(skb); ssap = nfc_llcp_ssap(skb); @@ -1300,11 +1305,17 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, sdres_tlvs_len = 0; while (offset < tlv_len) { + if (tlv_len - offset < 2) + break; type = tlv[0]; length = tlv[1]; + if (tlv_len - offset - 2 < length) + break; switch (type) { case LLCP_TLV_SDREQ: + if (length < 1) + break; tid = tlv[2]; service_name = (char *) &tlv[3]; service_name_len = length - 1; @@ -1369,6 +1380,8 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, break; case LLCP_TLV_SDRES: + if (length < 2) + break; mutex_lock(&local->sdreq_lock); pr_debug("LLCP_TLV_SDRES: searching tid %d\n", tlv[2]); -- 2.51.0