]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
netfilter: nf_conntrack_sip: fix Content-Length u32 truncation in sip_help_tcp()
authorLukas Johannes Möller <research@johannes-moeller.dev>
Tue, 10 Mar 2026 21:49:01 +0000 (21:49 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Mar 2026 10:08:52 +0000 (11:08 +0100)
[ Upstream commit fbce58e719a17aa215c724473fd5baaa4a8dc57c ]

sip_help_tcp() parses the SIP Content-Length header with
simple_strtoul(), which returns unsigned long, but stores the result in
unsigned int clen.  On 64-bit systems, values exceeding UINT_MAX are
silently truncated before computing the SIP message boundary.

For example, Content-Length 4294967328 (2^32 + 32) is truncated to 32,
causing the parser to miscalculate where the current message ends.  The
loop then treats trailing data in the TCP segment as a second SIP
message and processes it through the SDP parser.

Fix this by changing clen to unsigned long to match the return type of
simple_strtoul(), and reject Content-Length values that exceed the
remaining TCP payload length.

Fixes: f5b321bd37fb ("netfilter: nf_conntrack_sip: add TCP support")
Signed-off-by: Lukas Johannes Möller <research@johannes-moeller.dev>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/netfilter/nf_conntrack_sip.c

index d0eac27f6ba03cff12350a95ac48b9ed03fb778a..657839a58782a5cc26830f4039d9afba3f53de29 100644 (file)
@@ -1534,11 +1534,12 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
 {
        struct tcphdr *th, _tcph;
        unsigned int dataoff, datalen;
-       unsigned int matchoff, matchlen, clen;
+       unsigned int matchoff, matchlen;
        unsigned int msglen, origlen;
        const char *dptr, *end;
        s16 diff, tdiff = 0;
        int ret = NF_ACCEPT;
+       unsigned long clen;
        bool term;
 
        if (ctinfo != IP_CT_ESTABLISHED &&
@@ -1573,6 +1574,9 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
                if (dptr + matchoff == end)
                        break;
 
+               if (clen > datalen)
+                       break;
+
                term = false;
                for (; end + strlen("\r\n\r\n") <= dptr + datalen; end++) {
                        if (end[0] == '\r' && end[1] == '\n' &&