Skip to content

Commit 6c3c80a

Browse files
authored
Merge commit from fork
Bound both the Vec allocation and loop iteration count by the remaining packet data when parsing SSH_MSG_USERAUTH_INFO_RESPONSE. Previously, the response count was read as a u32 from the client and passed directly to Vec::with_capacity(), allowing a malicious client to trigger a multi-GB allocation with a single small packet, crashing the server via OOM. The fix caps the count to the maximum number of responses that could fit in the remaining packet data (each needs at least 4 bytes for a length prefix), bounding allocation to at most the packet size (~256KB).
1 parent a9057ed commit 6c3c80a

1 file changed

Lines changed: 7 additions & 1 deletion

File tree

russh/src/server/encrypted.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,13 @@ async fn read_userauth_info_response<H: Handler + Send, R: Reader>(
522522
if let Some(CurrentRequest::KeyboardInteractive { ref submethods }) = auth_request.current {
523523
let n = map_err!(u32::decode(r))?;
524524

525-
let mut responses = Vec::with_capacity(n as usize);
525+
// Bound both allocation and iteration by remaining packet data to
526+
// prevent a malicious client from causing a multi-GB allocation or
527+
// billions of loop iterations with a crafted count.
528+
// Each response needs at least 4 bytes (length prefix).
529+
let max_responses = r.remaining_len().saturating_add(3) / 4;
530+
let n = (n as usize).min(max_responses);
531+
let mut responses = Vec::with_capacity(n);
526532
for _ in 0..n {
527533
responses.push(Bytes::decode(r).ok())
528534
}

0 commit comments

Comments
 (0)