CVE-2022-35922 (Rust, published 2022-08-01T22:15Z)
Description: value: Rust-WebSocket is a WebSocket (RFC6455) library written in Rust. In versions prior to 0.26.5 untrusted websocket connections can cause an out-of-memory (OOM) process abort in a client or a server. The root cause of the issue is during dataframe parsing. Affected versions would allocate a buffer based on the declared dataframe size, which may come from an untrusted source. When `Vec::with_capacity` fails to allocate, the default Rust allocator will abort the current process, killing all threads. This affects only sync (non-Tokio) implementation. Async version also does not limit memory, but does not use `with_capacity`, so DoS can happen only when bytes for oversized dataframe or message actually got delivered by the attacker. The crashes are fixed in version 0.26.5 by imposing default dataframe size limits. Affected users are advised to update to this version. Users unable to upgrade are advised to filter websocket traffic externally or to only accept trusted traffic.
Severity: nan (CVSS v3 base score: 7.5)
Weakness: CWE-770 \u2014 Allocation of Resources Without Limits or Throttling
The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor.
Repository: https://github.com/websockets-rs/rust-websocket
Files changed:
src/receiver.rs
websocket-base/src/dataframe.rs
Commit message: Implement dataframe and message size limits


Vulnerable code:
		DataFrame::read_dataframe(reader, self.mask)
				0 => self.buffer.push(next),

Fixed code:
const DEFAULT_MAX_DATAFRAME_SIZE : usize = 1024*1024*100;
const DEFAULT_MAX_MESSAGE_SIZE : usize = 1024*1024*200;
const MAX_DATAFRAMES_IN_ONE_MESSAGE: usize = 1024*1024;

	// u32s instead uf usizes to economize used memory by this struct
	max_dataframe_size: u32,
	max_message_size: u32,
	/// 
	/// Uses built-in limits for dataframe and message sizes. 
		Receiver::new_with_limits(mask, DEFAULT_MAX_DATAFRAME_SIZE, DEFAULT_MAX_MESSAGE_SIZE)
	}

	/// Create a new Receiver using the specified Reader, with configurable limits
	/// 
	/// Sizes should not be larger than `u32::MAX`.
	/// 
	/// Note that `max_message_size` denotes message size where no new dataframes would be read,
	/// so actual maximum message size is larger.
	pub fn new_with_limits(mask: bool, max_dataframe_size: usize, max_message_size: usize) -> Receiver {
		let max_dataframe_size: u32 = max_dataframe_size.min(u32::MAX as usize) as u32;
		let max_message_size: u32 = max_message_size.min(u32::MAX as usize) as u32;
			max_dataframe_size,
			max_message_size,
		DataFrame::read_dataframe_with_limit(reader, self.mask, self.max_dataframe_size as usize)
		let mut current_message_length : usize = self.buffer.iter().map(|x|x.data.len()).sum();
			current_message_length += first.data.len();
				0 => {
					current_message_length += next.data.len();
					self.buffer.push(next)
				}

			if !finished {
				if self.buffer.len() >= MAX_DATAFRAMES_IN_ONE_MESSAGE {
					return Err(WebSocketError::ProtocolError(
						"Exceeded count of data frames in one WebSocket message",
					));
				}
				if current_message_length >= self.max_message_size as usize {
					return Err(WebSocketError::ProtocolError(
						"Exceeded maximum WebSocket message size",
					));
				}
			}

	/// Reads a DataFrame from a Reader, or error out if header declares exceeding limit you specify
	pub fn read_dataframe_with_limit<R>(reader: &mut R, should_be_masked: bool, limit: usize) -> WebSocketResult<Self>
	where
		R: Read,
	{
		let header = dfh::read_header(reader)?;

		if header.len > limit as u64 {
			return Err(io::Error::new(io::ErrorKind::InvalidData, "exceeded DataFrame length limit").into());
		}
		let mut data: Vec<u8> = Vec::with_capacity(header.len as usize);
		let read = reader.take(header.len).read_to_end(&mut data)?;
		if (read as u64) < header.len {
			return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "incomplete payload").into());
		}

		DataFrame::read_dataframe_body(header, data, should_be_masked)
	}