Conversation
sample() passes the deserialized sampler state directly to Duration::new, which panics on overflow. UniformChar already validates its deserialized UniformInt<u32> for the same reason (rust-random#1831); UniformDuration and UniformDurationMode used a bare derive with no validation. Replace the derived Deserialize for UniformDuration with one that checks the invariants new_inclusive establishes: offset is a valid subsecond nanosecond count, the Small nanos sampler cannot carry a second past u64::MAX, and the Large seconds sampler cannot exceed max_secs or carry past u64::MAX.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CHANGELOG.mdentrySummary
A deserialized
UniformDurationcan panic inDuration::new. This is the unguarded sibling of theUniform<char>problem fixed in #1831: same threat model, same fix shape.Motivation
UniformCharcarries a validating deserializer on its sampler field (src/distr/uniform_other.rs:36, added by #1831):UniformDuration(src/distr/uniform_other.rs:127) and the privateUniformDurationModeuse a barederive(Serialize, Deserialize)with no validation, andsamplefeeds that state straight toDuration::new, which panics on overflow:Smallarm:Duration::new(secs, n), wherencomes from aUniform<u32>whose range is whatever was deserialized. Ifn >= 1_000_000_000the carry can pushsecspastu64::MAX.Largearm:Duration::new(s, n + self.offset). The rejection test only fires whens == max_secs, so a seconds sampler whose maximum exceedsmax_secsis never rejected, andoffsetis never checked to be a valid subsecond count (it can also overflow then + self.offsetaddition).The
UniformInthardening in #1831 only fixedmax()for therange == 0case; it does not reject out-of-rangelow/range, so it is not a guard here.This is only reachable by deserializing untrusted or corrupted sampler state. That is the same threat model the project already accepted when it hardened
Uniform<char>, so I am filing it as a normal bug rather than through the security advisory process. It is not a memory-safety issue.Details
Before, on master (
9e7d328), deserializing and sampling:The new test
test_duration_bad_deser, run against unmodified source:The fix replaces the derived
DeserializeforUniformDurationwith one that checks the invariantsnew_inclusiveestablishes:offsetis a valid subsecond nanosecond count, theSmallnanos sampler cannot carry a second pastu64::MAX, and theLargeseconds sampler cannot exceedmax_secsor carry pastu64::MAX.Mediumneeds no check, sinceDuration::new(nanos / 1e9, nanos % 1e9)cannot overflow for anyu64. Rejection produces a clean serde data error, matching theUniformCharbehaviour and its test.After:
Baseline on master with
--features serdewas112 passed, so the delta is exactly the one new test. Round-tripping a validly constructedUniformDurationis unaffected.cargo fmt --checkandcargo clippy --features serde --all-targetsare clean, andcargo build --no-default-featuresstill builds.