git: 96b29c7f0cff - main - if_ovpn: Destroy cloned interfaces via a prison removal callback
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 28 Jul 2025 16:19:48 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=96b29c7f0cffd377a757ad8ccc0cdd8fcb96d0dd
commit 96b29c7f0cffd377a757ad8ccc0cdd8fcb96d0dd
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-07-28 15:46:37 +0000
Commit: Mark Johnston <markj@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);