From: Jiayuan Chen <jiayuan.chen@linux.dev>
To: netdev@vger.kernel.org
Cc: Jiayuan Chen <jiayuan.chen@linux.dev>,
stable@vger.kernel.org, "David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>, Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Randy Dunlap <rdunlap@infradead.org>,
Neal Cardwell <ncardwell@google.com>,
Kuniyuki Iwashima <kuniyu@google.com>,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH net v2 2/2] tcp: fix shift-out-of-bounds in inet_csk_rto_backoff()
Date: Mon, 26 Oct 2026 20:32:39 +0800 [thread overview]
Message-ID: <20261026123244.239766-2-jiayuan.chen@linux.dev> (raw)
In-Reply-To: <20261026123244.239766-1-jiayuan.chen@linux.dev>
icsk_backoff is incremented by tcp_retransmit_timer() on every backed-off
RTO with no cap of its own, and by tcp_send_probe0() up to tcp_retries2.
It is used as a shift amount in inet_csk_rto_backoff():
u64 when = (u64)icsk->icsk_rto << icsk->icsk_backoff;
Once it climbs past 63 the shift is UB. Seen with tcp_retries2=255 and a
silent peer, when an ICMP host unreachable goes through
tcp_ld_RTO_revert():
UBSAN: shift-out-of-bounds in ./include/net/inet_connection_sock.h:258:40
shift exponent 73 is too large for 64-bit type 'long long unsigned int'
Call Trace:
<IRQ>
dump_stack_lvl+0xc1/0xf0
dump_stack+0x10/0x20
__ubsan_handle_shift_out_of_bounds+0x1d1/0x390
tcp_ld_RTO_revert.cold+0x16/0x92
tcp_v4_err+0xdb3/0x13e0
icmp_socket_deliver+0x1a7/0x390
icmp_unreach+0x2dd/0xe50
icmp_rcv+0x93e/0xe30
ip_protocol_deliver_rcu+0x36b/0x3e0
ip_local_deliver_finish+0x37d/0x620
ip_local_deliver+0x165/0x1d0
ip_rcv+0x284/0x320
__netif_receive_skb_one_core+0x16b/0x1c0
__netif_receive_skb+0x21/0x150
process_backlog+0x37e/0x1200
__napi_poll.constprop.0+0xa5/0x5e0
net_rx_action+0x4c0/0xf70
handle_softirqs+0x204/0x9b0
__irq_exit_rcu+0x13c/0x220
irq_exit_rcu+0xe/0x20
sysvec_apic_timer_interrupt+0x92/0xd0
</IRQ>
The orphan check in tcp_probe_timer() calls the same helper. On x86-64
the oversized shift count is taken modulo 64, so an orphan that should
be dead can be seen as alive, and tcp_ld_RTO_revert() can end up with a
smaller RTO than intended.
Cap the shift at 32: any non-zero icsk_rto << 32 exceeds TCP_RTO_MAX, so
the min_t() result is what the unbounded math would give. The
ilog2(TCP_RTO_MAX / TCP_RTO_MIN) + 1 bound of tcp_probe0_when() does not
fit here, as icsk_rto has no TCP_RTO_MIN floor the way tcp_probe0_base()
has.
Fixes: fcdd1cf4dd63 ("tcp: avoid possible arithmetic overflows")
Cc: stable@vger.kernel.org
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
include/net/inet_connection_sock.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index 903499581db7..562e12033a5d 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -255,9 +255,10 @@ static inline unsigned long
inet_csk_rto_backoff(const struct inet_connection_sock *icsk,
unsigned long max_when)
{
- u64 when = (u64)icsk->icsk_rto << icsk->icsk_backoff;
+ u8 backoff = min_t(u8, 32U, icsk->icsk_backoff);
+ u64 when = (u64)icsk->icsk_rto << backoff;
- return (unsigned long)min_t(u64, when, max_when);
+ return (unsigned long)min_t(u64, when, max_when);
}
struct sock *inet_csk_accept(struct sock *sk, struct proto_accept_arg *arg);
--
2.43.0
next prev parent reply other threads:[~2026-10-26 12:33 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 12:32 [PATCH net v2 1/2] tcp: fix shift-out-of-bounds in SYN-ACK retransmit timers Jiayuan Chen
2026-10-26 12:32 ` Jiayuan Chen [this message]
2026-10-26 13:36 ` [PATCH net v2 2/2] tcp: fix shift-out-of-bounds in inet_csk_rto_backoff() Neal Cardwell
2026-10-26 13:27 ` [PATCH net v2 1/2] tcp: fix shift-out-of-bounds in SYN-ACK retransmit timers Neal Cardwell
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=20261026123244.239766-2-jiayuan.chen@linux.dev \
--to=jiayuan.chen@linux.dev \
--cc=corbet@lwn.net \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ncardwell@google.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=rdunlap@infradead.org \
--cc=skhan@linuxfoundation.org \
--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.