Skip to content

Commit 3b91160

Browse files
mthalmeiSasha Levin
authored andcommitted
net: nfc: nci: Fix parameter validation for packet data
[ Upstream commit 571dcbe ] Since commit 9c328f5 ("net: nfc: nci: Add parameter validation for packet data") communication with nci nfc chips is not working any more. The mentioned commit tries to fix access of uninitialized data, but failed to understand that in some cases the data packet is of variable length and can therefore not be compared to the maximum packet length given by the sizeof(struct). Fixes: 9c328f5 ("net: nfc: nci: Add parameter validation for packet data") Cc: stable@vger.kernel.org Signed-off-by: Michael Thalmeier <michael.thalmeier@hale.at> Reported-by: syzbot+740e04c2a93467a0f8c8@syzkaller.appspotmail.com Link: https://patch.msgid.link/20260218083000.301354-1-michael.thalmeier@hale.at Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent bd13585 commit 3b91160

1 file changed

Lines changed: 141 additions & 18 deletions

File tree

net/nfc/nci/ntf.c

Lines changed: 141 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static int nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
5858
struct nci_conn_info *conn_info;
5959
int i;
6060

61-
if (skb->len < sizeof(struct nci_core_conn_credit_ntf))
61+
if (skb->len < offsetofend(struct nci_core_conn_credit_ntf, num_entries))
6262
return -EINVAL;
6363

6464
ntf = (struct nci_core_conn_credit_ntf *)skb->data;
@@ -68,6 +68,10 @@ static int nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
6868
if (ntf->num_entries > NCI_MAX_NUM_CONN)
6969
ntf->num_entries = NCI_MAX_NUM_CONN;
7070

71+
if (skb->len < offsetofend(struct nci_core_conn_credit_ntf, num_entries) +
72+
ntf->num_entries * sizeof(struct conn_credit_entry))
73+
return -EINVAL;
74+
7175
/* update the credits */
7276
for (i = 0; i < ntf->num_entries; i++) {
7377
ntf->conn_entries[i].conn_id =
@@ -138,23 +142,48 @@ static int nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev,
138142
static const __u8 *
139143
nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
140144
struct rf_tech_specific_params_nfca_poll *nfca_poll,
141-
const __u8 *data)
145+
const __u8 *data, ssize_t data_len)
142146
{
147+
/* Check if we have enough data for sens_res (2 bytes) */
148+
if (data_len < 2)
149+
return ERR_PTR(-EINVAL);
150+
143151
nfca_poll->sens_res = __le16_to_cpu(*((__le16 *)data));
144152
data += 2;
153+
data_len -= 2;
154+
155+
/* Check if we have enough data for nfcid1_len (1 byte) */
156+
if (data_len < 1)
157+
return ERR_PTR(-EINVAL);
145158

146159
nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE);
160+
data_len--;
147161

148162
pr_debug("sens_res 0x%x, nfcid1_len %d\n",
149163
nfca_poll->sens_res, nfca_poll->nfcid1_len);
150164

165+
/* Check if we have enough data for nfcid1 */
166+
if (data_len < nfca_poll->nfcid1_len)
167+
return ERR_PTR(-EINVAL);
168+
151169
memcpy(nfca_poll->nfcid1, data, nfca_poll->nfcid1_len);
152170
data += nfca_poll->nfcid1_len;
171+
data_len -= nfca_poll->nfcid1_len;
172+
173+
/* Check if we have enough data for sel_res_len (1 byte) */
174+
if (data_len < 1)
175+
return ERR_PTR(-EINVAL);
153176

154177
nfca_poll->sel_res_len = *data++;
178+
data_len--;
179+
180+
if (nfca_poll->sel_res_len != 0) {
181+
/* Check if we have enough data for sel_res (1 byte) */
182+
if (data_len < 1)
183+
return ERR_PTR(-EINVAL);
155184

156-
if (nfca_poll->sel_res_len != 0)
157185
nfca_poll->sel_res = *data++;
186+
}
158187

159188
pr_debug("sel_res_len %d, sel_res 0x%x\n",
160189
nfca_poll->sel_res_len,
@@ -166,12 +195,21 @@ nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
166195
static const __u8 *
167196
nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev,
168197
struct rf_tech_specific_params_nfcb_poll *nfcb_poll,
169-
const __u8 *data)
198+
const __u8 *data, ssize_t data_len)
170199
{
200+
/* Check if we have enough data for sensb_res_len (1 byte) */
201+
if (data_len < 1)
202+
return ERR_PTR(-EINVAL);
203+
171204
nfcb_poll->sensb_res_len = min_t(__u8, *data++, NFC_SENSB_RES_MAXSIZE);
205+
data_len--;
172206

173207
pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len);
174208

209+
/* Check if we have enough data for sensb_res */
210+
if (data_len < nfcb_poll->sensb_res_len)
211+
return ERR_PTR(-EINVAL);
212+
175213
memcpy(nfcb_poll->sensb_res, data, nfcb_poll->sensb_res_len);
176214
data += nfcb_poll->sensb_res_len;
177215

@@ -181,14 +219,29 @@ nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev,
181219
static const __u8 *
182220
nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev,
183221
struct rf_tech_specific_params_nfcf_poll *nfcf_poll,
184-
const __u8 *data)
222+
const __u8 *data, ssize_t data_len)
185223
{
224+
/* Check if we have enough data for bit_rate (1 byte) */
225+
if (data_len < 1)
226+
return ERR_PTR(-EINVAL);
227+
186228
nfcf_poll->bit_rate = *data++;
229+
data_len--;
230+
231+
/* Check if we have enough data for sensf_res_len (1 byte) */
232+
if (data_len < 1)
233+
return ERR_PTR(-EINVAL);
234+
187235
nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE);
236+
data_len--;
188237

189238
pr_debug("bit_rate %d, sensf_res_len %d\n",
190239
nfcf_poll->bit_rate, nfcf_poll->sensf_res_len);
191240

241+
/* Check if we have enough data for sensf_res */
242+
if (data_len < nfcf_poll->sensf_res_len)
243+
return ERR_PTR(-EINVAL);
244+
192245
memcpy(nfcf_poll->sensf_res, data, nfcf_poll->sensf_res_len);
193246
data += nfcf_poll->sensf_res_len;
194247

@@ -198,22 +251,49 @@ nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev,
198251
static const __u8 *
199252
nci_extract_rf_params_nfcv_passive_poll(struct nci_dev *ndev,
200253
struct rf_tech_specific_params_nfcv_poll *nfcv_poll,
201-
const __u8 *data)
254+
const __u8 *data, ssize_t data_len)
202255
{
256+
/* Skip 1 byte (reserved) */
257+
if (data_len < 1)
258+
return ERR_PTR(-EINVAL);
259+
203260
++data;
261+
data_len--;
262+
263+
/* Check if we have enough data for dsfid (1 byte) */
264+
if (data_len < 1)
265+
return ERR_PTR(-EINVAL);
266+
204267
nfcv_poll->dsfid = *data++;
268+
data_len--;
269+
270+
/* Check if we have enough data for uid (8 bytes) */
271+
if (data_len < NFC_ISO15693_UID_MAXSIZE)
272+
return ERR_PTR(-EINVAL);
273+
205274
memcpy(nfcv_poll->uid, data, NFC_ISO15693_UID_MAXSIZE);
206275
data += NFC_ISO15693_UID_MAXSIZE;
276+
207277
return data;
208278
}
209279

210280
static const __u8 *
211281
nci_extract_rf_params_nfcf_passive_listen(struct nci_dev *ndev,
212282
struct rf_tech_specific_params_nfcf_listen *nfcf_listen,
213-
const __u8 *data)
283+
const __u8 *data, ssize_t data_len)
214284
{
285+
/* Check if we have enough data for local_nfcid2_len (1 byte) */
286+
if (data_len < 1)
287+
return ERR_PTR(-EINVAL);
288+
215289
nfcf_listen->local_nfcid2_len = min_t(__u8, *data++,
216290
NFC_NFCID2_MAXSIZE);
291+
data_len--;
292+
293+
/* Check if we have enough data for local_nfcid2 */
294+
if (data_len < nfcf_listen->local_nfcid2_len)
295+
return ERR_PTR(-EINVAL);
296+
217297
memcpy(nfcf_listen->local_nfcid2, data, nfcf_listen->local_nfcid2_len);
218298
data += nfcf_listen->local_nfcid2_len;
219299

@@ -364,7 +444,7 @@ static int nci_rf_discover_ntf_packet(struct nci_dev *ndev,
364444
const __u8 *data;
365445
bool add_target = true;
366446

367-
if (skb->len < sizeof(struct nci_rf_discover_ntf))
447+
if (skb->len < offsetofend(struct nci_rf_discover_ntf, rf_tech_specific_params_len))
368448
return -EINVAL;
369449

370450
data = skb->data;
@@ -380,26 +460,42 @@ static int nci_rf_discover_ntf_packet(struct nci_dev *ndev,
380460
pr_debug("rf_tech_specific_params_len %d\n",
381461
ntf.rf_tech_specific_params_len);
382462

463+
if (skb->len < (data - skb->data) +
464+
ntf.rf_tech_specific_params_len + sizeof(ntf.ntf_type))
465+
return -EINVAL;
466+
383467
if (ntf.rf_tech_specific_params_len > 0) {
384468
switch (ntf.rf_tech_and_mode) {
385469
case NCI_NFC_A_PASSIVE_POLL_MODE:
386470
data = nci_extract_rf_params_nfca_passive_poll(ndev,
387-
&(ntf.rf_tech_specific_params.nfca_poll), data);
471+
&(ntf.rf_tech_specific_params.nfca_poll), data,
472+
ntf.rf_tech_specific_params_len);
473+
if (IS_ERR(data))
474+
return PTR_ERR(data);
388475
break;
389476

390477
case NCI_NFC_B_PASSIVE_POLL_MODE:
391478
data = nci_extract_rf_params_nfcb_passive_poll(ndev,
392-
&(ntf.rf_tech_specific_params.nfcb_poll), data);
479+
&(ntf.rf_tech_specific_params.nfcb_poll), data,
480+
ntf.rf_tech_specific_params_len);
481+
if (IS_ERR(data))
482+
return PTR_ERR(data);
393483
break;
394484

395485
case NCI_NFC_F_PASSIVE_POLL_MODE:
396486
data = nci_extract_rf_params_nfcf_passive_poll(ndev,
397-
&(ntf.rf_tech_specific_params.nfcf_poll), data);
487+
&(ntf.rf_tech_specific_params.nfcf_poll), data,
488+
ntf.rf_tech_specific_params_len);
489+
if (IS_ERR(data))
490+
return PTR_ERR(data);
398491
break;
399492

400493
case NCI_NFC_V_PASSIVE_POLL_MODE:
401494
data = nci_extract_rf_params_nfcv_passive_poll(ndev,
402-
&(ntf.rf_tech_specific_params.nfcv_poll), data);
495+
&(ntf.rf_tech_specific_params.nfcv_poll), data,
496+
ntf.rf_tech_specific_params_len);
497+
if (IS_ERR(data))
498+
return PTR_ERR(data);
403499
break;
404500

405501
default:
@@ -574,7 +670,7 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
574670
const __u8 *data;
575671
int err = NCI_STATUS_OK;
576672

577-
if (skb->len < sizeof(struct nci_rf_intf_activated_ntf))
673+
if (skb->len < offsetofend(struct nci_rf_intf_activated_ntf, rf_tech_specific_params_len))
578674
return -EINVAL;
579675

580676
data = skb->data;
@@ -606,26 +702,41 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
606702
if (ntf.rf_interface == NCI_RF_INTERFACE_NFCEE_DIRECT)
607703
goto listen;
608704

705+
if (skb->len < (data - skb->data) + ntf.rf_tech_specific_params_len)
706+
return -EINVAL;
707+
609708
if (ntf.rf_tech_specific_params_len > 0) {
610709
switch (ntf.activation_rf_tech_and_mode) {
611710
case NCI_NFC_A_PASSIVE_POLL_MODE:
612711
data = nci_extract_rf_params_nfca_passive_poll(ndev,
613-
&(ntf.rf_tech_specific_params.nfca_poll), data);
712+
&(ntf.rf_tech_specific_params.nfca_poll), data,
713+
ntf.rf_tech_specific_params_len);
714+
if (IS_ERR(data))
715+
return -EINVAL;
614716
break;
615717

616718
case NCI_NFC_B_PASSIVE_POLL_MODE:
617719
data = nci_extract_rf_params_nfcb_passive_poll(ndev,
618-
&(ntf.rf_tech_specific_params.nfcb_poll), data);
720+
&(ntf.rf_tech_specific_params.nfcb_poll), data,
721+
ntf.rf_tech_specific_params_len);
722+
if (IS_ERR(data))
723+
return -EINVAL;
619724
break;
620725

621726
case NCI_NFC_F_PASSIVE_POLL_MODE:
622727
data = nci_extract_rf_params_nfcf_passive_poll(ndev,
623-
&(ntf.rf_tech_specific_params.nfcf_poll), data);
728+
&(ntf.rf_tech_specific_params.nfcf_poll), data,
729+
ntf.rf_tech_specific_params_len);
730+
if (IS_ERR(data))
731+
return -EINVAL;
624732
break;
625733

626734
case NCI_NFC_V_PASSIVE_POLL_MODE:
627735
data = nci_extract_rf_params_nfcv_passive_poll(ndev,
628-
&(ntf.rf_tech_specific_params.nfcv_poll), data);
736+
&(ntf.rf_tech_specific_params.nfcv_poll), data,
737+
ntf.rf_tech_specific_params_len);
738+
if (IS_ERR(data))
739+
return -EINVAL;
629740
break;
630741

631742
case NCI_NFC_A_PASSIVE_LISTEN_MODE:
@@ -635,7 +746,9 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
635746
case NCI_NFC_F_PASSIVE_LISTEN_MODE:
636747
data = nci_extract_rf_params_nfcf_passive_listen(ndev,
637748
&(ntf.rf_tech_specific_params.nfcf_listen),
638-
data);
749+
data, ntf.rf_tech_specific_params_len);
750+
if (IS_ERR(data))
751+
return -EINVAL;
639752
break;
640753

641754
default:
@@ -646,6 +759,13 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
646759
}
647760
}
648761

762+
if (skb->len < (data - skb->data) +
763+
sizeof(ntf.data_exch_rf_tech_and_mode) +
764+
sizeof(ntf.data_exch_tx_bit_rate) +
765+
sizeof(ntf.data_exch_rx_bit_rate) +
766+
sizeof(ntf.activation_params_len))
767+
return -EINVAL;
768+
649769
ntf.data_exch_rf_tech_and_mode = *data++;
650770
ntf.data_exch_tx_bit_rate = *data++;
651771
ntf.data_exch_rx_bit_rate = *data++;
@@ -657,6 +777,9 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
657777
pr_debug("data_exch_rx_bit_rate 0x%x\n", ntf.data_exch_rx_bit_rate);
658778
pr_debug("activation_params_len %d\n", ntf.activation_params_len);
659779

780+
if (skb->len < (data - skb->data) + ntf.activation_params_len)
781+
return -EINVAL;
782+
660783
if (ntf.activation_params_len > 0) {
661784
switch (ntf.rf_interface) {
662785
case NCI_RF_INTERFACE_ISO_DEP:

0 commit comments

Comments
 (0)