Skip to content

pkg/ip, host-local: fix panic on a RangeStart at the top of a family - #1293

Open
thc1006 wants to merge 2 commits into
containernetworking:mainfrom
thc1006:pkg-ip-host-local-topofspace-panic
Open

pkg/ip, host-local: fix panic on a RangeStart at the top of a family#1293
thc1006 wants to merge 2 commits into
containernetworking:mainfrom
thc1006:pkg-ip-host-local-topofspace-panic

Conversation

@thc1006

@thc1006 thc1006 commented Aug 17, 2026

Copy link
Copy Markdown

Fixes #1292.

intToIP converts arithmetic results back to fixed-width net.IP values. It must preserve the selected address family and reject results outside that family.

Incrementing the final IPv4 or IPv6 address produces a value one byte wider than the family, which makes the padding calculation use a negative length and panic. The existing conversion also returned a four-byte IPv4 value when a valid IPv6 result happened to have exactly four significant bytes (for example NextIP(::ff:ffff) returned 1.0.0.0 rather than ::100:0), and because big.Int.Bytes returns the absolute value, a subtraction below the first address of a family came back as the wrapped value instead of nil.

The host-local reproducer in #1292 is IPv4-specific. An explicit IPv4 rangeStart at the subnet broadcast address can be greater than the default rangeEnd, which excludes broadcast. Range.Canonicalize checked RangeStart before assigning the default end, so the reversed range was accepted. At 255.255.255.255 this reaches NextIP and panics; in a lower subnet a broadcast rangeStart walks outside the configured range before it reaches a family boundary. IPv6 defaults rangeEnd to the subnet's final address, so an all-ones rangeStart is also rangeEnd and the iterator exhausts the range before calling NextIP; the direct NextIP(max IPv6) helper call has the same arithmetic overflow, which the new unit test covers.

Changes:

  • pkg/ip: decide the family width first, reject sign-negative underflow and oversized overflow, and always return the selected family's fixed width.
  • host-local: reject RangeStart > RangeEnd after both values have been resolved.

Tests cover both family maxima, IPv6 family-width preservation, both family minima for PrevIP, the defaulted-end ordering check, and the exact configuration from #1292.

{"ipam":{"type":"host-local","ranges":[[{"subnet":"255.255.255.252/30","rangeStart":"255.255.255.255","gateway":"255.255.255.255"}]]}}

LoadIPAMConfig accepts this config. RangeEnd is not set, so Canonicalize
defaults it to 255.255.255.254, one below the explicit RangeStart. The
first call to Get skips RangeStart because it equals Gateway, asks the
iterator for the next address, and NextIP(255.255.255.255) carries into
a 5th byte. intToIP then computes make([]byte, 4-5) and panics with
"makeslice: len out of range", so a single malformed CNI ADD config can
crash the plugin. The same shape reaches an all-ones IPv6 RangeStart.

Two gaps let this through:

1. intToIP assumes the incremented value fits in the address family's
   byte width and never checks the overflow direction. NextIP's own doc
   comment says invalid input returns nil, but intToIP didn't hold to
   that once the carry needed more bytes than the family, so the nil
   contract only worked for the too-few-bytes case fixed by containernetworking#782/containernetworking#783.

2. Range.Canonicalize validates RangeStart against Contains before
   RangeEnd has been assigned a value (explicit or defaulted), so an
   explicit RangeStart that only conflicts with the *defaulted* RangeEnd
   was never checked against it.

Fix intToIP to return nil when the carry overflows the family width,
matching NextIP's contract. Fix Canonicalize to reject RangeStart >
RangeEnd once both are resolved, which also covers the general case of
an explicit RangeStart landing on a subnet's broadcast address with a
defaulted RangeEnd, not just the top of the whole address family.

Tests: NextIP cases for the last address of both families, a
Canonicalize case for RangeStart landing after a defaulted RangeEnd
(both a plain subnet and the top-of-family case), and a LoadIPAMConfig
regression test using the exact reported config.

Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>
@thc1006
thc1006 force-pushed the pkg-ip-host-local-topofspace-panic branch from 264e981 to d6d4b09 Compare August 17, 2026 10:20
intToIP decided the result length from the minimal big.Int encoding, so a low IPv6 value whose leading bytes are zero (NextIP(::ff:ffff)) came back as a 4-byte IPv4 address. And because big.Int.Bytes returns the absolute value, PrevIP below the first address of a family returned the wrapped value instead of nil.

Decide the family width first, reject sign-negative underflow and oversized overflow, and always return the family's fixed width. Add regressions for IPv6 family preservation and both family minima.

Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>
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.

host-local: RangeStart at the top of the address family panics Get

1 participant