Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Aug 2025 12:56:16 GMT
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 4d84cefbba2c - stable/14 - udp: Fix a inpcb refcount leak in the tunnel receive path
Message-ID:  <202508121256.57CCuGER088511@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/14 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=4d84cefbba2cad514d581d5dfaac7a2ac3ce2912

commit 4d84cefbba2cad514d581d5dfaac7a2ac3ce2912
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-07-25 13:10:24 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-08-12 12:49:43 +0000

    udp: Fix a inpcb refcount leak in the tunnel receive path
    
    When the socket has a tunneling function attached, udp_append() drops
    the inpcb lock before calling it.  To keep the inpcb alive, we bump the
    refcount.  After commit 742e7210d00b we only dropped the reference if
    the tunnel consumed the packet, but it needs to be dropped in either
    case.  if_ovpn is the only driver that can trigger this bug.
    
    Fixes:          742e7210d00b ("udp: allow udp_tun_func_t() to indicate it did not eat the packet")
    Reviewed by:    kp
    MFC after:      2 weeks
    Sponsored by:   Stormshield
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D51505
    
    (cherry picked from commit e1751ef896119d7372035b1b60f18a6342bd0e3b)
---
 sys/netinet/udp_usrreq.c   | 11 ++++++++---
 sys/netinet6/udp6_usrreq.c | 11 ++++++++---
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index d65343fc9997..adf8f0afc125 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -245,7 +245,6 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
 	struct sockaddr_in6 udp_in6;
 #endif
 	struct udpcb *up;
-	bool filtered;
 
 	INP_LOCK_ASSERT(inp);
 
@@ -254,13 +253,19 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
 	 */
 	up = intoudpcb(inp);
 	if (up->u_tun_func != NULL) {
+		bool filtered;
+
 		in_pcbref(inp);
 		INP_RUNLOCK(inp);
 		filtered = (*up->u_tun_func)(n, off, inp, (struct sockaddr *)&udp_in[0],
 		    up->u_tun_ctx);
 		INP_RLOCK(inp);
-		if (filtered)
-			return (in_pcbrele_rlocked(inp));
+		if (in_pcbrele_rlocked(inp))
+			return (1);
+		if (filtered) {
+			INP_RUNLOCK(inp);
+			return (1);
+		}
 	}
 
 	off += sizeof(struct udphdr);
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 8ab159b4e622..4a82315ea2f0 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -143,7 +143,6 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off,
 	struct socket *so;
 	struct mbuf *opts = NULL, *tmp_opts;
 	struct udpcb *up;
-	bool filtered;
 
 	INP_LOCK_ASSERT(inp);
 
@@ -152,13 +151,19 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off,
 	 */
 	up = intoudpcb(inp);
 	if (up->u_tun_func != NULL) {
+		bool filtered;
+
 		in_pcbref(inp);
 		INP_RUNLOCK(inp);
 		filtered = (*up->u_tun_func)(n, off, inp,
 		    (struct sockaddr *)&fromsa[0], up->u_tun_ctx);
 		INP_RLOCK(inp);
-		if (filtered)
-			return (in_pcbrele_rlocked(inp));
+		if (in_pcbrele_rlocked(inp))
+			return (1);
+		if (filtered) {
+			INP_RUNLOCK(inp);
+			return (1);
+		}
 	}
 #if defined(IPSEC) || defined(IPSEC_SUPPORT)
 	/* Check AH/ESP integrity. */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202508121256.57CCuGER088511>