From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: Dairui Zhang <zhangdairui@gmail.com>, netdev@vger.kernel.org
Cc: Dairui Zhang <zhangdairui@gmail.com>,
Willem de Bruijn <willemb@google.com>,
Daniel Borkmann <daniel@iogearbox.net>,
stable@vger.kernel.org
Subject: Re: [PATCH net] af_packet: fix integer overflow in prb_calc_retire_blk_tmo()
Date: Mon, 21 Sep 2026 23:06:48 -0400 [thread overview]
Message-ID: <willemdebruijn.kernel.1b65de0a75434@gmail.com> (raw)
In-Reply-To: <20260921192608.1420047-1-zhangdairui@gmail.com>
Dairui Zhang wrote:
> prb_calc_retire_blk_tmo() computes in 32-bit int arithmetic:
>
> mbits = (blk_size_in_bytes * 8) / (1024 * 1024);
>
> If I'm reading the validation right, tp_block_size is user
> controlled and packet_set_ring() only rejects values that are <= 0
> as int or not page aligned, so a 256MiB block goes right through
> (and alloc_one_pg_vec_page() even has a vzalloc fallback for it).
> 0x10000000 * 8 wraps to INT_MIN, and on a NIC reporting 1 Gbps
> (div == 1) the function ends up returning -2047.
>
> The condition is actually (8 * size) mod 2^32 >= 2^31 && div == 1,
> so the trigger set is [256,512), [768,1024), [1280,1536) and
> [1792,2048) MiB. Other sizes wrap to non-negative values and faster
> links divide the unsigned value back below 2^31, which is why this
> doesn't blow up for everyone.
>
> What makes it fatal is what happens next in init_prb_bdqc():
>
> p1->interval_ktime = ms_to_ktime(prb_calc_retire_blk_tmo(...));
> hrtimer_start(&p1->retire_blk_timer, p1->interval_ktime,
> HRTIMER_MODE_REL_SOFT);
>
> A negative relative timeout expires immediately. The callback
> unconditionally returns HRTIMER_RESTART, and hrtimer_forward() turns
> the negative interval into hrtimer_resolution:
>
> if (interval < hrtimer_resolution)
> interval = hrtimer_resolution;
>
> So the SOFT timer re-fires at the maximum rate forever, holding
> sk_receive_queue.lock each pass. One CPU spins in softirq until the
> socket is closed. Repeat with more rings and the machine is gone.
>
> This is mostly a new problem: the overflow is ancient, but with
> msecs_to_jiffies() a negative timeout just got clamped to a huge
> unsigned value, i.e. the retire timer effectively never fired.
> f7460d2989fa ("net: af_packet: Use hrtimer to do the retire
> operation", v6.18) turned it into "fire immediately and spin".
> Still present in 7.2.6 and in current mainline as of this
> writing.
>
> (Unrelated to CVE-2019-20812 - that one was the ethtool failure path
> returning 0, which now returns DEFAULT_PRB_RETIRE_TOV.)
>
> Reproducer, needs CAP_NET_RAW (a --network host container has it by
> default) and a 1 Gbps NIC (QEMU e1000 works):
>
> int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
> bind(fd, ...);
> int v = TPACKET_V3;
> setsockopt(fd, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
> struct tpacket_req3 req = {
> .tp_block_size = 0x10000000,
> .tp_block_nr = 1,
> .tp_frame_size = 2048,
> .tp_frame_nr = 0x10000000 / 2048,
> .tp_retire_blk_tov = 0,
> };
> setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
>
> Compute in 64 bits instead. The operands are already bounded by the
> existing validation, so nothing else changes. If you'd prefer a
> different fix, just say so and I'll respin.
>
> Fixes: f7460d2989fa ("net: af_packet: Use hrtimer to do the retire operation")
> Cc: stable@vger.kernel.org
> Signed-off-by: Dairui Zhang <zhangdairui@gmail.com>
> ---
> First patch to netdev, and compile-tested only - I don't have a
> 1 Gbps setup to trigger it live. If I've misread the code, got the
> Fixes: tag wrong, or picked the wrong fix, please say so and I'll
> respin.
Code Looks good to me. Thanks.
As Fixes tag do prefer original commit f6fb8f100b80 ("af-packet:
TPACKET_V3 flexible buffer implementation.")
That is where the bug is introduced, and the effect of the bug prior
to the currenty blamed commit is not as clear-cut as described in the
commit message.
The return value of prb_calc_retire_blk_tmo() is stored into an
unsigned short retire_blk_tov then, so can be truncated. A 0-jiffy
delay loop can also be programmed. Though its effect is not nearly as
detrimental as from the blamed commit on.
next prev parent reply other threads:[~2026-09-22 3:06 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-21 19:26 [PATCH net] af_packet: fix integer overflow in prb_calc_retire_blk_tmo() Dairui Zhang
2026-09-22 3:06 ` Willem de Bruijn [this message]
2026-09-22 3:36 ` Dairui Zhang
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=willemdebruijn.kernel.1b65de0a75434@gmail.com \
--to=willemdebruijn.kernel@gmail.com \
--cc=daniel@iogearbox.net \
--cc=netdev@vger.kernel.org \
--cc=stable@vger.kernel.org \
--cc=willemb@google.com \
--cc=zhangdairui@gmail.com \
/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.