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 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®