The branch main has been updated by markj:

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

commit e1751ef896119d7372035b1b60f18a6342bd0e3b
Author:     Mark Johnston <ma...@freebsd.org>
AuthorDate: 2025-07-25 13:10:24 +0000
Commit:     Mark Johnston <ma...@freebsd.org>
CommitDate: 2025-07-25 17:39:00 +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
---
 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 dafbaf6dc672..42cfb919e263 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -243,7 +243,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);
 
@@ -252,13 +251,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 304effa26e01..b3ed16fda713 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -142,7 +142,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);
 
@@ -151,13 +150,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);
+               }
        }
 
        off += sizeof(struct udphdr);

Reply via email to