From: Thomas Graf <tgraf@redhat.com> Date: Fri, 23 Jul 2010 15:36:52 -0400 Subject: [net] tcp: fix overflow bug in Vegas Message-id: <20100723153652.GN14925@lsx.localdomain> Patchwork-id: 27072 O-Subject: [RHEL5.6 PATCH 12/14] tcp: Overflow bug in Vegas Bugzilla: 612709 RH-Acked-by: Neil Horman <nhorman@redhat.com> RH-Acked-by: David S. Miller <davem@redhat.com> commit 159131149c2f56c1da5ae5e23ab9d5acef4916d1 Author: Lachlan Andrew <lachlan.andrew@gmail.com> Date: Wed Apr 30 01:04:03 2008 -0700 tcp: Overflow bug in Vegas From: Lachlan Andrew <lachlan.andrew@gmail.com> There is an overflow bug in net/ipv4/tcp_vegas.c for large BDPs (e.g. 400Mbit/s, 400ms). The multiplication (old_wnd * vegas->baseRTT) << V_PARAM_SHIFT overflows a u32. [ Fix tcp_veno.c too, it has similar calculations. -DaveM ] Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Jarod Wilson <jarod@redhat.com> diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index 0189f8d..7fb1cb3 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c @@ -229,7 +229,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, */ tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag); } else { - u32 rtt, target_cwnd, diff; + u32 rtt, diff; + u64 target_cwnd; /* We have enough RTT samples, so, using the Vegas * algorithm, we determine if we should increase or @@ -252,8 +253,9 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, * We keep it as a fixed point number with * V_PARAM_SHIFT bits to the right of the binary point. */ - target_cwnd = ((old_wnd * vegas->baseRTT) - << V_PARAM_SHIFT) / rtt; + target_cwnd = ((u64)old_wnd * vegas->baseRTT); + target_cwnd <<= V_PARAM_SHIFT; + do_div(target_cwnd, rtt); /* Calculate the difference between the window we had, * and the window we would like to have. This quantity @@ -279,7 +281,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, * utilization. */ tp->snd_cwnd = min(tp->snd_cwnd, - (target_cwnd >> + ((u32)target_cwnd >> V_PARAM_SHIFT)+1); } else if (tp->snd_cwnd <= tp->snd_ssthresh) { diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index 5b2fe6d..35baea6 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c @@ -128,7 +128,8 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, */ tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag); } else { - u32 rtt, target_cwnd; + u64 target_cwnd; + u32 rtt; /* We have enough rtt samples, so, using the Veno * algorithm, we determine the state of the network. @@ -136,8 +137,9 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, rtt = veno->minrtt; - target_cwnd = ((tp->snd_cwnd * veno->basertt) - << V_PARAM_SHIFT) / rtt; + target_cwnd = (tp->snd_cwnd * veno->basertt); + target_cwnd <<= V_PARAM_SHIFT; + do_div(target_cwnd, rtt); veno->diff = (tp->snd_cwnd << V_PARAM_SHIFT) - target_cwnd;