diff --git a/crates/tor-bytes/src/reader.rs b/crates/tor-bytes/src/reader.rs index cdd7dcc7f..8234631b9 100644 --- a/crates/tor-bytes/src/reader.rs +++ b/crates/tor-bytes/src/reader.rs @@ -262,7 +262,20 @@ impl<'a> Reader<'a> { /// /// On failure, consumes nothing. pub fn extract_n(&mut self, n: usize) -> Result> { - let mut result = Vec::with_capacity(n); + // This `min` will help us defend against a pathological case where an + // attacker tells us that there are BIGNUM elements forthcoming, and our + // attempt to allocate `Vec::with_capacity(BIGNUM)` makes us panic. + // + // The `min` can be incorrect if E is somehow encodable in zero bytes + // (!?), but that will only cause our initial allocation to be too + // small. + // + // In practice, callers should always check that `n` is reasonable + // before calling this function, and protocol designers should not + // provide e.g. 32-bit counters for object types of which we should + // never allocate u32::MAX. + let n_alloc = std::cmp::min(n, self.remaining()); + let mut result = Vec::with_capacity(n_alloc); let off_orig = self.off; for _ in 0..n { match E::take_from(self) {