witness: Allocate in reserve_batch if capacity < MIN_VECTOR_ALLOCATE
What changed, and why it matters
This commit fixes a bug in how the Bitcoin witness data decoder grows its internal buffer. Previously, when decoding witness data, the code could fail to reserve enough space before writing a size value, causing the program to panic and crash. The fix ensures the buffer is always expanded by at least a minimum amount when free space is low.
Treat as a security-relevant bug fix and include in release notes. Backport to maintained release branches. Review other uses of reserve_batch for similar assumptions about guaranteed allocation size. No immediate CVE is required unless a reproducible crash from untrusted network input is confirmed, but the project should assess whether this is reachable from serialized transaction parsing.
Security signals we found
Denial-of-service vector: malformed or crafted witness input can trigger a panic during decoding
Memory allocation boundary condition in serialization/deserialization code
Fix follows a prior related change (#6198), indicating an incomplete patch
Crash occurs in witness parsing, a consensus-critical data structure
Evidence from the diff
In WitnessDecoder::push_bytes, reserve_batch was called when available_capacity == 0. However, reserve_batch only allocates when capacity - len == 0, and it may not allocate up to required_len. If the content vector had some spare capacity but less than needed for a compact-size write, push_bytes could panic when writing the compact size. The fix changes the condition to allocate whenever available_capacity < MIN_VECTOR_ALLOCATE, ensuring at least MIN_VECTOR_ALLOCATE bytes of free space are reserved.
Changed components
primitives/src/witness.rsWitnessDecoder::push_bytesreserve_batch allocation logicInspect captured patch +1 / −1
diff --git a/primitives/src/witness.rs b/primitives/src/witness.rs
index 2806dbd1..2362eb48 100644
--- a/primitives/src/witness.rs
+++ b/primitives/src/witness.rs
@@ -354,7 +354,7 @@ impl WitnessDecoder {
let bytes_needed = required_len - self.content.len();
let available_capacity = self.content.capacity() - self.content.len();
- if available_capacity == 0 {
+ if available_capacity < MIN_VECTOR_ALLOCATE {
let batch_size = bytes_needed.clamp(MIN_VECTOR_ALLOCATE, MAX_VECTOR_ALLOCATE);
self.content.reserve_exact(batch_size);
}
Why this scored 59/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.