Skip to content

DoS: TCP transport buffers Content-Length bytes with no upper bound (memory exhaustion) #115

Description

@ryanmurf

Summary

TcpTransport::read_from_stream reads a peer-declared Content-Length number of bytes into its buffer with no cap. A stream peer can declare an arbitrarily large body and drive unbounded buffer growth; body_start + content_length can also overflow usize.

Location

crates/asterisk-sip/src/transport/mod.rs, read_from_stream (~line 350):

let content_length = extract_content_length(header_text); // uncapped usize
let body_start = sep_pos + 4;
let total_needed = body_start + content_length;            // can overflow
while buf.len() < total_needed {                           // grows buf unbounded
    let n = stream.read(&mut temp).await?;
    if n == 0 { break; }
    buf.extend_from_slice(&temp[..n]);
}

The if buf.len() > 65535 guard only runs in the pre-separator loop; once the header terminator is found there is no bound on the body read.

Hostile input

On a SIP/TCP connection:

INVITE ... SIP/2.0\r\n...\r\nContent-Length: 4000000000\r\n\r\n<stream bytes...>

The server buffers toward 4 GB (bounded only by attacker bandwidth). The UDP path is already bounded by the parser's MAX_CONTENT_LENGTH (65536); the stream path is not.

Impact

Memory-exhaustion DoS on stream transports (no amplification, but unbounded server-side allocation). Also a latent usize overflow in total_needed.

Fix

Reject a declared Content-Length above a cap (65536, matching the parser) as soon as the headers are in, before allocating/awaiting the body. PR incoming with a RED-capable regression test (the unpatched read loop blocks on the missing body; the test times out).

Axis

DoS — length field drives unbounded allocation; bounds must exist.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions