Fix SerializedSignature iteration stack overflow
What changed, and why it matters
This commit fixes a programming bug where iterating over a serialized ECDSA signature would cause the program to call itself forever, eventually crashing with a stack overflow. The fix changes one line so the iterator uses the actual byte data instead of accidentally re-entering the same function. A new test was added to confirm iteration now works correctly.
Upgrade to a version containing this commit. If upgrading is not possible, avoid iterating over `SerializedSignature` directly; instead deref to a slice first (e.g., `&**serialized_sig`) before iterating.
Security signals we found
Denial-of-service vector: any code path that iterates over a SerializedSignature would crash the process with a stack overflow
Fix is a one-line dereference correction in an iterator implementation
Regression test added to prevent recurrence
Evidence from the diff
The IntoIterator implementation for &SerializedSignature had (*self).iter(), which dereferences the reference to a SerializedSignature and calls .iter(). Because SerializedSignature likely implements Deref to [u8] and iter() on it resolves back through IntoIterator for &SerializedSignature, this created infinite recursion and a stack overflow at runtime. The fix uses (**self).iter() to deref through to the underlying [u8] slice and invoke slice iteration directly. A regression test iterate_serialized_signature was added.
Changed components
bitcoin/src/crypto/ecdsa.rsSerializedSignature IntoIterator implementationInspect captured patch +14 / −3
diff --git a/bitcoin/src/crypto/ecdsa.rs b/bitcoin/src/crypto/ecdsa.rs
index 58c0b028..e39cb1eb 100644
--- a/bitcoin/src/crypto/ecdsa.rs
+++ b/bitcoin/src/crypto/ecdsa.rs
@@ -199,7 +199,7 @@ impl<'a> IntoIterator for &'a SerializedSignature {
type Item = &'a u8;
#[inline]
- fn into_iter(self) -> Self::IntoIter { (*self).iter() }
+ fn into_iter(self) -> Self::IntoIter { (**self).iter() }
}
/// Error encountered while parsing an ECDSA signature from a byte slice.
@@ -335,11 +335,12 @@ impl<'a> Arbitrary<'a> for Signature {
mod tests {
use super::*;
+ const TEST_SIGNATURE_HEX: &str = "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45";
+
#[test]
fn write_serialized_signature() {
- let hex = "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45";
let sig = Signature {
- signature: secp256k1::ecdsa::Signature::from_str(hex).unwrap(),
+ signature: secp256k1::ecdsa::Signature::from_str(TEST_SIGNATURE_HEX).unwrap(),
sighash_type: EcdsaSighashType::All,
};
@@ -348,4 +349,14 @@ mod tests {
assert_eq!(sig.to_vec(), buf)
}
+
+ #[test]
+ fn iterate_serialized_signature() {
+ let sig = Signature {
+ signature: secp256k1::ecdsa::Signature::from_str(TEST_SIGNATURE_HEX).unwrap(),
+ sighash_type: EcdsaSighashType::All,
+ };
+
+ assert_eq!(sig.serialize().iter().copied().collect::<Vec<u8>>(), sig.to_vec());
+ }
}
Why this scored 44/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.