The branch main has been updated by markj:

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

commit 96b29c7f0cffd377a757ad8ccc0cdd8fcb96d0dd
Author:     Mark Johnston <ma...@freebsd.org>
AuthorDate: 2025-07-28 15:46:37 +0000
Commit:     Mark Johnston <ma...@freebsd.org>
CommitDate: 2025-07-28 16:19:38 +0000

    if_ovpn: Destroy cloned interfaces via a prison removal callback
    
    A if_ovpn interface carries a reference to a socket, which has a
    credential reference, which holds a reference on the containing prison
    and prevents SYSUNINITs from being invoked.  So, register a
    PR_METHOD_REMOVE callback and destroy the cloner from there instead,
    since that mechanism doesn't require the prison refcount to drop to zero
    first.
    
    This fixes a bug where jails get left stuck in the DYING state after
    running if_ovpn regression tests.
    
    Reviewed by:    kp
    MFC after:      2 weeks
    Sponsored by:   Stormshield
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D51526
---
 sys/net/if_ovpn.c | 48 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 40 insertions(+), 8 deletions(-)

diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c
index fdbf70465338..fe3e7bbd7fff 100644
--- a/sys/net/if_ovpn.c
+++ b/sys/net/if_ovpn.c
@@ -34,11 +34,13 @@
 #include <sys/epoch.h>
 #include <sys/file.h>
 #include <sys/filedesc.h>
+#include <sys/jail.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/module.h>
 #include <sys/nv.h>
+#include <sys/osd.h>
 #include <sys/priv.h>
 #include <sys/protosw.h>
 #include <sys/rmlock.h>
@@ -2784,23 +2786,53 @@ vnet_ovpn_init(const void *unused __unused)
 VNET_SYSINIT(vnet_ovpn_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
     vnet_ovpn_init, NULL);
 
-static void
-vnet_ovpn_uninit(const void *unused __unused)
+static int
+ovpn_prison_remove(void *obj, void *data __unused)
 {
-       if_clone_detach(V_ovpn_cloner);
+#ifdef VIMAGE
+       struct prison *pr;
+
+       pr = obj;
+       if (prison_owns_vnet(pr)) {
+               CURVNET_SET(pr->pr_vnet);
+               if (V_ovpn_cloner != NULL) {
+                       ifc_detach_cloner(V_ovpn_cloner);
+                       V_ovpn_cloner = NULL;
+               }
+               CURVNET_RESTORE();
+       }
+#endif
+       return (0);
 }
-VNET_SYSUNINIT(vnet_ovpn_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
-    vnet_ovpn_uninit, NULL);
 
 static int
 ovpnmodevent(module_t mod, int type, void *data)
 {
+       static int ovpn_osd_jail_slot;
+
        switch (type) {
-       case MOD_LOAD:
-               /* Done in vnet_ovpn_init() */
+       case MOD_LOAD: {
+               /*
+                * Registration is handled in vnet_ovpn_init(), but cloned
+                * interfaces must be destroyed via PR_METHOD_REMOVE since they
+                * hold a reference to the prison via the UDP socket, which
+                * prevents the prison from being destroyed.
+                */
+               osd_method_t methods[PR_MAXMETHOD] = {
+                       [PR_METHOD_REMOVE] = ovpn_prison_remove,
+               };
+               ovpn_osd_jail_slot = osd_jail_register(NULL, methods);
                break;
+       }
        case MOD_UNLOAD:
-               /* Done in vnet_ovpn_uninit() */
+               if (ovpn_osd_jail_slot != 0)
+                       osd_jail_deregister(ovpn_osd_jail_slot);
+               CURVNET_SET(vnet0);
+               if (V_ovpn_cloner != NULL) {
+                       ifc_detach_cloner(V_ovpn_cloner);
+                       V_ovpn_cloner = NULL;
+               }
+               CURVNET_RESTORE();
                break;
        default:
                return (EOPNOTSUPP);

Reply via email to