From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-oo1-f69.google.com (mail-oo1-f69.google.com [209.85.161.69]) (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 DEE9F321434 for ; Wed, 18 Feb 2026 08:46:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.69 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771404407; cv=none; b=qeKAwecmVyViXhqi+O65JTHPp6nRsMcu5FvfmgIdmnw0IliDGy8C8Z3JVVNr72IYwjqDbQXCfAWJ2VKXc7KL2p9sMP5FQdG9UzLL9/lpozIaWI1q6WUJhUQKiX0CEG/9XZhhc49pr/LPyi5WKfEKJJUCrID8xA3ogO70JH15oMk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771404407; c=relaxed/simple; bh=xleAXSYgfldZ5Lo7QczBN3WcQaEFqdS4EuUbpH6Deac=; h=MIME-Version:Date:In-Reply-To:Message-ID:Subject:From:To: Content-Type; b=bMD4kznw0tQ+gDXteu5y8jLH7hYE5wShCHcok0uNKx0wh5pyBdCjfVEa90Ee0FbCNgmmzfbgqUdtBS506QwrzPWQ7Gvy+fHVwnjYSwn6NqeaI5V5RJXuo1+NgpOePXk7UAXCgzlgLrRGy9Uj09LkKOk0CS0KrIw5PrVql26t8CM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com; arc=none smtp.client-ip=209.85.161.69 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com Received: by mail-oo1-f69.google.com with SMTP id 006d021491bc7-662b9af3988so20803764eaf.1 for ; Wed, 18 Feb 2026 00:46:45 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771404405; x=1772009205; h=to:from:subject:message-id:in-reply-to:date:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=kxF1g1vH06EfdBFD0/8djcUu6pZptU2NflLbjF4KAhA=; b=DYD0BPidFtifRZ6ZBRfuWafjaPZhumGZbOlyRGXh7vydBWIlSf8ZTHn4FbA9Xd1ezJ GWml4O1woNa2cihldAs1uUKZvgPVG9WV0ygG72Bms/XBZ7S+/yt3WGiPXhP2qUhroX8K HIlndQ/CEZexHZ7he6SinD1q1FkY0Qg3yk9ZTU6JdMoj9NP86ZiH9/0yTHQCBazoG+B2 P7tEtvLGcbPs/RuXdtYWGJrnaQ3wG6BxnBiRJ2EagET0s7+DjeF9qH0wXCSJmhoNPbUX 086gfh76wdssqMI8t/8ukXSHdWIwHYJSoZs7nOoWos2Im/YEj0YJecQZo4lzDOZTUxXT UqUg== X-Gm-Message-State: AOJu0YxESl96dRWyK5OVhyaV7GPVIg1mmFPsDOhaf67C9LnEtppdcvul 3eQwFJs60wj2+/CcYBCkWsocOvsxHqgmSSq8+ZGzZj0A4olGozTh8GUz9SaS9gVJMjoyFKpOfqU TbseAdsi7QPWf2x2QF6YLGdviO9SoBXQto+3os8X6BMAgfue4yVHKmoqcY3Y= Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Received: by 2002:a05:6820:981:b0:672:9b05:1ad0 with SMTP id 006d021491bc7-679a73f88f6mr642419eaf.37.1771404404949; Wed, 18 Feb 2026 00:46:44 -0800 (PST) Date: Wed, 18 Feb 2026 00:46:44 -0800 In-Reply-To: <6894dce2.050a0220.7f033.0049.GAE@google.com> X-Google-Appengine-App-Id: s~syzkaller X-Google-Appengine-App-Id-Alias: syzkaller Message-ID: <69957c74.a70a0220.2c38d7.011a.GAE@google.com> Subject: Forwarded: Re: [PATCH net v6] net: nfc: nci: Fix parameter validation for packet data From: syzbot To: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com Content-Type: text/plain; charset="UTF-8" For archival purposes, forwarding an incoming command email to linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com. *** Subject: Re: [PATCH net v6] net: nfc: nci: Fix parameter validation for packet data Author: krzk@kernel.org On 18/02/2026 09:30, Michael Thalmeier wrote: > Since commit 9c328f54741b ("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: 9c328f54741b ("net: nfc: nci: Add parameter validation for packet data") Reported-by: syzbot+740e04c2a93467a0f8c8@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=740e04c2a93467a0f8c8 #syz unfix > Cc: stable@vger.kernel.org > Signed-off-by: Michael Thalmeier > --- > v6: > - use ssize_t for data_len parameter to guard against underflows > - omit unneeded data_len decrements at the end of the functions > > v5: > - also check helper functions in nci_extract_rf_params_nfcf_passive_listen > and nci_rf_discover_ntf_packet > > v4: > - formatting fixes > > v3: > - perform complete checks > - replace magic numbers with offsetofend and sizeof > > v2: > - Reference correct commit hash > > --- > net/nfc/nci/ntf.c | 159 ++++++++++++++++++++++++++++++++++++++++------ > 1 file changed, 141 insertions(+), 18 deletions(-) > > diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c > index 418b84e2b260..c96512bb8653 100644 > --- a/net/nfc/nci/ntf.c > +++ b/net/nfc/nci/ntf.c > @@ -58,7 +58,7 @@ static int nci_core_conn_credits_ntf_packet(struct nci_dev *ndev, > struct nci_conn_info *conn_info; > int i; > > - if (skb->len < sizeof(struct nci_core_conn_credit_ntf)) > + if (skb->len < offsetofend(struct nci_core_conn_credit_ntf, num_entries)) > return -EINVAL; > > 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, > if (ntf->num_entries > NCI_MAX_NUM_CONN) > ntf->num_entries = NCI_MAX_NUM_CONN; > > + if (skb->len < offsetofend(struct nci_core_conn_credit_ntf, num_entries) + > + ntf->num_entries * sizeof(struct conn_credit_entry)) > + return -EINVAL; > + > /* update the credits */ > for (i = 0; i < ntf->num_entries; i++) { > ntf->conn_entries[i].conn_id = > @@ -138,23 +142,48 @@ static int nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev, > static const __u8 * > nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, > struct rf_tech_specific_params_nfca_poll *nfca_poll, > - const __u8 *data) > + const __u8 *data, ssize_t data_len) > { > + /* Check if we have enough data for sens_res (2 bytes) */ > + if (data_len < 2) > + return ERR_PTR(-EINVAL); > + > nfca_poll->sens_res = __le16_to_cpu(*((__le16 *)data)); > data += 2; > + data_len -= 2; > + > + /* Check if we have enough data for nfcid1_len (1 byte) */ > + if (data_len < 1) > + return ERR_PTR(-EINVAL); > > nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE); > + data_len--; > > pr_debug("sens_res 0x%x, nfcid1_len %d\n", > nfca_poll->sens_res, nfca_poll->nfcid1_len); > > + /* Check if we have enough data for nfcid1 */ > + if (data_len < nfca_poll->nfcid1_len) > + return ERR_PTR(-EINVAL); > + > memcpy(nfca_poll->nfcid1, data, nfca_poll->nfcid1_len); > data += nfca_poll->nfcid1_len; > + data_len -= nfca_poll->nfcid1_len; > + > + /* Check if we have enough data for sel_res_len (1 byte) */ > + if (data_len < 1) > + return ERR_PTR(-EINVAL); > > nfca_poll->sel_res_len = *data++; > + data_len--; > + > + if (nfca_poll->sel_res_len != 0) { > + /* Check if we have enough data for sel_res (1 byte) */ > + if (data_len < 1) > + return ERR_PTR(-EINVAL); > > - if (nfca_poll->sel_res_len != 0) > nfca_poll->sel_res = *data++; > + } > > pr_debug("sel_res_len %d, sel_res 0x%x\n", > nfca_poll->sel_res_len, > @@ -166,12 +195,21 @@ nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, > static const __u8 * > nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, > struct rf_tech_specific_params_nfcb_poll *nfcb_poll, > - const __u8 *data) > + const __u8 *data, ssize_t data_len) > { > + /* Check if we have enough data for sensb_res_len (1 byte) */ > + if (data_len < 1) > + return ERR_PTR(-EINVAL); > + > nfcb_poll->sensb_res_len = min_t(__u8, *data++, NFC_SENSB_RES_MAXSIZE); > + data_len--; > > pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len); > > + /* Check if we have enough data for sensb_res */ > + if (data_len < nfcb_poll->sensb_res_len) > + return ERR_PTR(-EINVAL); > + > memcpy(nfcb_poll->sensb_res, data, nfcb_poll->sensb_res_len); > data += nfcb_poll->sensb_res_len; > > @@ -181,14 +219,29 @@ nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, > static const __u8 * > nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, > struct rf_tech_specific_params_nfcf_poll *nfcf_poll, > - const __u8 *data) > + const __u8 *data, ssize_t data_len) > { > + /* Check if we have enough data for bit_rate (1 byte) */ > + if (data_len < 1) > + return ERR_PTR(-EINVAL); > + > nfcf_poll->bit_rate = *data++; > + data_len--; > + > + /* Check if we have enough data for sensf_res_len (1 byte) */ > + if (data_len < 1) > + return ERR_PTR(-EINVAL); > + > nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE); > + data_len--; > > pr_debug("bit_rate %d, sensf_res_len %d\n", > nfcf_poll->bit_rate, nfcf_poll->sensf_res_len); > > + /* Check if we have enough data for sensf_res */ > + if (data_len < nfcf_poll->sensf_res_len) > + return ERR_PTR(-EINVAL); > + > memcpy(nfcf_poll->sensf_res, data, nfcf_poll->sensf_res_len); > data += nfcf_poll->sensf_res_len; > > @@ -198,22 +251,49 @@ nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, > static const __u8 * > nci_extract_rf_params_nfcv_passive_poll(struct nci_dev *ndev, > struct rf_tech_specific_params_nfcv_poll *nfcv_poll, > - const __u8 *data) > + const __u8 *data, ssize_t data_len) > { > + /* Skip 1 byte (reserved) */ > + if (data_len < 1) > + return ERR_PTR(-EINVAL); > + > ++data; > + data_len--; > + > + /* Check if we have enough data for dsfid (1 byte) */ > + if (data_len < 1) > + return ERR_PTR(-EINVAL); > + > nfcv_poll->dsfid = *data++; > + data_len--; > + > + /* Check if we have enough data for uid (8 bytes) */ > + if (data_len < NFC_ISO15693_UID_MAXSIZE) > + return ERR_PTR(-EINVAL); > + > memcpy(nfcv_poll->uid, data, NFC_ISO15693_UID_MAXSIZE); > data += NFC_ISO15693_UID_MAXSIZE; > + > return data; > } > > static const __u8 * > nci_extract_rf_params_nfcf_passive_listen(struct nci_dev *ndev, > struct rf_tech_specific_params_nfcf_listen *nfcf_listen, > - const __u8 *data) > + const __u8 *data, ssize_t data_len) > { > + /* Check if we have enough data for local_nfcid2_len (1 byte) */ > + if (data_len < 1) > + return ERR_PTR(-EINVAL); > + > nfcf_listen->local_nfcid2_len = min_t(__u8, *data++, > NFC_NFCID2_MAXSIZE); > + data_len--; > + > + /* Check if we have enough data for local_nfcid2 */ > + if (data_len < nfcf_listen->local_nfcid2_len) > + return ERR_PTR(-EINVAL); > + > memcpy(nfcf_listen->local_nfcid2, data, nfcf_listen->local_nfcid2_len); > data += nfcf_listen->local_nfcid2_len; > > @@ -364,7 +444,7 @@ static int nci_rf_discover_ntf_packet(struct nci_dev *ndev, > const __u8 *data; > bool add_target = true; > > - if (skb->len < sizeof(struct nci_rf_discover_ntf)) > + if (skb->len < offsetofend(struct nci_rf_discover_ntf, rf_tech_specific_params_len)) > return -EINVAL; > > data = skb->data; > @@ -380,26 +460,42 @@ static int nci_rf_discover_ntf_packet(struct nci_dev *ndev, > pr_debug("rf_tech_specific_params_len %d\n", > ntf.rf_tech_specific_params_len); > > + if (skb->len < (data - skb->data) + > + ntf.rf_tech_specific_params_len + sizeof(ntf.ntf_type)) > + return -EINVAL; > + > if (ntf.rf_tech_specific_params_len > 0) { > switch (ntf.rf_tech_and_mode) { > case NCI_NFC_A_PASSIVE_POLL_MODE: > data = nci_extract_rf_params_nfca_passive_poll(ndev, > - &(ntf.rf_tech_specific_params.nfca_poll), data); > + &(ntf.rf_tech_specific_params.nfca_poll), data, > + ntf.rf_tech_specific_params_len); > + if (IS_ERR(data)) > + return PTR_ERR(data); > break; > > case NCI_NFC_B_PASSIVE_POLL_MODE: > data = nci_extract_rf_params_nfcb_passive_poll(ndev, > - &(ntf.rf_tech_specific_params.nfcb_poll), data); > + &(ntf.rf_tech_specific_params.nfcb_poll), data, > + ntf.rf_tech_specific_params_len); > + if (IS_ERR(data)) > + return PTR_ERR(data); > break; > > case NCI_NFC_F_PASSIVE_POLL_MODE: > data = nci_extract_rf_params_nfcf_passive_poll(ndev, > - &(ntf.rf_tech_specific_params.nfcf_poll), data); > + &(ntf.rf_tech_specific_params.nfcf_poll), data, > + ntf.rf_tech_specific_params_len); > + if (IS_ERR(data)) > + return PTR_ERR(data); > break; > > case NCI_NFC_V_PASSIVE_POLL_MODE: > data = nci_extract_rf_params_nfcv_passive_poll(ndev, > - &(ntf.rf_tech_specific_params.nfcv_poll), data); > + &(ntf.rf_tech_specific_params.nfcv_poll), data, > + ntf.rf_tech_specific_params_len); > + if (IS_ERR(data)) > + return PTR_ERR(data); > break; > > default: > @@ -596,7 +692,7 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, > const __u8 *data; > int err = NCI_STATUS_OK; > > - if (skb->len < sizeof(struct nci_rf_intf_activated_ntf)) > + if (skb->len < offsetofend(struct nci_rf_intf_activated_ntf, rf_tech_specific_params_len)) > return -EINVAL; > > data = skb->data; > @@ -628,26 +724,41 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, > if (ntf.rf_interface == NCI_RF_INTERFACE_NFCEE_DIRECT) > goto listen; > > + if (skb->len < (data - skb->data) + ntf.rf_tech_specific_params_len) > + return -EINVAL; > + > if (ntf.rf_tech_specific_params_len > 0) { > switch (ntf.activation_rf_tech_and_mode) { > case NCI_NFC_A_PASSIVE_POLL_MODE: > data = nci_extract_rf_params_nfca_passive_poll(ndev, > - &(ntf.rf_tech_specific_params.nfca_poll), data); > + &(ntf.rf_tech_specific_params.nfca_poll), data, > + ntf.rf_tech_specific_params_len); > + if (IS_ERR(data)) > + return -EINVAL; > break; > > case NCI_NFC_B_PASSIVE_POLL_MODE: > data = nci_extract_rf_params_nfcb_passive_poll(ndev, > - &(ntf.rf_tech_specific_params.nfcb_poll), data); > + &(ntf.rf_tech_specific_params.nfcb_poll), data, > + ntf.rf_tech_specific_params_len); > + if (IS_ERR(data)) > + return -EINVAL; > break; > > case NCI_NFC_F_PASSIVE_POLL_MODE: > data = nci_extract_rf_params_nfcf_passive_poll(ndev, > - &(ntf.rf_tech_specific_params.nfcf_poll), data); > + &(ntf.rf_tech_specific_params.nfcf_poll), data, > + ntf.rf_tech_specific_params_len); > + if (IS_ERR(data)) > + return -EINVAL; > break; > > case NCI_NFC_V_PASSIVE_POLL_MODE: > data = nci_extract_rf_params_nfcv_passive_poll(ndev, > - &(ntf.rf_tech_specific_params.nfcv_poll), data); > + &(ntf.rf_tech_specific_params.nfcv_poll), data, > + ntf.rf_tech_specific_params_len); > + if (IS_ERR(data)) > + return -EINVAL; > break; > > case NCI_NFC_A_PASSIVE_LISTEN_MODE: > @@ -657,7 +768,9 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, > case NCI_NFC_F_PASSIVE_LISTEN_MODE: > data = nci_extract_rf_params_nfcf_passive_listen(ndev, > &(ntf.rf_tech_specific_params.nfcf_listen), > - data); > + data, ntf.rf_tech_specific_params_len); > + if (IS_ERR(data)) > + return -EINVAL; > break; > > default: > @@ -668,6 +781,13 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, > } > } > > + if (skb->len < (data - skb->data) + > + sizeof(ntf.data_exch_rf_tech_and_mode) + > + sizeof(ntf.data_exch_tx_bit_rate) + > + sizeof(ntf.data_exch_rx_bit_rate) + > + sizeof(ntf.activation_params_len)) > + return -EINVAL; > + > ntf.data_exch_rf_tech_and_mode = *data++; > ntf.data_exch_tx_bit_rate = *data++; > ntf.data_exch_rx_bit_rate = *data++; > @@ -679,6 +799,9 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, > pr_debug("data_exch_rx_bit_rate 0x%x\n", ntf.data_exch_rx_bit_rate); > pr_debug("activation_params_len %d\n", ntf.activation_params_len); > > + if (skb->len < (data - skb->data) + ntf.activation_params_len) > + return -EINVAL; > + > if (ntf.activation_params_len > 0) { > switch (ntf.rf_interface) { > case NCI_RF_INTERFACE_ISO_DEP: Best regards, Krzysztof