fix unrecoverable Err(Overflow) in websocket frame parser

This commit is contained in:
maotao 2022-06-22 15:45:34 +08:00
parent 265fa0d050
commit ca02dc4630
2 changed files with 31 additions and 15 deletions

View File

@ -1,7 +1,8 @@
# Changes # Changes
## Unreleased - 2021-xx-xx ## Unreleased - 2021-xx-xx
### Fixed
- Websocket parser throw endless Overflow after received oversized frame.
## 3.1.0 - 2022-06-11 ## 3.1.0 - 2022-06-11
### Changed ### Changed

View File

@ -17,7 +17,6 @@ impl Parser {
fn parse_metadata( fn parse_metadata(
src: &[u8], src: &[u8],
server: bool, server: bool,
max_size: usize,
) -> Result<Option<(usize, bool, OpCode, usize, Option<[u8; 4]>)>, ProtocolError> { ) -> Result<Option<(usize, bool, OpCode, usize, Option<[u8; 4]>)>, ProtocolError> {
let chunk_len = src.len(); let chunk_len = src.len();
@ -60,20 +59,12 @@ impl Parser {
return Ok(None); return Ok(None);
} }
let len = u64::from_be_bytes(TryFrom::try_from(&src[idx..idx + 8]).unwrap()); let len = u64::from_be_bytes(TryFrom::try_from(&src[idx..idx + 8]).unwrap());
if len > max_size as u64 {
return Err(ProtocolError::Overflow);
}
idx += 8; idx += 8;
len as usize len as usize
} else { } else {
len as usize len as usize
}; };
// check for max allowed size
if length > max_size {
return Err(ProtocolError::Overflow);
}
let mask = if server { let mask = if server {
if chunk_len < idx + 4 { if chunk_len < idx + 4 {
return Ok(None); return Ok(None);
@ -98,11 +89,10 @@ impl Parser {
max_size: usize, max_size: usize,
) -> Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError> { ) -> Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError> {
// try to parse ws frame metadata // try to parse ws frame metadata
let (idx, finished, opcode, length, mask) = let (idx, finished, opcode, length, mask) = match Parser::parse_metadata(src, server)? {
match Parser::parse_metadata(src, server, max_size)? { None => return Ok(None),
None => return Ok(None), Some(res) => res,
Some(res) => res, };
};
// not enough data // not enough data
if src.len() < idx + length { if src.len() < idx + length {
@ -112,6 +102,12 @@ impl Parser {
// remove prefix // remove prefix
src.advance(idx); src.advance(idx);
// check for max allowed size
if length > max_size {
src.advance(length);
return Err(ProtocolError::Overflow);
}
// no need for body // no need for body
if length == 0 { if length == 0 {
return Ok(Some((finished, opcode, None))); return Ok(Some((finished, opcode, None)));
@ -339,6 +335,25 @@ mod tests {
} }
} }
#[test]
fn test_parse_frame_max_size_recoverability() {
let mut buf =
BytesMut::from(&[0b0000_0001u8, 0b0000_0010u8, 0b0000_0000u8, 0b0000_0000u8][..]);
buf.extend(&[0b0000_0010u8, 0b0000_0010u8, 0xffu8, 0xffu8]);
assert_eq!(buf.len(), 8);
if let Err(ProtocolError::Overflow) = Parser::parse(&mut buf, false, 1) {
} else {
unreachable!("error");
}
assert_eq!(buf.len(), 4);
let frame = extract(Parser::parse(&mut buf, false, 2));
assert!(!frame.finished);
assert_eq!(frame.opcode, OpCode::Binary);
assert_eq!(frame.payload, Bytes::from(vec![0xffu8, 0xffu8]));
assert_eq!(buf.len(), 0);
}
#[test] #[test]
fn test_ping_frame() { fn test_ping_frame() {
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();