icsk_backoff is bumped on every RTO and zero window probe, and the only thing bounding it is tcp_retries2 (a u8 sysctl, 0..255). inet_csk_rto_backoff() then uses it as a shift amount: u64 when = (u64)icsk->icsk_rto << icsk->icsk_backoff; Set tcp_retries2 to 64 or more and keep the peer silent, icsk_backoff climbs past 63 and the shift is UB. For example an ICMP host unreachable arriving on such a socket 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: 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 The orphan check in tcp_probe_timer() calls the same helper. tcp_probe0_when() got a similar clamp in 2020, but this helper was left as is. Cap the shift at 32 like it was suggested back then: icsk_rto is at least 1 jiffy, so 1 << 32 jiffies is already far above any max_when, and the min_t() result is unchanged. Unlike an ilog2(RTO_MAX/RTO_MIN) bound, 32 still holds when tcp_rto_min_us is lowered. Fixes: fcdd1cf4dd63 ("tcp: avoid possible arithmetic overflows") Cc: stable@vger.kernel.org Signed-off-by: Jiayuan Chen --- 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