Skip to content

Commit fcdd1cf

Browse files
edumazetdavem330
authored andcommitted
tcp: avoid possible arithmetic overflows
icsk_rto is a 32bit field, and icsk_backoff can reach 15 by default, or more if some sysctl (eg tcp_retries2) are changed. Better use 64bit to perform icsk_rto << icsk_backoff operations As Joe Perches suggested, add a helper for this. Yuchung spotted the tcp_v4_err() case. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 35f7aa5 commit fcdd1cf

File tree

5 files changed

+23
-14
lines changed

5 files changed

+23
-14
lines changed

include/net/inet_connection_sock.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,15 @@ static inline void inet_csk_reset_xmit_timer(struct sock *sk, const int what,
242242
#endif
243243
}
244244

245+
static inline unsigned long
246+
inet_csk_rto_backoff(const struct inet_connection_sock *icsk,
247+
unsigned long max_when)
248+
{
249+
u64 when = (u64)icsk->icsk_rto << icsk->icsk_backoff;
250+
251+
return (unsigned long)min_t(u64, when, max_when);
252+
}
253+
245254
struct sock *inet_csk_accept(struct sock *sk, int flags, int *err);
246255

247256
struct request_sock *inet_csk_search_req(const struct sock *sk,

net/ipv4/tcp_input.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3208,9 +3208,10 @@ static void tcp_ack_probe(struct sock *sk)
32083208
* This function is not for random using!
32093209
*/
32103210
} else {
3211+
unsigned long when = inet_csk_rto_backoff(icsk, TCP_RTO_MAX);
3212+
32113213
inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
3212-
min(icsk->icsk_rto << icsk->icsk_backoff, TCP_RTO_MAX),
3213-
TCP_RTO_MAX);
3214+
when, TCP_RTO_MAX);
32143215
}
32153216
}
32163217

net/ipv4/tcp_ipv4.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
430430
break;
431431

432432
icsk->icsk_backoff--;
433-
inet_csk(sk)->icsk_rto = (tp->srtt_us ? __tcp_set_rto(tp) :
434-
TCP_TIMEOUT_INIT) << icsk->icsk_backoff;
435-
tcp_bound_rto(sk);
433+
icsk->icsk_rto = tp->srtt_us ? __tcp_set_rto(tp) :
434+
TCP_TIMEOUT_INIT;
435+
icsk->icsk_rto = inet_csk_rto_backoff(icsk, TCP_RTO_MAX);
436436

437437
skb = tcp_write_queue_head(sk);
438438
BUG_ON(!skb);

net/ipv4/tcp_output.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3279,6 +3279,7 @@ void tcp_send_probe0(struct sock *sk)
32793279
{
32803280
struct inet_connection_sock *icsk = inet_csk(sk);
32813281
struct tcp_sock *tp = tcp_sk(sk);
3282+
unsigned long probe_max;
32823283
int err;
32833284

32843285
err = tcp_write_wakeup(sk);
@@ -3294,9 +3295,7 @@ void tcp_send_probe0(struct sock *sk)
32943295
if (icsk->icsk_backoff < sysctl_tcp_retries2)
32953296
icsk->icsk_backoff++;
32963297
icsk->icsk_probes_out++;
3297-
inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
3298-
min(icsk->icsk_rto << icsk->icsk_backoff, TCP_RTO_MAX),
3299-
TCP_RTO_MAX);
3298+
probe_max = TCP_RTO_MAX;
33003299
} else {
33013300
/* If packet was not sent due to local congestion,
33023301
* do not backoff and do not remember icsk_probes_out.
@@ -3306,11 +3305,11 @@ void tcp_send_probe0(struct sock *sk)
33063305
*/
33073306
if (!icsk->icsk_probes_out)
33083307
icsk->icsk_probes_out = 1;
3309-
inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
3310-
min(icsk->icsk_rto << icsk->icsk_backoff,
3311-
TCP_RESOURCE_PROBE_INTERVAL),
3312-
TCP_RTO_MAX);
3308+
probe_max = TCP_RESOURCE_PROBE_INTERVAL;
33133309
}
3310+
inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
3311+
inet_csk_rto_backoff(icsk, probe_max),
3312+
TCP_RTO_MAX);
33143313
}
33153314

33163315
int tcp_rtx_synack(struct sock *sk, struct request_sock *req)

net/ipv4/tcp_timer.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ static int tcp_write_timeout(struct sock *sk)
180180

181181
retry_until = sysctl_tcp_retries2;
182182
if (sock_flag(sk, SOCK_DEAD)) {
183-
const int alive = (icsk->icsk_rto < TCP_RTO_MAX);
183+
const int alive = icsk->icsk_rto < TCP_RTO_MAX;
184184

185185
retry_until = tcp_orphan_retries(sk, alive);
186186
do_reset = alive ||
@@ -294,7 +294,7 @@ static void tcp_probe_timer(struct sock *sk)
294294
max_probes = sysctl_tcp_retries2;
295295

296296
if (sock_flag(sk, SOCK_DEAD)) {
297-
const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) < TCP_RTO_MAX);
297+
const int alive = inet_csk_rto_backoff(icsk, TCP_RTO_MAX) < TCP_RTO_MAX;
298298

299299
max_probes = tcp_orphan_retries(sk, alive);
300300

0 commit comments

Comments
 (0)