Skip to content

Commit a209334

Browse files
Muhammad Bilalgregkh
authored andcommitted
nfc: llcp: fix OOB read and u8 offset wrap in TLV parsers
commit 78b20c8 upstream. nfc_llcp_parse_gb_tlv() and nfc_llcp_parse_connection_tlv() contain three related bugs in their TLV parsing loops: 1. 'offset' is declared u8 but tlv_array_len is u16. When TLV data advances offset past 255 it silently wraps to zero, causing infinite loops or double-processing of buffer data. 2. Before reading tlv[0] (type) and tlv[1] (length) there is no check that offset+2 <= tlv_array_len. A truncated TLV causes an OOB read of one byte past the buffer end. 3. After reading the length field, the value bytes are accessed without checking offset+2+length <= tlv_array_len. A crafted length=0xFF on a short buffer causes up to 255 bytes of OOB read past the buffer end. Both functions are reachable without authentication via nfc_llcp_set_remote_gb() which feeds remote LLCP general bytes directly into nfc_llcp_parse_gb_tlv() with no additional validation. Fix all three issues by widening offset from u8 to u16 and adding bounds checks for both the TLV header and value field before each access. Fixes: 3df40eb ("nfc: constify several pointers to u8, char and sk_buff") Cc: stable@vger.kernel.org Signed-off-by: Muhammad Bilal <meatuni001@gmail.com> Reviewed-by: Simon Horman <horms@kernel.org> Link: https://patch.msgid.link/20260622131802.239035-1-meatuni001@gmail.com Signed-off-by: David Heidelberg <david@ixit.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 1964add commit a209334

1 file changed

Lines changed: 16 additions & 2 deletions

File tree

net/nfc/llcp_commands.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,24 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
193193
const u8 *tlv_array, u16 tlv_array_len)
194194
{
195195
const u8 *tlv = tlv_array;
196-
u8 type, length, offset = 0;
196+
u8 type, length;
197+
u16 offset = 0;
197198

198199
pr_debug("TLV array length %d\n", tlv_array_len);
199200

200201
if (local == NULL)
201202
return -ENODEV;
202203

203204
while (offset < tlv_array_len) {
205+
if (offset + 2 > tlv_array_len)
206+
return -EINVAL;
207+
204208
type = tlv[0];
205209
length = tlv[1];
206210

211+
if (offset + 2 + length > tlv_array_len)
212+
return -EINVAL;
213+
207214
pr_debug("type 0x%x length %d\n", type, length);
208215

209216
switch (type) {
@@ -243,17 +250,24 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
243250
const u8 *tlv_array, u16 tlv_array_len)
244251
{
245252
const u8 *tlv = tlv_array;
246-
u8 type, length, offset = 0;
253+
u8 type, length;
254+
u16 offset = 0;
247255

248256
pr_debug("TLV array length %d\n", tlv_array_len);
249257

250258
if (sock == NULL)
251259
return -ENOTCONN;
252260

253261
while (offset < tlv_array_len) {
262+
if (offset + 2 > tlv_array_len)
263+
return -EINVAL;
264+
254265
type = tlv[0];
255266
length = tlv[1];
256267

268+
if (offset + 2 + length > tlv_array_len)
269+
return -EINVAL;
270+
257271
pr_debug("type 0x%x length %d\n", type, length);
258272

259273
switch (type) {

0 commit comments

Comments
 (0)