diff --git a/src/exec_service.rs b/src/exec_service.rs index 40f4f59..fec46cd 100644 --- a/src/exec_service.rs +++ b/src/exec_service.rs @@ -32,6 +32,7 @@ impl FrameDecoder { } let len = u32::from_be_bytes(self.buf[..4].try_into().unwrap()) as usize; if len > FRAME_MAX_LEN { + self.buf.clear(); bail!("exec protocol frame too large: {len} bytes"); } if self.buf.len() < 4 + len { @@ -69,3 +70,23 @@ fn encode_frame(payload: &[u8]) -> Result> { out.extend_from_slice(payload); Ok(out) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn oversized_frame_clears_decoder_state() { + let mut decoder = FrameDecoder::default(); + let too_large = ((FRAME_MAX_LEN + 1) as u32).to_be_bytes(); + assert!(decoder.push(&too_large).is_err()); + + let valid = encode_response(&ExecResponse::Exit { code: Some(0) }).unwrap(); + let frames = decoder.push(&valid).unwrap(); + assert_eq!(frames.len(), 1); + assert_eq!( + decode_response(&frames[0]).unwrap(), + ExecResponse::Exit { code: Some(0) } + ); + } +} diff --git a/src/file_transfer.rs b/src/file_transfer.rs index 3453049..379aad2 100644 --- a/src/file_transfer.rs +++ b/src/file_transfer.rs @@ -123,6 +123,7 @@ impl FrameDecoder { } let len = u32::from_be_bytes(self.buf[..4].try_into().unwrap()) as usize; if len > FRAME_MAX_LEN { + self.buf.clear(); bail!("file protocol frame too large: {len} bytes"); } if self.buf.len() < 4 + len { @@ -288,6 +289,18 @@ mod tests { assert_eq!(frames.len(), 1); } + #[test] + fn oversized_frame_clears_decoder_state() { + let mut decoder = FrameDecoder::default(); + let too_large = ((FRAME_MAX_LEN + 1) as u32).to_be_bytes(); + assert!(decoder.push(&too_large).is_err()); + + let valid = encode_response(&FileResponse::Ok).unwrap(); + let frames = decoder.push(&valid).unwrap(); + assert_eq!(frames.len(), 1); + assert_eq!(decode_response(&frames[0]).unwrap(), FileResponse::Ok); + } + #[test] fn copy_endpoint_parses_scp_style_but_not_windows_drive() { assert_eq!(