From: Simon Horman <horms@kernel.org>
To: Liu Chao <liuc63@xiaopeng.com>
Cc: netdev@vger.kernel.org, david@ixit.cz, davem@davemloft.net,
edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
oe-linux-nfc@lists.linux.dev, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Subject: Re: [PATCH net v3] nfc: nci: avoid unbounded skb allocation when max_pkt_payload_len is zero
Date: Mon, 28 Sep 2026 11:48:09 +0100 [thread overview]
Message-ID: <20260928104809.GQ13925@horms.kernel.org> (raw)
In-Reply-To: <20260927115940.3817019-1-liuc63@xiaopeng.com>
On Sun, Sep 27, 2026 at 07:59:40PM +0800, Liu Chao wrote:
> nci_queue_tx_data_frags() uses conn_info->max_pkt_payload_len as the
> fragment size. When that value is zero, frag_len is always zero and
> total_len never decreases. The loop then allocates skbs without bound:
> none of them are freed inside the loop, they accumulate on frags_q, and
> there is no cond_resched() in the loop body. A single sendmsg() can
> therefore consume all allocatable memory, and on CONFIG_PREEMPT_NONE it
> occupies the CPU long enough to trip the softlockup watchdog:
>
> watchdog: BUG: soft lockup - CPU#3 stuck for 26s! [kworker/3:1:57]
> Workqueue: events rawsock_tx_work [nfc]
> Call Trace:
> nci_send_data+0x1ca/0x6b0 [nci]
> nci_transceive+0xbb/0x170 [nci]
> rawsock_tx_work+0xb5/0x1a0 [nfc]
>
> max_pkt_payload_len comes straight from controller-supplied fields with
> no check for zero, and it is read several times along the TX path while
> the rx workqueue can update it without any lock held against this path.
>
> Take a single READ_ONCE() snapshot of the limit in nci_send_data(),
> reject a zero limit there, and pass the snapshot down to
> nci_queue_tx_data_frags(). The fragmentation decision and the
> fragmentation loop then consume the same value, so the loop cannot spin
> on a limit that differs from the one just validated, and no plain read
> of the field is left in nci_send_data() or nci_queue_tx_data_frags().
>
> Rejecting the zero limit at the entry of the TX data path covers the RF
> connection as well: ndev->rf_conn_info is allocated with devm_kzalloc(),
> so its max_pkt_payload_len is zero from the moment the object exists and
> only becomes usable when an activation notification assigns a
> controller-supplied value. Checking where the value is consumed catches
> every producer of a zero limit -- the initial state, the notification,
> and any future writer.
>
> The two producers of the field are annotated with WRITE_ONCE() to match
> the snapshot read; the remaining plain accesses on the HCI path are
> untouched here, since nci_hci_send_data() loops over a different
> conn_info instance (ndev->hci_dev->conn_info) and needs its own fix,
> which is sent separately.
>
> The "failed to fragment tx data packet" print sits on a data path driven
> by controller/remote data and can fire on every transmit once
> fragmentation keeps failing. Rate-limit it so a misbehaving controller
> cannot flood the log. Note that with the zero-limit rejection moved into
> nci_send_data(), a rejected zero limit returns before this print, so the
> per-sendmsg flood does not occur through that path.
>
> No legitimate configuration is affected: where the NCI spec does mandate
> a zero Max Data Packet Payload Size -- the NFCEE Direct RF Interface --
> nci_rf_intf_activated_ntf_packet() takes the "goto listen" shortcut,
> bypassing the assignment entirely.
>
> While at it, drop the conn_info lookup in nci_queue_tx_data_frags():
> the caller has already validated the connection, the function now takes
> everything it needs as arguments, and the lookup was the only use of
> conn_info left in it.
>
> Fixes: 6a2968aaf50c ("NFC: basic NCI protocol implementation")
> Cc: stable@vger.kernel.org
> Signed-off-by: Liu Chao <liuc63@xiaopeng.com>
> ---
> Changes in v3:
> - Snapshot max_pkt_payload_len once in nci_send_data() with
> READ_ONCE() and pass it down to nci_queue_tx_data_frags(), as
> suggested by Simon Horman, so the fragmentation decision and the
> fragmentation loop consume the same value and no plain read of the
> field remains on this path (review:
> https://lore.kernel.org/netdev/20260925155040.GP13925@horms.kernel.org/)
> - Move the zero-limit rejection from nci_queue_tx_data_frags() into
> nci_send_data(), so the check runs on the same snapshot the loop
> consumes; this also means a rejected zero limit returns before the
> "failed to fragment" print rather than triggering it per sendmsg
> - Annotate the two producers of the field (RF activation NTF and
> CORE_CONN_CREATE_RSP) with WRITE_ONCE() to match the snapshot read
> - Drop the now-redundant conn_info lookup in nci_queue_tx_data_frags();
> the caller already validated the connection
> - Rate-limit the "failed to fragment tx data packet" print, which sits
> on a data path driven by remote data, as discussed in the review of
> the v2 series
> - Keep the v1/v2 subject so the revision is tracked as the same fix
>
> Changes in v2:
> - READ_ONCE() snapshot of max_pkt_payload_len in
> nci_queue_tx_data_frags(): with the check and the loop reading the
> field independently, a store from the rx workqueue in between
> could let the loop spin on a value the check had just rejected
Thanks for the updates.
Reviewed-by: Simon Horman <horms@kernel.org>
prev parent reply other threads:[~2026-09-28 10:48 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-27 11:59 [PATCH net v3] nfc: nci: avoid unbounded skb allocation when max_pkt_payload_len is zero Liu Chao
2026-09-28 10:48 ` Simon Horman [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260928104809.GQ13925@horms.kernel.org \
--to=horms@kernel.org \
--cc=davem@davemloft.net \
--cc=david@ixit.cz \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=liuc63@xiaopeng.com \
--cc=netdev@vger.kernel.org \
--cc=oe-linux-nfc@lists.linux.dev \
--cc=pabeni@redhat.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.