git: 8254b0dec02b - main - kern: mac: add various jail MAC hooks

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Fri, 16 Jan 2026 00:24:19 UTC
The branch main has been updated by kevans:

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

commit 8254b0dec02b376dae259cd2043513842d827bd8
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-10-21 03:42:50 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2026-01-16 00:23:39 +0000

    kern: mac: add various jail MAC hooks
    
    This adds the following hooks:
     - mpo_prison_check_attach: check for subject capability to attach to
        a given jail
     - mpo_prison_check_create: check for subject capability to create a
        jail with the given option set
     - mpo_prison_check_get: check for subject capability to fetch the
        given parameters for a jail
     - mpo_prison_check_set: check for subject capability to set the
        given parameters for a jail
     - mpo_prison_check_remove: check for subject capability to remove the
        jail
    
    check_get wouldn't typically be a privileged operation, but is included
    to give MAC policies a wider range of capabilities at a relatively low
    cost.  We also add two more for the purpose of label propagation:
     - mpo_prison_created: surface the creation of a jail so that one can
        do propagation to, e.g., the root vnode or any mounts
     - mpo_prison_attached: attach an existing process to the jail so that
        one can propagate the jail label to the process, as appropriate.
    
    It is unclear if this is preferred vs. having separate associate entry
    points for each type of object we might associate.  That would split
    these up like so:
    
     - prison_created -> prison_associate_vnode
     - prison_attached -> prison_associate_proc
    
    Some sample policy ideas that should be feasible to implement with this
    set of hooks, in case it's inspiring:
     - mac_bomb: policy that allows a poudriere user to construct jails
        without root privilege, given a restricted set of jail parameters.
        Slap a warning label on it.
     - mac_capsule: policy that realizes the capsule idea that I pitched[0]
        on -jail@ to create jails that are effectively immutable once
        sealed, using these hooks and a label.
    
    Perhaps a silly idea, but a downstream could consider a scenario where
    it can implement special jail enumeration using a MAC policy and a
    cooperating application that specifies non-parameter options to filter
    the results.
    
    [0] https://lists.freebsd.org/archives/freebsd-jail/2025-September/000550.html
    
    Reviewed by:    olce (slightly earlier version)
    Differential Revision:  https://reviews.freebsd.org/D53954
---
 share/man/man4/mac.4             |   2 +
 sys/kern/kern_jail.c             | 126 ++++++++++++++++++++++++------
 sys/security/mac/mac_framework.h |  12 +++
 sys/security/mac/mac_policy.h    |  25 ++++++
 sys/security/mac/mac_prison.c    |  87 +++++++++++++++++++++
 sys/security/mac_stub/mac_stub.c |  83 ++++++++++++++++++++
 sys/security/mac_test/mac_test.c | 161 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 474 insertions(+), 22 deletions(-)

diff --git a/share/man/man4/mac.4 b/share/man/man4/mac.4
index 134086139f53..2e2abbdb2c06 100644
--- a/share/man/man4/mac.4
+++ b/share/man/man4/mac.4
@@ -115,6 +115,8 @@ Policy enforcement is divided into the following areas of the system:
 .Bl -ohang
 .It Sy "File System"
 File system mounts, modifying directories, modifying files, etc.
+.It Sy Jails
+Creating, modifying, removing, and attaching to jails
 .It Sy KLD
 Loading, unloading, and retrieving statistics on loaded kernel modules
 .It Sy Network
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 8c224597bdf5..b5f61e3957d9 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -36,6 +36,7 @@
 
 #include <sys/param.h>
 #include <sys/types.h>
+#include <sys/ctype.h>
 #include <sys/kernel.h>
 #include <sys/systm.h>
 #include <sys/errno.h>
@@ -1701,6 +1702,11 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
 	/* If there's no prison to update, create a new one and link it in. */
 	created = pr == NULL;
 	if (created) {
+#ifdef MAC
+		error = mac_prison_check_create(td->td_ucred, opts, flags);
+		if (error != 0)
+			goto done_deref;
+#endif
 		for (tpr = mypr; tpr != NULL; tpr = tpr->pr_parent)
 			if (tpr->pr_childcount >= tpr->pr_childmax) {
 				error = EPERM;
@@ -1855,6 +1861,11 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
 			prison_hold(pr);
 			drflags |= PD_DEREF;
 		}
+#ifdef MAC
+		error = mac_prison_check_set(td->td_ucred, pr, opts, flags);
+		if (error != 0)
+			goto done_deref;
+#endif
 #if defined(VIMAGE) && (defined(INET) || defined(INET6))
 		if ((pr->pr_flags & PR_VNET) &&
 		    (ch_flags & (PR_IP4_USER | PR_IP6_USER))) {
@@ -2246,6 +2257,13 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
 	if (created) {
 		sx_assert(&allprison_lock, SX_XLOCKED);
 		prison_knote(ppr, NOTE_JAIL_CHILD | pr->pr_id);
+#ifdef MAC
+		/*
+		 * Note that mac_prison_created() assumes that it's called in a
+		 * sleepable context.
+		 */
+		mac_prison_created(td->td_ucred, pr);
+#endif
 		mtx_lock(&pr->pr_mtx);
 		drflags |= PD_LOCKED;
 		pr->pr_state = PRISON_STATE_ALIVE;
@@ -2253,6 +2271,14 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
 
 	/* Attach this process to the prison if requested. */
 	if (flags & JAIL_ATTACH) {
+#ifdef MAC
+		error = mac_prison_check_attach(td->td_ucred, pr);
+		if (error != 0) {
+			vfs_opterror(opts,
+			    "attach operation denied by MAC policy");
+			goto done_deref;
+		}
+#endif
 		error = do_jail_attach(td, pr,
 		    prison_lock_xlock(pr, drflags & PD_LOCK_FLAGS));
 		drflags &= ~(PD_LOCKED | PD_LIST_XLOCKED);
@@ -2556,12 +2582,6 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
 			drflags |= PD_DEREF;
 			mtx_lock(&pr->pr_mtx);
 			drflags |= PD_LOCKED;
-			if (!(prison_isalive(pr) || (flags & JAIL_DYING))) {
-				error = ENOENT;
-				vfs_opterror(opts, "jail %d is dying",
-				    pr->pr_id);
-				goto done;
-			}
 			goto found_prison;
 		}
 		if (flags & JAIL_AT_DESC) {
@@ -2593,7 +2613,29 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
 			    prison_ischild(mypr, pr)) {
 				mtx_lock(&pr->pr_mtx);
 				drflags |= PD_LOCKED;
+#ifdef MAC
+				/*
+				 * We special-case this one check because we
+				 * don't want MAC to break jail enumeration.  We
+				 * need to just move on to the next accessible
+				 * and alive prison.
+				 */
+				error = mac_prison_check_get(td->td_ucred, pr,
+				    opts, flags);
+				if (error != 0) {
+					mtx_unlock(&pr->pr_mtx);
+					drflags &= ~PD_LOCKED;
+					continue;
+				}
+
+				/*
+				 * Avoid potentially expensive trip back into
+				 * the MAC framework.
+				 */
+				goto found_prison_nomac_alive;
+#else
 				goto found_prison;
+#endif
 			}
 		}
 		error = ENOENT;
@@ -2608,13 +2650,6 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
 			pr = prison_find_child(mypr, jid);
 			if (pr != NULL) {
 				drflags |= PD_LOCKED;
-				if (!(prison_isalive(pr) ||
-				    (flags & JAIL_DYING))) {
-					error = ENOENT;
-					vfs_opterror(opts, "jail %d is dying",
-					    jid);
-					goto done;
-				}
 				goto found_prison;
 			}
 			error = ENOENT;
@@ -2633,12 +2668,6 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
 		pr = prison_find_name(mypr, name);
 		if (pr != NULL) {
 			drflags |= PD_LOCKED;
-			if (!(prison_isalive(pr) || (flags & JAIL_DYING))) {
-				error = ENOENT;
-				vfs_opterror(opts, "jail \"%s\" is dying",
-				    name);
-				goto done;
-			}
 			goto found_prison;
 		}
 		error = ENOENT;
@@ -2652,6 +2681,25 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
 	goto done;
 
  found_prison:
+#ifdef MAC
+	error = mac_prison_check_get(td->td_ucred, pr, opts, flags);
+	if (error != 0)
+		goto done;
+#endif
+	if (!(prison_isalive(pr) || (flags & JAIL_DYING))) {
+		error = ENOENT;
+		if (pr->pr_name[0] != '0' && isdigit(pr->pr_name[0])) {
+			vfs_opterror(opts, "jail %d is dying",
+			    pr->pr_id);
+		} else {
+			vfs_opterror(opts, "jail \"%s\" (%d) is dying",
+			    pr->pr_name, pr->pr_id);
+		}
+		goto done;
+	}
+#ifdef MAC
+ found_prison_nomac_alive:
+#endif
 	/* Get the parameters of the prison. */
 	if (!(drflags & PD_DEREF)) {
 		prison_hold(pr);
@@ -2891,6 +2939,14 @@ sys_jail_remove(struct thread *td, struct jail_remove_args *uap)
 		sx_xunlock(&allprison_lock);
 		return (EINVAL);
 	}
+#ifdef MAC
+	error = mac_prison_check_remove(td->td_ucred, pr);
+	if (error != 0) {
+		mtx_unlock(&pr->pr_mtx);
+		sx_xunlock(&allprison_lock);
+		return (error);
+	}
+#endif
 	prison_hold(pr);
 	prison_remove(pr);
 	return (0);
@@ -2913,6 +2969,10 @@ sys_jail_remove_jd(struct thread *td, struct jail_remove_jd_args *uap)
 		return (error);
 	error = priv_check_cred(jdcred, PRIV_JAIL_REMOVE);
 	crfree(jdcred);
+#ifdef MAC
+	if (error == 0)
+		error = mac_prison_check_remove(td->td_ucred, pr);
+#endif
 	if (error) {
 		prison_free(pr);
 		return (error);
@@ -2957,14 +3017,25 @@ sys_jail_attach(struct thread *td, struct jail_attach_args *uap)
 		return (EINVAL);
 	}
 
+#ifdef MAC
+	error = mac_prison_check_attach(td->td_ucred, pr);
+	if (error != 0)
+		goto unlock;
+#endif
+
 	/* Do not allow a process to attach to a prison that is not alive. */
 	if (!prison_isalive(pr)) {
-		mtx_unlock(&pr->pr_mtx);
-		sx_sunlock(&allprison_lock);
-		return (EINVAL);
+		error = EINVAL;
+		goto unlock;
 	}
 
 	return (do_jail_attach(td, pr, PD_LOCKED | PD_LIST_SLOCKED));
+
+unlock:
+
+	mtx_unlock(&pr->pr_mtx);
+	sx_sunlock(&allprison_lock);
+	return (error);
 }
 
 /*
@@ -2986,6 +3057,10 @@ sys_jail_attach_jd(struct thread *td, struct jail_attach_jd_args *uap)
 		goto fail;
 	drflags |= PD_DEREF;
 	error = priv_check_cred(jdcred, PRIV_JAIL_ATTACH);
+#ifdef MAC
+	if (error == 0)
+		error = mac_prison_check_attach(td->td_ucred, pr);
+#endif
 	crfree(jdcred);
 	if (error)
 		goto fail;
@@ -3086,6 +3161,13 @@ do_jail_attach(struct thread *td, struct prison *pr, int drflags)
 	prison_deref(oldcred->cr_prison, drflags);
 	crfree(oldcred);
 	prison_knote(pr, NOTE_JAIL_ATTACH | td->td_proc->p_pid);
+#ifdef MAC
+	/*
+	 * Note that mac_prison_attached() assumes that it's called in a
+	 * sleepable context.
+	 */
+	mac_prison_attached(td->td_ucred, pr, td->td_proc);
+#endif
 
 	/*
 	 * If the prison was killed while changing credentials, die along
diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h
index f14e8d7d1e7d..5e13434e5ecc 100644
--- a/sys/security/mac/mac_framework.h
+++ b/sys/security/mac/mac_framework.h
@@ -86,6 +86,7 @@ struct thread;
 struct timespec;
 struct ucred;
 struct vattr;
+struct vfsoptlist;
 struct vnode;
 struct vop_setlabel_args;
 
@@ -351,6 +352,17 @@ int	mac_prison_init(struct prison *pr, int flag);
 void	mac_prison_relabel(struct ucred *cred, struct prison *pr,
 	    struct label *newlabel);
 void	mac_prison_destroy(struct prison *pr);
+int	mac_prison_check_attach(struct ucred *cred, struct prison *pr);
+int	mac_prison_check_create(struct ucred *cred, struct vfsoptlist *opts,
+	    int flags);
+int	mac_prison_check_get(struct ucred *cred, struct prison *pr,
+	    struct vfsoptlist *opts, int flags);
+int	mac_prison_check_set(struct ucred *cred, struct prison *pr,
+	    struct vfsoptlist *opts, int flags);
+int	mac_prison_check_remove(struct ucred *cred, struct prison *pr);
+void	mac_prison_created(struct ucred *cred, struct prison *pr);
+void	mac_prison_attached(struct ucred *cred, struct prison *pr,
+	    struct proc *p);
 
 int	mac_priv_check_impl(struct ucred *cred, int priv);
 #ifdef MAC
diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h
index fba1f4a1c85e..7693eb309534 100644
--- a/sys/security/mac/mac_policy.h
+++ b/sys/security/mac/mac_policy.h
@@ -101,6 +101,7 @@ struct sysctl_req;
 struct thread;
 struct ucred;
 struct vattr;
+struct vfsoptlist;
 struct vnode;
 
 struct in_addr;
@@ -419,6 +420,23 @@ typedef int	(*mpo_prison_internalize_label_t)(struct label *label,
 		    char *element_name, char *element_data, int *claimed);
 typedef void	(*mpo_prison_relabel_t)(struct ucred *cred, struct prison *pr,
 		    struct label *prlabel, struct label *newlabel);
+typedef int	(*mpo_prison_check_attach_t)(struct ucred *cred,
+		    struct prison *pr, struct label *prlabel);
+typedef int	(*mpo_prison_check_create_t)(struct ucred *cred,
+		    struct vfsoptlist *opts, int flags);
+typedef int	(*mpo_prison_check_get_t)(struct ucred *cred,
+		    struct prison *pr, struct label *prlabel,
+		    struct vfsoptlist *opts, int flags);
+typedef int	(*mpo_prison_check_set_t)(struct ucred *cred,
+		    struct prison *pr, struct label *prlabel,
+		    struct vfsoptlist *opts, int flags);
+typedef int	(*mpo_prison_check_remove_t)(struct ucred *cred,
+		    struct prison *pr, struct label *prlabel);
+typedef void	(*mpo_prison_created_t)(struct ucred *cred,
+		    struct prison *pr, struct label *prlabel);
+typedef void	(*mpo_prison_attached_t)(struct ucred *cred,
+		    struct prison *pr, struct label *prlabel, struct proc *p,
+		    struct label *proclabel);
 
 typedef int	(*mpo_priv_check_t)(struct ucred *cred, int priv);
 typedef int	(*mpo_priv_grant_t)(struct ucred *cred, int priv);
@@ -882,6 +900,13 @@ struct mac_policy_ops {
 	mpo_prison_externalize_label_t		mpo_prison_externalize_label;
 	mpo_prison_internalize_label_t		mpo_prison_internalize_label;
 	mpo_prison_relabel_t			mpo_prison_relabel;
+	mpo_prison_check_attach_t		mpo_prison_check_attach;
+	mpo_prison_check_create_t		mpo_prison_check_create;
+	mpo_prison_check_get_t			mpo_prison_check_get;
+	mpo_prison_check_set_t			mpo_prison_check_set;
+	mpo_prison_check_remove_t		mpo_prison_check_remove;
+	mpo_prison_created_t			mpo_prison_created;
+	mpo_prison_attached_t			mpo_prison_attached;
 
 	mpo_priv_check_t			mpo_priv_check;
 	mpo_priv_grant_t			mpo_priv_grant;
diff --git a/sys/security/mac/mac_prison.c b/sys/security/mac/mac_prison.c
index e24ffa9e698d..3f787c6b3647 100644
--- a/sys/security/mac/mac_prison.c
+++ b/sys/security/mac/mac_prison.c
@@ -142,3 +142,90 @@ mac_prison_check_relabel(struct ucred *cred, struct prison *pr,
 
 	return (error);
 }
+
+MAC_CHECK_PROBE_DEFINE3(prison_check_attach, "struct ucred *",
+    "struct prison *", "struct label *");
+int
+mac_prison_check_attach(struct ucred *cred, struct prison *pr)
+{
+	int error;
+
+	MAC_POLICY_CHECK_NOSLEEP(prison_check_attach, cred, pr, pr->pr_label);
+	MAC_CHECK_PROBE3(prison_check_attach, error, cred, pr, pr->pr_label);
+
+	return (error);
+}
+
+MAC_CHECK_PROBE_DEFINE3(prison_check_create, "struct ucred *",
+    "struct vfsoptlist *", "int");
+int
+mac_prison_check_create(struct ucred *cred, struct vfsoptlist *opts,
+    int flags)
+{
+	int error;
+
+	MAC_POLICY_CHECK_NOSLEEP(prison_check_create, cred, opts, flags);
+	MAC_CHECK_PROBE3(prison_check_create, error, cred, opts, flags);
+
+	return (error);
+}
+
+MAC_CHECK_PROBE_DEFINE5(prison_check_get, "struct ucred *",
+    "struct prison *", "struct label *", "struct vfsoptlist *", "int");
+int
+mac_prison_check_get(struct ucred *cred, struct prison *pr,
+    struct vfsoptlist *opts, int flags)
+{
+	int error;
+
+	MAC_POLICY_CHECK_NOSLEEP(prison_check_get, cred, pr, pr->pr_label,
+	    opts, flags);
+	MAC_CHECK_PROBE5(prison_check_get, error, cred, pr, pr->pr_label, opts,
+	    flags);
+
+	return (error);
+}
+
+MAC_CHECK_PROBE_DEFINE5(prison_check_set, "struct ucred *",
+    "struct prison *", "struct label *", "struct vfsoptlist *", "int");
+int
+mac_prison_check_set(struct ucred *cred, struct prison *pr,
+    struct vfsoptlist *opts, int flags)
+{
+	int error;
+
+	MAC_POLICY_CHECK_NOSLEEP(prison_check_set, cred, pr, pr->pr_label,
+	    opts, flags);
+	MAC_CHECK_PROBE5(prison_check_set, error, cred, pr, pr->pr_label, opts,
+	    flags);
+
+	return (error);
+}
+
+MAC_CHECK_PROBE_DEFINE3(prison_check_remove, "struct ucred *",
+    "struct prison *", "struct label *");
+int
+mac_prison_check_remove(struct ucred *cred, struct prison *pr)
+{
+	int error;
+
+	MAC_POLICY_CHECK_NOSLEEP(prison_check_remove, cred, pr, pr->pr_label);
+	MAC_CHECK_PROBE3(prison_check_remove, error, cred, pr, pr->pr_label);
+
+	return (error);
+}
+
+void
+mac_prison_created(struct ucred *cred, struct prison *pr)
+{
+
+	MAC_POLICY_PERFORM(prison_created, cred, pr, pr->pr_label);
+}
+
+void
+mac_prison_attached(struct ucred *cred, struct prison *pr, struct proc *p)
+{
+
+	MAC_POLICY_PERFORM(prison_attached, cred, pr, pr->pr_label, p,
+	    p->p_label);
+}
diff --git a/sys/security/mac_stub/mac_stub.c b/sys/security/mac_stub/mac_stub.c
index ac5d5b58e5db..20b04d4acf58 100644
--- a/sys/security/mac_stub/mac_stub.c
+++ b/sys/security/mac_stub/mac_stub.c
@@ -52,6 +52,7 @@
 #include <sys/acl.h>
 #include <sys/conf.h>
 #include <sys/extattr.h>
+#include <sys/jail.h>
 #include <sys/kdb.h>
 #include <sys/kernel.h>
 #include <sys/ksem.h>
@@ -852,6 +853,74 @@ stub_posixshm_create(struct ucred *cred, struct shmfd *shmfd,
 
 }
 
+static void
+stub_prison_relabel(struct ucred *cred, struct prison *pr,
+    struct label *prlabel, struct label *newlabel)
+{
+
+}
+
+static int
+stub_prison_check_relabel(struct ucred *cred, struct prison *pr,
+    struct label *prlabel, struct label *newlabel)
+{
+
+	return (0);
+}
+
+static int
+stub_prison_check_attach(struct ucred *cred, struct prison *pr,
+    struct label *prlabel)
+{
+
+	return (0);
+}
+
+static int
+stub_prison_check_create(struct ucred *cred, struct vfsoptlist *opts, int flags)
+{
+
+	return (0);
+}
+
+static int
+stub_prison_check_get(struct ucred *cred, struct prison *pr,
+    struct label *prlabel, struct vfsoptlist *opts, int flags)
+{
+
+	return (0);
+}
+
+static int
+stub_prison_check_set(struct ucred *cred, struct prison *pr,
+    struct label *prlabel, struct vfsoptlist *opts, int flags)
+{
+
+	return (0);
+}
+
+static int
+stub_prison_check_remove(struct ucred *cred, struct prison *pr,
+    struct label *prlabel)
+{
+
+	return (0);
+}
+
+static void
+stub_prison_created(struct ucred *cred, struct prison *pr,
+    struct label *prlabel)
+{
+
+}
+
+static void
+stub_prison_attached(struct ucred *cred, struct prison *pr,
+    struct label *prlabel, struct proc *p, struct label *proclabel)
+{
+
+}
+
 static int
 stub_priv_check(struct ucred *cred, int priv)
 {
@@ -1841,6 +1910,20 @@ static struct mac_policy_ops stub_ops =
 	.mpo_posixshm_destroy_label = stub_destroy_label,
 	.mpo_posixshm_init_label = stub_init_label,
 
+	.mpo_prison_init_label = stub_init_label_waitcheck,
+	.mpo_prison_destroy_label = stub_destroy_label,
+	.mpo_prison_externalize_label = stub_externalize_label,
+	.mpo_prison_internalize_label = stub_internalize_label,
+	.mpo_prison_relabel = stub_prison_relabel,
+	.mpo_prison_check_relabel = stub_prison_check_relabel,
+	.mpo_prison_check_attach = stub_prison_check_attach,
+	.mpo_prison_check_create = stub_prison_check_create,
+	.mpo_prison_check_get = stub_prison_check_get,
+	.mpo_prison_check_set = stub_prison_check_set,
+	.mpo_prison_check_remove = stub_prison_check_remove,
+	.mpo_prison_created = stub_prison_created,
+	.mpo_prison_attached = stub_prison_attached,
+
 	.mpo_priv_check = stub_priv_check,
 	.mpo_priv_grant = stub_priv_grant,
 
diff --git a/sys/security/mac_test/mac_test.c b/sys/security/mac_test/mac_test.c
index c447eeef010d..72af48edb00f 100644
--- a/sys/security/mac_test/mac_test.c
+++ b/sys/security/mac_test/mac_test.c
@@ -51,6 +51,7 @@
 
 #include <sys/param.h>
 #include <sys/acl.h>
+#include <sys/jail.h>
 #include <sys/kdb.h>
 #include <sys/kernel.h>
 #include <sys/ksem.h>
@@ -99,6 +100,7 @@ static SYSCTL_NODE(_security_mac, OID_AUTO, test,
 #define	MAGIC_PIPE	0xdc6c9919
 #define	MAGIC_POSIX_SEM	0x78ae980c
 #define	MAGIC_POSIX_SHM	0x4e853fc9
+#define	MAGIC_PRISON	0x9639acdb
 #define	MAGIC_PROC	0x3b4be98f
 #define	MAGIC_CRED	0x9a5a4987
 #define	MAGIC_VNODE	0x1a67a45c
@@ -1591,6 +1593,151 @@ test_posixshm_init_label(struct label *label)
 	COUNTER_INC(posixshm_init_label);
 }
 
+COUNTER_DECL(prison_init_label);
+static int
+test_prison_init_label(struct label *label, int flag)
+{
+
+	if (flag & M_WAITOK)
+		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+		    "test_prison_init_label() at %s:%d", __FILE__,
+		    __LINE__);
+
+	LABEL_INIT(label, MAGIC_PRISON);
+	COUNTER_INC(prison_init_label);
+	return (0);
+}
+
+COUNTER_DECL(prison_destroy_label);
+static void
+test_prison_destroy_label(struct label *label)
+{
+
+	LABEL_DESTROY(label, MAGIC_PRISON);
+	COUNTER_INC(prison_destroy_label);
+}
+
+COUNTER_DECL(prison_externalize_label);
+static int
+test_prison_externalize_label(struct label *label, char *element_name,
+    struct sbuf *sb, int *claimed)
+{
+
+	LABEL_CHECK(label, MAGIC_PRISON);
+	COUNTER_INC(prison_externalize_label);
+
+	return (0);
+}
+
+COUNTER_DECL(prison_internalize_label);
+static int
+test_prison_internalize_label(struct label *label, char *element_name,
+    char *element_data, int *claimed)
+{
+
+	LABEL_CHECK(label, MAGIC_PRISON);
+	COUNTER_INC(prison_internalize_label);
+
+	return (0);
+}
+
+COUNTER_DECL(prison_relabel);
+static void
+test_prison_relabel(struct ucred *cred, struct prison *pr,
+    struct label *prlabel, struct label *newlabel)
+{
+
+	LABEL_CHECK(prlabel, MAGIC_PRISON);
+	LABEL_CHECK(newlabel, MAGIC_PRISON);
+	COUNTER_INC(prison_relabel);
+}
+
+COUNTER_DECL(prison_check_relabel);
+static int
+test_prison_check_relabel(struct ucred *cred, struct prison *pr,
+    struct label *prlabel, struct label *newlabel)
+{
+
+	LABEL_CHECK(prlabel, MAGIC_PRISON);
+	LABEL_CHECK(newlabel, MAGIC_PRISON);
+	COUNTER_INC(prison_check_relabel);
+	return (0);
+}
+
+COUNTER_DECL(prison_check_attach);
+static int
+test_prison_check_attach(struct ucred *cred, struct prison *pr,
+    struct label *prlabel)
+{
+
+	LABEL_CHECK(prlabel, MAGIC_PRISON);
+	COUNTER_INC(prison_check_attach);
+	return (0);
+}
+
+COUNTER_DECL(prison_check_create);
+static int
+test_prison_check_create(struct ucred *cred, struct vfsoptlist *opts, int flags)
+{
+
+	COUNTER_INC(prison_check_create);
+	return (0);
+}
+
+COUNTER_DECL(prison_check_get);
+static int
+test_prison_check_get(struct ucred *cred, struct prison *pr,
+    struct label *prlabel, struct vfsoptlist *opts, int flags)
+{
+
+	LABEL_CHECK(prlabel, MAGIC_PRISON);
+	COUNTER_INC(prison_check_get);
+	return (0);
+}
+
+COUNTER_DECL(prison_check_set);
+static int
+test_prison_check_set(struct ucred *cred, struct prison *pr,
+    struct label *prlabel, struct vfsoptlist *opts, int flags)
+{
+
+	LABEL_CHECK(prlabel, MAGIC_PRISON);
+	COUNTER_INC(prison_check_set);
+	return (0);
+}
+
+COUNTER_DECL(prison_check_remove);
+static int
+test_prison_check_remove(struct ucred *cred, struct prison *pr,
+    struct label *prlabel)
+{
+
+	LABEL_CHECK(prlabel, MAGIC_PRISON);
+	COUNTER_INC(prison_check_remove);
+	return (0);
+}
+
+COUNTER_DECL(prison_created);
+static void
+test_prison_created(struct ucred *cred, struct prison *pr,
+    struct label *prlabel)
+{
+
+	LABEL_CHECK(prlabel, MAGIC_PRISON);
+	COUNTER_INC(prison_created);
+}
+
+COUNTER_DECL(prison_attached);
+static void
+test_prison_attached(struct ucred *cred, struct prison *pr,
+    struct label *prlabel, struct proc *p, struct label *proclabel)
+{
+
+	LABEL_CHECK(prlabel, MAGIC_PRISON);
+	LABEL_CHECK(proclabel, MAGIC_PROC);
+	COUNTER_INC(prison_attached);
+}
+
 COUNTER_DECL(proc_check_debug);
 static int
 test_proc_check_debug(struct ucred *cred, struct proc *p)
@@ -3208,6 +3355,20 @@ static struct mac_policy_ops test_ops =
 	.mpo_posixshm_destroy_label = test_posixshm_destroy_label,
 	.mpo_posixshm_init_label = test_posixshm_init_label,
 
+	.mpo_prison_init_label = test_prison_init_label,
+	.mpo_prison_destroy_label = test_prison_destroy_label,
+	.mpo_prison_externalize_label = test_prison_externalize_label,
+	.mpo_prison_internalize_label = test_prison_internalize_label,
+	.mpo_prison_relabel = test_prison_relabel,
+	.mpo_prison_check_relabel = test_prison_check_relabel,
+	.mpo_prison_check_attach = test_prison_check_attach,
+	.mpo_prison_check_create = test_prison_check_create,
+	.mpo_prison_check_get = test_prison_check_get,
+	.mpo_prison_check_set = test_prison_check_set,
+	.mpo_prison_check_remove = test_prison_check_remove,
+	.mpo_prison_created = test_prison_created,
+	.mpo_prison_attached = test_prison_attached,
+
 	.mpo_proc_check_debug = test_proc_check_debug,
 	.mpo_proc_check_sched = test_proc_check_sched,
 	.mpo_proc_check_signal = test_proc_check_signal,