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>