Skip to content

parse_cseq: reject overlarge CSeq numbers to avoid unsigned overflow#553

Open
hecko wants to merge 1 commit into
masterfrom
hecko/parse-cseq-num-overflow
Open

parse_cseq: reject overlarge CSeq numbers to avoid unsigned overflow#553
hecko wants to merge 1 commit into
masterfrom
hecko/parse-cseq-num-overflow

Conversation

@hecko

@hecko hecko commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Bug

parse_cseq (core/sip/parse_cseq.cpp) accumulates the numeric CSeq field digit-by-digit into sip_cseq::num (an unsigned int) with no bound check:

default:
    if(!IS_DIGIT(*c)){
        return MALFORMED_SIP_MSG;
    }
    cseq->num = cseq->num*10 + *c - '0';
    break;

A CSeq header whose number is wider than 32 bits (e.g. CSeq: 99999999999999 INVITE) silently wraps the accumulator, so two distinct on-wire CSeq strings can collapse to the same 32-bit value. num feeds transaction matching (core/sip/trans_table.cpp) and is propagated to the application layer, so the wrap can corrupt transaction matching / request routing. It is triggerable by a single crafted request or reply — no dialog or auth required. Every other scalar SIP field parser in the tree (Content-Length, the parse_100rel READ_NUMBER path) already rejects overlarge values; parse_cseq was the gap.

Fix

Reject the header as malformed once the next digit would overflow UINT_MAX:

if(cseq->num > (UINT_MAX - (unsigned int)(*c - '0')) / 10){
    return MALFORMED_SIP_MSG;
}
cseq->num = cseq->num*10 + *c - '0';

Validation

  • Confirmed sip_cseq::num is unsigned int (parse_cseq.h) and that the accumulation has no existing guard in current master.
  • The added check only rejects numbers that do not fit in 32 bits (which the wire format does not allow anyway); all valid CSeq values are unaffected.

Acknowledgement

Backport of the intent of the yeti-switch/sems fix, commit f9d7c3f2c789c74dddfc3231b4cec8420b2bbfcd ("fix Scalar Fields with Overlarge Values checking"). The bound check is expressed with the primitives available in this tree rather than yeti's helper macros. Thanks to the yeti-switch maintainers.


Generated by Claude Code

parse_cseq accumulates the numeric CSeq field digit-by-digit into the
unsigned int sip_cseq::num with no bound check. A CSeq header with a
number wider than 32 bits (e.g. 'CSeq: 99999999999999 INVITE') silently
wraps, so distinct on-wire CSeq strings can collapse to the same value.
That number feeds transaction matching, so the wrap can corrupt matching
and mis-route in/out requests. Every other scalar SIP field parser in the
codebase already rejects overlarge values.

Reject the header once the accumulator would exceed UINT_MAX. Backport of
the intent of yeti-switch/sems f9d7c3f2.
Copilot AI review requested due to automatic review settings July 10, 2026 03:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because no GitHub Actions runner was available. Make sure your repository has a runner available to run Copilot's review, or add a copilot-setup-steps.yml file specifying one with the runs-on attribute. See the docs for more details.

This PR addresses a parsing bug in parse_cseq where overly large numeric CSeq values could overflow an unsigned int accumulator and silently wrap, potentially corrupting SIP transaction matching.

Changes:

  • Add an overflow guard while accumulating sip_cseq::num digit-by-digit.
  • Include a header to access UINT_MAX for the overflow calculation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread core/sip/parse_cseq.cpp

#include "log.h"

#include <limits.h>
Comment thread core/sip/parse_cseq.cpp
Comment on lines +70 to 78
// reject overlarge CSeq numbers: the RFC 3261 CSeq value is a
// 32-bit quantity and 'num' is unsigned int; without this guard
// the accumulation silently wraps, so distinct on-wire CSeq
// strings can collapse to the same value and corrupt
// transaction matching.
if(cseq->num > (UINT_MAX - (unsigned int)(*c - '0')) / 10){
return MALFORMED_SIP_MSG;
}
cseq->num = cseq->num*10 + *c - '0';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants