Summary
subnetMaskToCIDR() in pkg/unikontainers/unikernels/utils.go computes the
prefix length by counting the number of 1 bits in the mask, without checking
that those bits are contiguous. As a result, structurally-invalid netmasks
(where the set bits are not left-aligned) are accepted and mapped to a
plausible-but-wrong CIDR instead of being rejected.
Steps to reproduce
Feeding a few masks through the current logic:
| Input mask |
Returned |
Correct behavior |
255.0.255.0 |
/16 |
error (invalid mask) |
0.255.255.255 |
/24 |
error (invalid mask) |
255.255.1.0 |
/17 |
error (invalid mask) |
A valid IPv4 mask must be a contiguous run of 1s followed by 0s
(e.g. 255.255.255.0). The current implementation only counts bits, so
255.0.255.0 (16 set bits) is accepted as /16.
Impact
Low severity this is an input-validation gap, not a crash. But the resulting
CIDR is used to build the guest's network configuration, so a malformed mask
propagates silently into wrong guest networking rather than failing fast with a
clear error.
Suggested fix
After parsing the four octets into a uint32 mask value v, reject any mask
whose inverse is not a contiguous low-bit block:
inv := ^v
if inv&(inv+1) != 0 {
return 0, fmt.Errorf("invalid (non-contiguous) subnet mask: %s", subnetMask)
}
I verified this guard accepts all 33 canonical masks (/0–/32) with the
correct CIDR and rejects the non-contiguous cases above.
How this was found
Surfaced while adding fuzz coverage for the unikernel parsers (relates to #852).
A FuzzSubnetMaskToCIDR target with a contiguity oracle fails on the seed
corpus immediately. Happy to open a PR adding both the validation and the fuzz
target if that's useful.
CC @ananos @cmainas
Summary
subnetMaskToCIDR()inpkg/unikontainers/unikernels/utils.gocomputes theprefix length by counting the number of
1bits in the mask, without checkingthat those bits are contiguous. As a result, structurally-invalid netmasks
(where the set bits are not left-aligned) are accepted and mapped to a
plausible-but-wrong CIDR instead of being rejected.
Steps to reproduce
Feeding a few masks through the current logic:
255.0.255.0/160.255.255.255/24255.255.1.0/17A valid IPv4 mask must be a contiguous run of
1s followed by0s(e.g.
255.255.255.0). The current implementation only counts bits, so255.0.255.0(16 set bits) is accepted as/16.Impact
Low severity this is an input-validation gap, not a crash. But the resulting
CIDR is used to build the guest's network configuration, so a malformed mask
propagates silently into wrong guest networking rather than failing fast with a
clear error.
Suggested fix
After parsing the four octets into a
uint32mask valuev, reject any maskwhose inverse is not a contiguous low-bit block:
I verified this guard accepts all 33 canonical masks (
/0–/32) with thecorrect CIDR and rejects the non-contiguous cases above.
How this was found
Surfaced while adding fuzz coverage for the unikernel parsers (relates to #852).
A
FuzzSubnetMaskToCIDRtarget with a contiguity oracle fails on the seedcorpus immediately. Happy to open a PR adding both the validation and the fuzz
target if that's useful.
CC @ananos @cmainas