Integer Overflow in tcp_cdg_cong_avoid — Shadow Window Corruption
Summary
net/ipv4/tcp_cdg.c, function tcp_cdg_cong_avoid (line 296), contains a u32 integer
overflow that silently corrupts the shadow congestion window (shadow_wnd). Because
shadow_wnd feeds directly into tcp_cdg_ssthresh(), an attacker who can influence RTT
measurements over a TCP connection using the CDG congestion-control algorithm can
manipulate the effective slow-start threshold, bypassing congestion control and sustaining
an inflated send window indefinitely.
Vulnerable Code
// net/ipv4/tcp_cdg.c:292-296
prior_snd_cwnd = tcp_snd_cwnd(tp);
tcp_reno_cong_avoid(sk, ack, acked);
incr = tcp_snd_cwnd(tp) - prior_snd_cwnd;
ca->shadow_wnd = max(ca->shadow_wnd, ca->shadow_wnd + incr); // ← overflow
Root Cause
ca->shadow_wnd and incr are both u32. When ca->shadow_wnd is near U32_MAX
and incr > 0, the addition ca->shadow_wnd + incr wraps to a small value. The
max() then selects the original (pre-overflow) value, causing shadow_wnd to
permanently stall at its current level instead of tracking the real congestion window.
This is the classic max(a, a + b) antipattern: when no overflow occurs the max()
is entirely redundant (a + b ≥ a for non-negative b); when overflow does occur,
the wrap-around silently freezes shadow_wnd.
Secondary: signed integer overflow (UB) in tcp_cdg_grad
// net/ipv4/tcp_cdg.c:217,221
grad *= window; // s32 × int — overflows for large RTT deltas
...
grad = (grad * window) / (int)ca->tail; // same UB
grad is s32 and window is int (maximum 256). An RTT gradient exceeding
S32_MAX / 256 ≈ 8.4 s causes signed overflow, which is undefined behaviour in C.
Modern compilers exploit this UB to mis-compile surrounding comparisons and branches,
potentially subverting the grad > 0 check that guards tcp_cdg_backoff().
Attack Surface
CDG is selected per-socket via setsockopt(TCP_CONGESTION, "cdg") — no privilege
required. Any unprivileged user-space process that opens a TCP socket can:
setsockopt(sk, IPPROTO_TCP, TCP_CONGESTION, "cdg", 3)to opt-in.- Control the other endpoint (loopback, a cooperating remote host, or a MITM).
- Craft ACKs that inflate RTT samples, driving
gradto large values and maximisingincrthrough repeated slow-start events.
Exploit Scenario
Congestion-control bypass (shadow_wnd freeze)
- Establish a TCP connection with CDG enabled.
- Allow the connection to ramp up until
shadow_wndgrows large (many MB). - Trigger rapid slow-start recovery cycles by inducing synthetic loss events,
forcing
tcp_reno_cong_avoidto produce largeincrvalues. - Once
shadow_wnd + incrwraps pastU32_MAX,shadow_wndfreezes at its pre-wrap value. tcp_cdg_ssthreshsubsequently returnsmax3(2, shadow_wnd, cwnd >> 1)— whereshadow_wndis now an arbitrarily large stale value — preventing the slow-start threshold from ever decreasing.- The connection behaves as if it is always in congestion avoidance with an unbounded threshold, consuming far more than its fair share of link bandwidth (network resource exhaustion / fairness violation).
Gradient UB → backoff suppression
- With CDG loaded and the gradient window partially filled (
!gfilled,tail > 0), send ACKs with RTT samples that pushgminorgmaxaboveS32_MAX / 256. grad *= windowoverflowss32; the compiler may fold the subsequentgrad > 0branch to a constant, skippingtcp_cdg_backoff()entirely.- The connection never backs off on detected queue build-up, effectively disabling the core CDG algorithm and allowing unbounded queue inflation (bufferbloat / DoS).
Impact
| Property | Value |
|---|---|
| CWE | CWE-190 (Integer Overflow); CWE-758 (UB — signed overflow) |
| Attack vector | Network (any TCP peer) |
| Privileges required | None (TCP_CONGESTION is unprivileged) |
| Affected component | net/ipv4/tcp_cdg.c |
| Severity | High — network fairness bypass, potential bufferbloat DoS |
Fix
// Before (buggy):
ca->shadow_wnd = max(ca->shadow_wnd, ca->shadow_wnd + incr);
// After (correct — use saturating addition):
ca->shadow_wnd = min(U32_MAX - incr < ca->shadow_wnd
? U32_MAX
: ca->shadow_wnd + incr,
(u32)tcp_snd_cwnd(tp) * 2);
For the gradient UB, promote to s64 before multiplying:
// Before:
grad = (grad * window) / (int)ca->tail;
// After:
grad = (s32)(((s64)grad * window) / (int)ca->tail);
References
- Vulnerable file:
net/ipv4/tcp_cdg.c - Primary bug: line 296 (
tcp_cdg_cong_avoid) - Secondary bug: lines 217, 221 (
tcp_cdg_grad) - Shadow window consumer: lines 339–342 (
tcp_cdg_ssthresh) - CDG paper: Hayes & Armitage, “Revisiting TCP congestion control using delay gradients,” IFIP Networking 2011