Skip to content

Commit 3189068

Browse files
committed
fix: cap the amount of garbage to search
Cap a DOS vector by setting a limit on the amount of garbage to search for a terminator.
1 parent b047e87 commit 3189068

File tree

1 file changed

+21
-8
lines changed

1 file changed

+21
-8
lines changed

protocol/src/handshake.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,12 @@ impl Handshake<SentVersion> {
472472
fn split_garbage<'b>(&self, buffer: &'b [u8]) -> Result<(&'b [u8], &'b [u8]), Error> {
473473
let terminator = &self.state.remote_garbage_terminator;
474474

475-
if let Some(index) = buffer
475+
// Only search up to the maximum amount of garbage bytes
476+
// allowed in the spec to avoid a DOS vector.
477+
if let Some(index) = buffer[..core::cmp::min(
478+
buffer.len(),
479+
MAX_NUM_GARBAGE_BYTES + NUM_GARBAGE_TERMINTOR_BYTES,
480+
)]
476481
.windows(terminator.len())
477482
.position(|window| window == terminator)
478483
{
@@ -846,32 +851,40 @@ mod tests {
846851

847852
// Test split_garbage error conditions.
848853
//
849-
// 1. NoGarbageTerminator - when buffer exceeds max size without finding terminator
850-
// 2. CiphertextTooSmall - when buffer is too short to possibly contain terminator
854+
// 1. NoGarbageTerminator - Buffer exceeds max size without finding terminator.
855+
// 2. CiphertextTooSmall - Buffer is too short to possibly contain terminator.i
851856
#[test]
852857
fn test_handshake_split_garbage() {
853-
// Create a handshake and bring it to the SentVersion state to test split_garbage
858+
// Create a handshake and bring it to the SentVersion state to test split_garbage.
854859
let handshake = Handshake::<Initialized>::new(Network::Bitcoin, Role::Initiator).unwrap();
855860
let mut buffer = vec![0u8; NUM_ELLIGATOR_SWIFT_BYTES];
856861
let handshake = handshake.send_key(None, &mut buffer).unwrap();
857862

858-
// Create a fake peer key to receive
863+
// Create a fake peer key to receive.
859864
let fake_peer_key = [0u8; NUM_ELLIGATOR_SWIFT_BYTES];
860865
let handshake = handshake.receive_key(fake_peer_key).unwrap();
861866

862-
// Send version to get to SentVersion state
867+
// Send version to get to SentVersion state.
863868
let mut version_buffer = vec![0u8; 1024];
864869
let handshake = handshake.send_version(&mut version_buffer, None).unwrap();
865870

866-
// Test with a buffer that is too long (should fail to find terminator)
871+
// Test with a buffer that is too long (should fail to find terminator).
867872
let test_buffer = vec![0; MAX_NUM_GARBAGE_BYTES + NUM_GARBAGE_TERMINTOR_BYTES];
868873
let result = handshake.split_garbage(&test_buffer);
869874
assert!(matches!(result, Err(Error::NoGarbageTerminator)));
870875

871-
// Test with a buffer that's just short of the required length
876+
// Test with a buffer that's just short of the required length.
872877
let short_buffer = vec![0; MAX_NUM_GARBAGE_BYTES + NUM_GARBAGE_TERMINTOR_BYTES - 1];
873878
let result = handshake.split_garbage(&short_buffer);
874879
assert!(matches!(result, Err(Error::CiphertextTooSmall)));
880+
881+
// Even if terminator is present, it's beyond the search limit.
882+
let mut oversized_buffer = vec![0xEE; 5000];
883+
oversized_buffer.extend_from_slice(&handshake.state.remote_garbage_terminator);
884+
oversized_buffer.extend_from_slice(&[0xFF; 32]);
885+
let result = handshake.split_garbage(&oversized_buffer);
886+
// Should return NoGarbageTerminator because terminator is beyond search limit.
887+
assert!(matches!(result, Err(Error::NoGarbageTerminator)));
875888
}
876889

877890
// Test that receive_key detects V1 protocol when peer's key starts with network magic.

0 commit comments

Comments
 (0)