Skip to content

fix(core): refuse a byte size that does not fit instead of wrapping it to zero - #190

Merged
congwang-mk merged 1 commit into
multikernel:mainfrom
dzerik:fix/bytesize-overflow
Aug 6, 2026
Merged

fix(core): refuse a byte size that does not fit instead of wrapping it to zero#190
congwang-mk merged 1 commit into
multikernel:mainfrom
dzerik:fix/bytesize-overflow

Conversation

@dzerik

@dzerik dzerik commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Small, self-contained, and safe for the release you are about to cut.

The bug

ByteSize::parse reads the digits, matches the suffix and then multiplies,
and that multiply is unchecked. A debug build panics; a release build wraps,
which is the case that matters, because it wraps into a number the caller
never wrote and nothing reports it.

memory = "17179869184G" is exactly 2^64 bytes. It wraps to 0 and installs a
ceiling of zero. That ceiling is not inert: the supervisor registers the
memory handler on is_some(), so the guest is SIGKILLed on its first
anonymous mmap, while /proc/meminfo inside the sandbox reports the sandbox
unlimited. Both readings cannot stand, and neither names the setting that
caused it.

Reachable from every surface that takes a size: --max-memory, --max-disk,
[limits].memory, [limits].disk, and the builder.

The fix

The suffix resolves to a scale and the multiply becomes checked_mul, so a
value that does not fit is reported as byte size out of range: <value>,
naming what was written. The largest value each suffix can carry still parses,
so this refuses what does not fit rather than trimming the usable range.

ByteSize::kib, mib and gib keep their unchecked multiplies on purpose.
They take a number the caller already holds rather than text the caller wrote,
so the question they answer is different, and changing their signatures would
be a breaking change to a public type for a case no parse path reaches.

Testing

test_bytesize_that_does_not_fit_is_an_error_not_a_ceiling_of_zero covers the
overflowing value for each of the three suffixes and pins the boundary that
must still parse. Verified it fails against the previous behaviour: with the
multiply put back, the test reports that 17179869184G was accepted.

cargo test -p sandlock-core --lib: 683 pass.
cargo test -p sandlock-core --test integration: 395 pass.

Where this comes from

This is one commit lifted out of #185, which you suggested deferring to the
next release. I agree with deferring that one, but this defect is independent
of everything else in it and costs 40 lines, so it seemed worth offering on
its own rather than holding a silent SIGKILL back for a release cycle. Take it
or leave it for the same batch, either is fine.

…t to zero

`ByteSize::parse` reads the digits, matches the suffix and then multiplies,
and that multiply was unchecked. In a debug build it panics; in a release
build it wraps, which is the case that matters, because it wraps into a
number the caller never wrote and nothing reports it.

`memory = "17179869184G"` is exactly 2^64 bytes. It wrapped to 0 and
installed a ceiling of zero, and a memory ceiling of zero is not inert: the
supervisor registers the handler on `is_some()`, so the guest is SIGKILLed on
its first anonymous mmap while `/proc/meminfo` inside the sandbox reports the
sandbox unlimited. The two readings cannot both stand, and neither of them
names the setting that caused it.

The suffix now resolves to a scale and the multiply is `checked_mul`, so a
value that does not fit is `byte size out of range: <value>`, naming what was
written. The largest value each suffix can carry still parses, so this refuses
what does not fit rather than trimming the usable range.

`ByteSize::kib`, `mib` and `gib` keep their unchecked multiplies. They take a
number the caller already holds rather than text the caller wrote, so the
question they answer is different, and changing their signatures would be a
breaking change to a public type for a case no parse path reaches.
@congwang-mk
congwang-mk merged commit 80ffbb6 into multikernel:main Aug 6, 2026
13 checks passed
@congwang-mk

Copy link
Copy Markdown
Contributor

Thanks for the quick fix!

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.

2 participants