public inbox for netfilter-devel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] netfilter: nf_conntrack_sip: add bounds-checked port parsing helper
@ 2026-03-13 19:52 Jenny Guanni Qu
  2026-03-13 23:36 ` Florian Westphal
  0 siblings, 1 reply; 4+ messages in thread
From: Jenny Guanni Qu @ 2026-03-13 19:52 UTC (permalink / raw)
  To: pablo, kadlec; +Cc: netfilter-devel, fw, klaudia, dawid, Jenny Guanni Qu

Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(),
and ct_sip_parse_request() with a new sip_parse_port() helper that
validates each digit against the buffer limit, eliminating the use of
simple_strtoul() which assumes NUL-terminated strings.

The previous code dereferenced pointers without bounds checks after
sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated
skb data. A port that reaches the buffer limit without a trailing
character is also rejected as malformed.

Based on a suggestion by Florian Westphal.

Fixes: 05e3ced297fe ("[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper")
Reported-by: Klaudia Kloc <klaudia@vidocsecurity.com>
Reported-by: Dawid Moczadło <dawid@vidocsecurity.com>
Suggested-by: Florian Westphal <fw@strlen.de>
Tested-by: Jenny Guanni Qu <qguanni@gmail.com>
Signed-off-by: Jenny Guanni Qu <qguanni@gmail.com>
---
 net/netfilter/nf_conntrack_sip.c | 80 +++++++++++++++++++++++---------
 1 file changed, 57 insertions(+), 23 deletions(-)

diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index d0eac27f6ba0..00ecb5df5b5d 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp,
 	return 1;
 }
 
+/* Parse optional port number after IP address.
+ * Returns false on malformed input, true otherwise.
+ * If port is non-NULL, stores parsed port in network byte order.
+ * If no port is present, sets *port to default SIP port.
+ */
+static bool sip_parse_port(const char *dptr, const char **endp,
+			   const char *limit, __be16 *port)
+{
+	unsigned int p = 0;
+	int len = 0;
+
+	if (dptr >= limit)
+		return false;
+
+	if (*dptr != ':') {
+		if (port)
+			*port = htons(SIP_PORT);
+		if (endp)
+			*endp = dptr;
+		return true;
+	}
+
+	dptr++; /* skip ':' */
+
+	while (dptr < limit && isdigit(*dptr)) {
+		p = p * 10 + (*dptr - '0');
+		dptr++;
+		len++;
+		if (len > 5) /* max "65535" */
+			return false;
+	}
+
+	if (len == 0)
+		return false;
+
+	/* reached limit while parsing port */
+	if (dptr >= limit)
+		return false;
+
+	if (port) {
+		if (p < 1024 || p > 65535)
+			return false;
+		*port = htons(p);
+	}
+
+	if (endp)
+		*endp = dptr;
+
+	return true;
+}
+
 /* skip ip address. returns its length. */
 static int epaddr_len(const struct nf_conn *ct, const char *dptr,
 		      const char *limit, int *shift)
@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr,
 		return 0;
 	}
 
-	/* Port number */
-	if (*dptr == ':') {
-		dptr++;
-		dptr += digits_len(ct, dptr, limit, shift);
-	}
+	if (!sip_parse_port(dptr, &dptr, limit, NULL))
+		return 0;
 	return dptr - aux;
 }
 
@@ -241,7 +289,6 @@ int ct_sip_parse_request(const struct nf_conn *ct,
 {
 	const char *start = dptr, *limit = dptr + datalen, *end;
 	unsigned int mlen;
-	unsigned int p;
 	int shift = 0;
 
 	/* Skip method and following whitespace */
@@ -267,14 +314,8 @@ int ct_sip_parse_request(const struct nf_conn *ct,
 
 	if (!sip_parse_addr(ct, dptr, &end, addr, limit, true))
 		return -1;
-	if (end < limit && *end == ':') {
-		end++;
-		p = simple_strtoul(end, (char **)&end, 10);
-		if (p < 1024 || p > 65535)
-			return -1;
-		*port = htons(p);
-	} else
-		*port = htons(SIP_PORT);
+	if (!sip_parse_port(end, &end, limit, port))
+		return -1;
 
 	if (end == dptr)
 		return 0;
@@ -509,7 +550,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
 			    union nf_inet_addr *addr, __be16 *port)
 {
 	const char *c, *limit = dptr + datalen;
-	unsigned int p;
 	int ret;
 
 	ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
@@ -520,14 +560,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
 
 	if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true))
 		return -1;
-	if (*c == ':') {
-		c++;
-		p = simple_strtoul(c, (char **)&c, 10);
-		if (p < 1024 || p > 65535)
-			return -1;
-		*port = htons(p);
-	} else
-		*port = htons(SIP_PORT);
+	if (!sip_parse_port(c, &c, limit, port))
+		return -1;
 
 	if (dataoff)
 		*dataoff = c - dptr;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] netfilter: nf_conntrack_sip: add bounds-checked port parsing helper
  2026-03-13 19:52 [PATCH v2] netfilter: nf_conntrack_sip: add bounds-checked port parsing helper Jenny Guanni Qu
@ 2026-03-13 23:36 ` Florian Westphal
  2026-03-31 23:32   ` Pablo Neira Ayuso
  2026-04-02 12:52   ` Florian Westphal
  0 siblings, 2 replies; 4+ messages in thread
From: Florian Westphal @ 2026-03-13 23:36 UTC (permalink / raw)
  To: Jenny Guanni Qu; +Cc: pablo, kadlec, netfilter-devel, klaudia, dawid

Jenny Guanni Qu <qguanni@gmail.com> wrote:
> +	/* reached limit while parsing port */
> +	if (dptr >= limit)
> +		return false;
> +
> +	if (port) {
> +		if (p < 1024 || p > 65535)
> +			return false;
> +		*port = htons(p);
> +	}

I like the port range check, but should we make this universal?

	if (p < 1024 || p > 65535)
		return false;
	if (port)
		*port = htons(p);

?

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] netfilter: nf_conntrack_sip: add bounds-checked port parsing helper
  2026-03-13 23:36 ` Florian Westphal
@ 2026-03-31 23:32   ` Pablo Neira Ayuso
  2026-04-02 12:52   ` Florian Westphal
  1 sibling, 0 replies; 4+ messages in thread
From: Pablo Neira Ayuso @ 2026-03-31 23:32 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Jenny Guanni Qu, kadlec, netfilter-devel, klaudia, dawid

Hi,

On Sat, Mar 14, 2026 at 12:36:33AM +0100, Florian Westphal wrote:
> Jenny Guanni Qu <qguanni@gmail.com> wrote:
> > +	/* reached limit while parsing port */
> > +	if (dptr >= limit)
> > +		return false;
> > +
> > +	if (port) {
> > +		if (p < 1024 || p > 65535)
> > +			return false;
> > +		*port = htons(p);
> > +	}
> 
> I like the port range check, but should we make this universal?
> 
> 	if (p < 1024 || p > 65535)
> 		return false;
> 	if (port)
> 		*port = htons(p);
> 
> ?

Can anyone have a look into following up on this?

Otherwise, I will try to have a look for the next PR with fixes.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] netfilter: nf_conntrack_sip: add bounds-checked port parsing helper
  2026-03-13 23:36 ` Florian Westphal
  2026-03-31 23:32   ` Pablo Neira Ayuso
@ 2026-04-02 12:52   ` Florian Westphal
  1 sibling, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2026-04-02 12:52 UTC (permalink / raw)
  To: Jenny Guanni Qu; +Cc: pablo, kadlec, netfilter-devel, klaudia, dawid

Florian Westphal <fw@strlen.de> wrote:
> Jenny Guanni Qu <qguanni@gmail.com> wrote:
> > +	/* reached limit while parsing port */
> > +	if (dptr >= limit)
> > +		return false;
> > +
> > +	if (port) {
> > +		if (p < 1024 || p > 65535)
> > +			return false;
> > +		*port = htons(p);
> > +	}
> 
> I like the port range check, but should we make this universal?
> 
> 	if (p < 1024 || p > 65535)
> 		return false;
> 	if (port)
> 		*port = htons(p);

Ping, will you send a v3 or do you expect us to take over from here?

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-04-02 12:52 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-13 19:52 [PATCH v2] netfilter: nf_conntrack_sip: add bounds-checked port parsing helper Jenny Guanni Qu
2026-03-13 23:36 ` Florian Westphal
2026-03-31 23:32   ` Pablo Neira Ayuso
2026-04-02 12:52   ` Florian Westphal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox