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:

  1. setsockopt(sk, IPPROTO_TCP, TCP_CONGESTION, "cdg", 3) to opt-in.
  2. Control the other endpoint (loopback, a cooperating remote host, or a MITM).
  3. Craft ACKs that inflate RTT samples, driving grad to large values and maximising incr through repeated slow-start events.

Exploit Scenario

Congestion-control bypass (shadow_wnd freeze)

  1. Establish a TCP connection with CDG enabled.
  2. Allow the connection to ramp up until shadow_wnd grows large (many MB).
  3. Trigger rapid slow-start recovery cycles by inducing synthetic loss events, forcing tcp_reno_cong_avoid to produce large incr values.
  4. Once shadow_wnd + incr wraps past U32_MAX, shadow_wnd freezes at its pre-wrap value.
  5. tcp_cdg_ssthresh subsequently returns max3(2, shadow_wnd, cwnd >> 1) — where shadow_wnd is now an arbitrarily large stale value — preventing the slow-start threshold from ever decreasing.
  6. 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

  1. With CDG loaded and the gradient window partially filled (!gfilled, tail > 0), send ACKs with RTT samples that push gmin or gmax above S32_MAX / 256.
  2. grad *= window overflows s32; the compiler may fold the subsequent grad > 0 branch to a constant, skipping tcp_cdg_backoff() entirely.
  3. 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