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);