Encephala
Encephala

Reputation: 348

In a custom network protocol that prepends messages with their length, how do you prevent malicious packets from causing memory exhaustion?

For learning purposes, I'm writing a basic network protocol over TcpStreams. In order to delimit individual messages, I was using read_until, but because the data sent can contain any bytes, this can't work. So the next best option seems to be to prepend every message with the length and then read that many bytes from the stream.

Naively, this could be implemented as such:

fn read(stream: &mut TcpStream) -> Vec<u8> {
    let mut length_buffer = [0_u8; 8];
    stream.read_exact(&mut length_buffer); // Ignoring errors for the example
    let length = u64::from_le_bytes(length_buffer);

    let mut result = vec![0_u8; length as usize];
    stream.read_exact(&mut result); // Ignoring errors for the example

    result
}

However, let's imagine a server is using this read function. A malicious user could send a packet: [255, 255, 255, 255, 255, 255, 255, 255], causing the server to attempt to allocate 18446744073709551615 bytes of memory, which will obviously fail and crash the program.

How could you deal with this? Options I can think of are:

But neither of these seem right. What is done in practice for public-facing server protocols?

Upvotes: 0

Views: 94

Answers (0)

Related Questions