net: fix divide by zero in tcp algorithm illinois
Subsystems (3)
PATCH v2 1/1 net: fix divide by zero in tcp algorithm illinois
Reading TCP stats when using TCP Illinois congestion control algorithm can cause a divide by zero kernel oops.
The division by zero occur in tcp_illinois_info() at:
do_div(t, ca->cnt_rtt);
where ca->cnt_rtt can become zero (when rtt_reset is called)
Steps to Reproduce:
1. Register tcp_illinois:
# sysctl -w net.ipv4.tcp_congestion_control=illinois
2. Monitor internal TCP information via command "ss -i"
# watch -d ss -i
3. Establish new TCP conn to machineEither it fails at the initial conn, or else it needs to wait for a loss or a reset.
This is only related to reading stats. The function avg_delay() also performs the same divide, but is guarded with a (ca->cnt_rtt > 0) at its calling point in update_params(). Thus, simply fix tcp_illinois_info().
Function tcp_illinois_info() / get_info() is called without socket lock. Thus, eliminate any race condition on ca->cnt_rtt by using a local stack variable. Simply reuse info.tcpv_rttcnt, as its already set to ca->cnt_rtt.
Function avg_delay() is not affected by this race condition, as its called with the socket lock.
---
V2:
Address Eric Dumazets input:
- Save 2 bytes of stack, by using info.tcpv_rttcnt.
- Help compiler, and define "u64 t" inside if() lexical scope.
net/ipv4/tcp_illinois.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-)
net/ipv4/tcp_illinois.c +5 -3
@@ -313,11 +313,13 @@ static void tcp_illinois_info(struct sock *sk, u32 ext, .tcpv_rttcnt = ca->cnt_rtt, .tcpv_minrtt = ca->base_rtt, }; -u64 t = ca->sum_rtt; -do_div (t, ca->cnt_rtt); - info.tcpv_rtt = t; +if (info.tcpv_rttcnt >0 ) { +u64 t = ca->sum_rtt; +do_div (t, info.tcpv_rttcnt); + info.tcpv_rtt = t; + }nla_put (skb,INET_DIAG_VEGASINFO ,sizeof (info), &info); } }
Quoted 8 lines · Jesper Dangaard Brouer
Reading TCP stats when using TCP Illinois congestion control algorithm can cause a divide by zero kernel oops.
The division by zero occur in
tcp_illinois_info()at:
do_div(t, ca->cnt_rtt);
whereca->cnt_rttcan become zero (whenrtt_resetis called)
Quoted 4 lines
Cc Petr Matousek <[email protected]>Signed-off-by Jesper Dangaard Brouer <[email protected]>---
From: Eric Dumazet <[email protected]>
Date: Wed, 31 Oct 2012 18:14:38 +0100
Quoted 9 lines · Jesper Dangaard Brouer
Quoted 7 lines
Reading TCP stats when using TCP Illinois congestion control algorithm can cause a divide by zero kernel oops.
The division by zero occur in
tcp_illinois_info()at:
do_div(t, ca->cnt_rtt);
whereca->cnt_rttcan become zero (whenrtt_resetis called)
Quoted 6 lines
Quoted 4 lines
Cc Petr Matousek <[email protected]>Signed-off-by Jesper Dangaard Brouer <[email protected]>---
Acked-by Eric Dumazet <[email protected]>
Applied, thanks everyone.
Quoted 53 lines · On Wed, 31 Oct 2012 13:45:32 +0100 Jesper Dangaard Brouer <[email protected]>…
Reading TCP stats when using TCP Illinois congestion control algorithm can cause a divide by zero kernel oops.
The division by zero occur in
tcp_illinois_info()at:
do_div(t, ca->cnt_rtt);
whereca->cnt_rttcan become zero (whenrtt_resetis called)Steps to Reproduce:
1. Registertcp_illinois:# sysctl -w net.ipv4.tcp_congestion_control=illinois 2. Monitor internal TCP information via command "ss -i" # watch -d ss -i 3. Establish new TCP conn to machineEither it fails at the initial conn, or else it needs to wait for a loss or a reset.
This is only related to reading stats. The function
avg_delay()also performs the same divide, but is guarded with a (ca->cnt_rtt> 0) at its calling point inupdate_params(). Thus, simply fixtcp_illinois_info().Function
tcp_illinois_info()/get_info()is called without socket lock. Thus, eliminate any race condition onca->cnt_rttby using a local stack variable. Simply reuse info.tcpv_rttcnt, as its already set toca->cnt_rtt.
Functionavg_delay()is not affected by this race condition, as its called with the socket lock.Cc Petr Matousek <[email protected]>Signed-off-by Jesper Dangaard Brouer <[email protected]>---
V2:
Address Eric Dumazets input:
- Save 2 bytes of stack, by using info.tcpv_rttcnt.
- Help compiler, and define "u64 t" insideif()lexical scope.net/ipv4/tcp_illinois.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-)net/ipv4/tcp_illinois.c +0
-2@@ -313,11 +313,13 @@ static void tcp_illinois_info(struct sock *sk, u32 ext, .tcpv_rttcnt = ca->cnt_rtt, .tcpv_minrtt = ca->base_rtt, }; -u64 t = ca->sum_rtt; -do_div (t, ca->cnt_rtt);
net/ipv4/tcp_illinois.c static void tcp_illinois_info(struct sock *sk, u32 ext, · line 325
Quoted 10 lines
net/ipv4/tcp_illinois.c +5
-1- info.tcpv_rtt = t; +if (info.tcpv_rttcnt >0 ) { +u64 t = ca->sum_rtt; +do_div (t, info.tcpv_rttcnt); + info.tcpv_rtt = t; + }nla_put (skb,INET_DIAG_VEGASINFO ,sizeof (info), &info); } }
Quoted 5 lines · Stephen Hemminger
Quoted 2 lines · On Wed, 31 Oct 2012 13:45:32 +0100 Jesper Dangaard Brouer <[email protected]>…
Reading TCP stats when using TCP Illinois congestion control algorithm can cause a divide by zero kernel oops.
[...]
Quoted 2 lines
When DaveM is without power, people even have/get time to review and ack my patches ;-). Thanks Stephen and Eric.
--Jesper