Skip to content

SIP TCP framing: unbounded Content-Length buffering + add overflow in read_from_stream #111

Description

@ryanmurf

Summary

TcpConnectionManager::read_from_stream frames a SIP message using the
Content-Length header, but (1) the length is parsed as an unbounded usize
and added to the body offset without overflow protection, and (2) the body-read
loop has no size cap, so a large Content-Length drives unbounded buffering.

Location

crates/asterisk-sip/src/transport/mod.rs:351-364

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

extract_content_length (:431) parses the raw value with no upper bound.

Impact

  • body_start + content_length overflows for Content-Length near
    usize::MAX: panic in debug (arithmetic overflow), wraps in release.
  • The 65535 cap exists only in the outer header-read loop (:368), not the
    inner body loop, so Content-Length: 4000000000 (dribbled) forces the
    connection to buffer gigabytes → memory-exhaustion DoS. The
    MAX_CONTENT_LENGTH check in parse_message runs only after the buffer is
    already filled, so it does not bound this.

Suggested fix (low-risk)

Reject content_length > MAX_CONTENT_LENGTH (65536) immediately after
extraction, and use saturating_add/checked_add for total_needed. Filed
rather than fixed here because a red-capable regression test needs TCP socket
plumbing; recommend pairing the fix with a small framing-math helper that is
unit-testable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions