From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f51.google.com (mail-pj1-f51.google.com [209.85.216.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EB6C6374E6D for ; Fri, 10 Jul 2026 17:55:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.51 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783706115; cv=none; b=MjoSMpf/hB7WAfudb7N6n/wdJYgiUtJ1J0vls+Xkb7xgLZ87xzC3Cg0l+/y95jU5mNZ4WwlcJqOSWEDOeU+3IhTZ7zc6BRzFSTYb6e2B/77OM8pzAfsfpKv/ba5hIBsIel2w9ao7aCocLYw++toMm/4m4ZZtDQ8BNDR04oYRRV0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783706115; c=relaxed/simple; bh=q2Pq9v5SXGlcc93M8LKL/aV+CQ++fQMQq3HsJTaHEFo=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=WMEz0cjctcQ45v7eHvPhX/QVbShMT7MaMbg6mSHAJNVyGfXnt4xjlrBvpLMJq+8NmhaYThGUIyHJiHYCMir5Rm0tm5iaou0RVvlXwZKjXndRrjxOExLIMLLFZoYmuuRImpOY2N96+BDLF+JwZZSDh0mebTZ6j3g37t+yL8SWC9c= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hpOp5hP6; arc=none smtp.client-ip=209.85.216.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hpOp5hP6" Received: by mail-pj1-f51.google.com with SMTP id 98e67ed59e1d1-38101f85591so1757666a91.1 for ; Fri, 10 Jul 2026 10:55:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783706113; x=1784310913; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=g/g6IlAQtSI8doB/Bb8hhgXDYZeL8IDA7KJYnBAyAHU=; b=hpOp5hP6cRBd/LrQW2ksjdFVGQIfhOjdMt+y6NmfUg0B/EBx5pwnC2uoyBKs53pQbz +amXLV3QniFfNgIhrkeSg31DxJThsJil8et3b6DXhauIfQk+lTZ241ksfblHrW7UZoQV MCB2wuVyhYFANZxphVifp1GSgnYo8dQ6M6TizkX2sv6/datbAaUXmuw+imE0B7NZURiW 9SD22DklogXVZhN2gXoMldlX0Au+IOUXzk9nitBCJSDL8b6fS8fF/667o3DtFJWGjEwh seXjczxvU09ecYAx4n1E+hUOAJfidO2OMPphrGxvj81gsbM4jGixs0UpwcZnknxl3Zda NAKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783706113; x=1784310913; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=g/g6IlAQtSI8doB/Bb8hhgXDYZeL8IDA7KJYnBAyAHU=; b=bTj9k1hImUH+prWqnMo4N+ndJHoToMu9dRAzFDpnVntbWaG1YfBQUOnWF/Q6DKsNEl PJoKWsnL2324cSwavbvY7DBDIK1eDYh2kr062jpw//woYdp4xn1Bkz3POZ0G319iHhQh MqAcv+QmTTj5VNCVQ7b0GbceUTUhrcO2AmMxZPLkuQx0BPQtH2AzR0QJdtPqmXSCnxSL RwCa3XezY6H8Gdj4sEzPmMiZPDrWhP0zwrXQXyLthsRa3EeJ6fVuqgM97aZJsknRXh7u o9CH/Il9W5Zr7bkPan3QkFPfcmsDoaSo83qv2Njl8dylnIXLwXPd/gw0EIICVemx2np1 o1ww== X-Forwarded-Encrypted: i=1; AHgh+RqeH/hsdbGJN7YXzune0o1cnoWtgAU2tdrFeiAvuMUnzm/WtClOMcd/NieH+qNDds8CHWjrrmjv+m7eo5c=@vger.kernel.org X-Gm-Message-State: AOJu0YyIQRcP9CYhrmTDNO+hgX6dur9G35Bj1lha3ZwNmJmZTETRGoAF 7Qea0EicBM3Oh4RGXBdxgRTxC4aEKD/vVaCxW9BBJTPpvPPK+wzBgk8s X-Gm-Gg: AfdE7cnzTyMhhfvFnFH92Y14fUwJeGy5SkLgbXFxdf1x79kaL3gr6FgQ/E0o0Ei9QHb ZCHw1j/IOKDKKwCH+m+WdZEDZI1m5a2NXy+45ICchyCM+btrOzNHgU8pCo7JWUtm6nBOdAtS3UO rVQMBAJXZ15IDKb/LioPfxgNDCw49nbEkk3YtUxLSgndUOcZx0MhUUzCIjMWcS45rnIgXWSk27K cREtji/pYvMG1/FUCKYrnyaJPCBd+aHm3IZtTFrmCCAnK0yww2zvWaGDM5wMAGZIOlKE0pnSI45 XSgahyZ83GjbbX1jOB64UJ+2GGxvm1pZSph/d8te9jLwydYt8dH1g4zUvauInj1tSz+cpVBzeTc E9k/YufE0LlHACqJy9oBb7ebuKo2XJSWiI7PAUsInNvNofgaQEHUS8aZIA0HfhdVdaBmoEtF/Yg CKQuMPBbqzqp4C+fk9vefnyNOKpF6VHf0cfWdlKj/JN+bSFhBNo+xE8CCGS0KH87FyCbNY X-Received: by 2002:a17:90b:2401:b0:38d:9eda:fa04 with SMTP id 98e67ed59e1d1-38d9edafc8emr2029326a91.2.1783706113230; Fri, 10 Jul 2026 10:55:13 -0700 (PDT) Received: from fx.tailc0aff1.ts.net ([206.206.192.132]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-311747f596asm43051871eec.2.2026.07.10.10.55.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Jul 2026 10:55:12 -0700 (PDT) From: Weiming Shi To: David Heidelberg , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: oe-linux-nfc@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, xmei5@asu.edu, Weiming Shi Subject: [PATCH net] nfc: llcp: validate TLV length before parsing to fix OOB read Date: Fri, 10 Jul 2026 10:55:01 -0700 Message-ID: <20260710175500.2068564-2-bestswngs@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit nfc_llcp_parse_gb_tlv() and nfc_llcp_parse_connection_tlv() iterate over a TLV array supplied by the remote peer. Each iteration reads the type and length from tlv[0]/tlv[1] and then advances by length + 2, but the loop only tests offset < tlv_array_len and never checks that the 2-byte header fits in the remaining space. A truncated trailing entry is enough to read past the buffer on the tlv[1] access. The length byte then makes it worse. offset is a u8, so length + 2 wraps at 256: length == 0xff advances by 0x101 and leaves offset unchanged, so the loop stays live while tlv keeps moving forward. The parse walks well past the buffer, and the next iteration's tlv[0]/tlv[1] read lands out of bounds rather than the walk stopping one entry over. nfc_llcp_parse_gb_tlv() runs on the general bytes of an activated NFC-DEP link. An RF_INTF_ACTIVATED_NTF in listen mode reaches it via nci_ntf_packet() -> nfc_tm_activated() -> nfc_llcp_set_remote_gb(), which copies the peer's general bytes into the 48-byte remote_gb[] field of the heap-allocated struct nfc_llcp_local; the wrapped walk runs off the end of that allocation. nfc_llcp_parse_connection_tlv() is reached the same way from CONNECT/CC PDUs, over tlv data taken from the received skb. Bound each iteration to tlv_array_len before touching the header, and widen offset to u16 so the advance can no longer wrap. Well-formed TLVs are parsed as before; a malformed trailing entry ends the loop. BUG: KASAN: slab-out-of-bounds in nfc_llcp_parse_gb_tlv (net/nfc/llcp_commands.c:204) Read of size 1 by task kworker/u8:3 nfc_llcp_parse_gb_tlv (net/nfc/llcp_commands.c:204) nfc_llcp_set_remote_gb (net/nfc/llcp_core.c:681) nfc_tm_activated (net/nfc/core.c:643 net/nfc/core.c:677) nci_ntf_packet (net/nfc/nci/ntf.c:883 net/nfc/nci/ntf.c:1015) nci_rx_work (net/nfc/nci/core.c:1564) Fixes: d646960f7986 ("NFC: Initial LLCP support") Reported-by: Xiang Mei Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Weiming Shi --- net/nfc/llcp_commands.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index 291f26facbf3..3f0f8eef9890 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c @@ -193,17 +193,21 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local, const u8 *tlv_array, u16 tlv_array_len) { const u8 *tlv = tlv_array; - u8 type, length, offset = 0; + u8 type, length; + u16 offset = 0; pr_debug("TLV array length %d\n", tlv_array_len); if (local == NULL) return -ENODEV; - while (offset < tlv_array_len) { + while (offset + 2 <= tlv_array_len) { type = tlv[0]; length = tlv[1]; + if (offset + 2 + length > tlv_array_len) + break; + pr_debug("type 0x%x length %d\n", type, length); switch (type) { @@ -243,17 +247,21 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock, const u8 *tlv_array, u16 tlv_array_len) { const u8 *tlv = tlv_array; - u8 type, length, offset = 0; + u8 type, length; + u16 offset = 0; pr_debug("TLV array length %d\n", tlv_array_len); if (sock == NULL) return -ENOTCONN; - while (offset < tlv_array_len) { + while (offset + 2 <= tlv_array_len) { type = tlv[0]; length = tlv[1]; + if (offset + 2 + length > tlv_array_len) + break; + pr_debug("type 0x%x length %d\n", type, length); switch (type) { -- 2.43.0