Skip to content

bpf: close rate-limit bypasses via IPv6, fragments, non-IP, rotating flows - #3

Open
terraboops wants to merge 1 commit into
mainfrom
fix/bpf-limit-bypass
Open

terraboops wants to merge 1 commit into
mainfrom
fix/bpf-limit-bypass

Conversation

@terraboops

Copy link
Copy Markdown
Owner

Found in a security review. Each one lets a pod exceed its own kubernetes.io/*-bandwidth limit. None reaches another pod's state.

Bypass Before After
IPv6 parse_flow returned -1, so the packet passed unaccounted parsed; addresses XOR-folded into the existing 32-bit key fields (IPv4 hash cost unchanged)
IPv4 fragments "ports" read from non-first fragments' payload, so each fragment looked like a new mouse fragments keyed on address pair + protocol
Non-IP / truncated headers passed unaccounted (raw-socket flood under any EtherType) keyed on EtherType or a partial tuple; still classified by the CMS
Rotating 5-tuples each flow stays under hh_threshold; ~24–48x rate until CMS saturation per-direction mouse budget, max(rate × 125 ms, 4 × hh_threshold) per ~134 ms window; past it, mice pay tokens. That's ~3x rate at the default threshold, and mice still pass whenever the bucket has tokens

TestScenarioThousandMice sent 320 KB of mice at 1 B/s, which is the rotating-flow pattern itself. It now runs at 100 Mbps so the traffic fits the budget, and the one-byte bucket still drops anything that reaches it.

Testing

New L3 tests in test/bpf/bypass_linux_test.go, one per bypass, with both directions checked in each test.

On main (unfixed BPF), all five fail:

TestBypassIPv6Elephant      ingress/egress: passed=50 hh_hits=0 throttled=0
TestBypassIPv4Fragments     ingress/egress: passed=50 hh_hits=0 throttled=0
TestBypassNonIPFlood        ingress/egress: passed=50 hh_hits=0 throttled=0
TestBypassTruncatedL4       ingress/egress: passed=50 hh_hits=0 throttled=0
TestBypassRotatingMice      ingress/egress: 5000 mouse packets passed (320000 bytes), want <= 801

On this branch, make test-bpf and make test-perf both pass (full L3, including the new tests, and L5).

L5 single-sample ns/op, main → branch: prog_run 759.0 → 746.6, one_elephant ingress 849.4 → 816.3, egress 827.3 → 812.6, thousand_mice 807.1 → 811.5 (noise-level). Repeated-sample A/B and the full-profile perf-vs-vanilla comparison against main are in progress; results will be posted here before merge.

https://claude.ai/code/session_01RyYnvjh5DBevutC4HTgELn

…flows

A pod could get past its bandwidth limit several ways:

- IPv6: parse_flow returned -1 for anything but IPv4 and the packet
  passed unaccounted. It now parses IPv6, XOR-folding the addresses
  into the existing 32-bit key fields so the IPv4 hash cost doesn't
  change.
- IPv4 fragments: ports were read from non-first fragments' payload,
  so every fragment looked like a new mouse. Fragments now key on
  the address pair + protocol.
- Non-IP frames and truncated/malformed headers passed unaccounted.
  They're keyed on EtherType (or a partial tuple) and go through the
  sketch like everything else; single ARP-sized frames stay mice.
- Rotating 5-tuples: each new flow stays under hh_threshold, so a
  pod could push ~24-48x its rate before the CMS saturated. Mouse
  bytes are now summed per direction over a ~134 ms window; past
  max(rate x 125 ms, 4 x hh_threshold) further packets go through
  the token bucket. With the default threshold that bounds mice to
  ~3x the configured rate, and mice still pass whenever the bucket
  has tokens.

TestScenarioThousandMice ran 320 KB of mice at 1 B/s, which is the
rotating-flow pattern itself; it now uses 100 Mbps so the traffic
fits the mouse budget while the one-byte bucket still drops anything
that reaches it.

New L3 tests (test/bpf/bypass_linux_test.go) cover each case; all
five fail on main and pass here.

Claude-Session: https://claude.ai/code/session_01RyYnvjh5DBevutC4HTgELn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant