git: 11d6ea47f06a - main - kern: mac: add a MAC label to struct prison

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

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

commit 11d6ea47f06a38f66536b173e85ddf2674da6aff
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-10-04 03:46:03 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2026-01-16 00:23:39 +0000

    kern: mac: add a MAC label to struct prison
    
    Reviewed by:    olce
    Differential Revision:  https://reviews.freebsd.org/D53953
---
 sys/conf/files                   |   1 +
 sys/kern/kern_jail.c             |  26 +++++++
 sys/security/mac/mac_framework.c |   1 +
 sys/security/mac/mac_framework.h |   6 ++
 sys/security/mac/mac_internal.h  |   9 +++
 sys/security/mac/mac_policy.h    |  20 ++++++
 sys/security/mac/mac_prison.c    | 144 +++++++++++++++++++++++++++++++++++++++
 sys/sys/jail.h                   |   1 +
 8 files changed, 208 insertions(+)

diff --git a/sys/conf/files b/sys/conf/files
index d0c4ea5f544d..a6a76dec433a 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -5264,6 +5264,7 @@ security/mac/mac_net.c		optional mac
 security/mac/mac_pipe.c		optional mac
 security/mac/mac_posix_sem.c	optional mac
 security/mac/mac_posix_shm.c	optional mac
+security/mac/mac_prison.c	optional mac
 security/mac/mac_priv.c		optional mac
 security/mac/mac_process.c	optional mac
 security/mac/mac_socket.c	optional mac
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index f803be76a70e..8c224597bdf5 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -275,8 +275,17 @@ prison0_init(void)
 	uint8_t *file, *data;
 	size_t size;
 	char buf[sizeof(prison0.pr_hostuuid)];
+#ifdef MAC
+	int error __diagused;
+#endif
 	bool valid;
 
+#ifdef MAC
+	error = mac_prison_init(&prison0, M_WAITOK);
+	MPASS(error == 0);
+
+	mtx_unlock(&prison0.pr_mtx);
+#endif
 	prison0.pr_cpuset = cpuset_ref(thread0.td_cpuset);
 	prison0.pr_osreldate = osreldate;
 	strlcpy(prison0.pr_osrelease, osrelease, sizeof(prison0.pr_osrelease));
@@ -1828,7 +1837,14 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
 		if (error)
 			goto done_deref;
 
+#ifdef MAC
+		error = mac_prison_init(pr, M_WAITOK);
+		MPASS(error == 0);
+
+		mtx_assert(&pr->pr_mtx, MA_OWNED);
+#else
 		mtx_lock(&pr->pr_mtx);
+#endif
 		drflags |= PD_LOCKED;
 	} else {
 		/*
@@ -3540,6 +3556,16 @@ prison_deref(struct prison *pr, int flags)
 					KASSERT(
 					    refcount_load(&prison0.pr_ref) != 0,
 					    ("prison0 pr_ref=0"));
+#ifdef MAC
+					/*
+					 * The MAC framework will call into any
+					 * policies that want to hook
+					 * prison_destroy_label, so ideally we
+					 * call this prior to any final state
+					 * invalidation to be safe.
+					 */
+					mac_prison_destroy(pr);
+#endif
 					pr->pr_state = PRISON_STATE_INVALID;
 					TAILQ_REMOVE(&allprison, pr, pr_list);
 					LIST_REMOVE(pr, pr_sibling);
diff --git a/sys/security/mac/mac_framework.c b/sys/security/mac/mac_framework.c
index b0776160cc74..fec63b99c0e0 100644
--- a/sys/security/mac/mac_framework.c
+++ b/sys/security/mac/mac_framework.c
@@ -374,6 +374,7 @@ mac_policy_getlabeled(struct mac_policy_conf *mpc)
 	MPC_FLAG(mount_init_label, MPC_OBJECT_MOUNT);
 	MPC_FLAG(posixsem_init_label, MPC_OBJECT_POSIXSEM);
 	MPC_FLAG(posixshm_init_label, MPC_OBJECT_POSIXSHM);
+	MPC_FLAG(prison_init_label, MPC_OBJECT_PRISON);
 	MPC_FLAG(sysvmsg_init_label, MPC_OBJECT_SYSVMSG);
 	MPC_FLAG(sysvmsq_init_label, MPC_OBJECT_SYSVMSQ);
 	MPC_FLAG(sysvsem_init_label, MPC_OBJECT_SYSVSEM);
diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h
index 1233cd30f211..f14e8d7d1e7d 100644
--- a/sys/security/mac/mac_framework.h
+++ b/sys/security/mac/mac_framework.h
@@ -73,6 +73,7 @@ struct mount;
 struct msg;
 struct msqid_kernel;
 struct pipepair;
+struct prison;
 struct proc;
 struct semid_kernel;
 struct shmfd;
@@ -346,6 +347,11 @@ void 	mac_posixshm_create(struct ucred *cred, struct shmfd *shmfd);
 void	mac_posixshm_destroy(struct shmfd *);
 void	mac_posixshm_init(struct shmfd *);
 
+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_priv_check_impl(struct ucred *cred, int priv);
 #ifdef MAC
 extern bool mac_priv_check_fp_flag;
diff --git a/sys/security/mac/mac_internal.h b/sys/security/mac/mac_internal.h
index aeef59017d18..a882a476d1b0 100644
--- a/sys/security/mac/mac_internal.h
+++ b/sys/security/mac/mac_internal.h
@@ -177,6 +177,7 @@ struct label {
 #define	MPC_OBJECT_SYSVSHM		0x0000000000020000
 #define	MPC_OBJECT_SYNCACHE		0x0000000000040000
 #define	MPC_OBJECT_IP6Q			0x0000000000080000
+#define	MPC_OBJECT_PRISON		0x0000000000100000
 
 /*
  * MAC Framework global variables.
@@ -252,6 +253,14 @@ int	mac_pipe_externalize_label(struct label *label, char *elements,
 	    char *outbuf, size_t outbuflen);
 int	mac_pipe_internalize_label(struct label *label, char *string);
 
+int	mac_prison_check_relabel(struct ucred *cred, struct prison *pr,
+	    struct label *newlabel);
+int	mac_prison_externalize_label(struct label *label, char *elements,
+	    char *outbuf, size_t outbuflen);
+int	mac_prison_internalize_label(struct label *label, char *string);
+void	mac_prison_relabel(struct ucred *cred, struct prison *pr,
+	    struct label *newlabel);
+
 int	mac_socket_label_set(struct ucred *cred, struct socket *so,
 	    struct label *label);
 void	mac_socket_copy_label(struct label *src, struct label *dest);
diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h
index f0a1f0863c96..fba1f4a1c85e 100644
--- a/sys/security/mac/mac_policy.h
+++ b/sys/security/mac/mac_policy.h
@@ -88,6 +88,7 @@ struct mount;
 struct msg;
 struct msqid_kernel;
 struct pipepair;
+struct prison;
 struct proc;
 struct sbuf;
 struct semid_kernel;
@@ -407,6 +408,18 @@ typedef void	(*mpo_posixshm_create_t)(struct ucred *cred,
 typedef void	(*mpo_posixshm_destroy_label_t)(struct label *label);
 typedef void	(*mpo_posixshm_init_label_t)(struct label *label);
 
+typedef int	(*mpo_prison_init_label_t)(struct label *label, int flag);
+typedef int	(*mpo_prison_check_relabel_t)(struct ucred *cred,
+		    struct prison *pr, struct label *prlabel,
+		    struct label *newlabel);
+typedef void	(*mpo_prison_destroy_label_t)(struct label *label);
+typedef int	(*mpo_prison_externalize_label_t)(struct label *label,
+		    char *element_name, struct sbuf *sb, int *claimed);
+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_priv_check_t)(struct ucred *cred, int priv);
 typedef int	(*mpo_priv_grant_t)(struct ucred *cred, int priv);
 
@@ -863,6 +876,13 @@ struct mac_policy_ops {
 	mpo_posixshm_destroy_label_t		mpo_posixshm_destroy_label;
 	mpo_posixshm_init_label_t		mpo_posixshm_init_label;
 
+	mpo_prison_init_label_t			mpo_prison_init_label;
+	mpo_prison_check_relabel_t		mpo_prison_check_relabel;
+	mpo_prison_destroy_label_t		mpo_prison_destroy_label;
+	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_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
new file mode 100644
index 000000000000..e24ffa9e698d
--- /dev/null
+++ b/sys/security/mac/mac_prison.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 2025 Kyle Evans <kevans@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/cdefs.h>
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/condvar.h>
+#include <sys/imgact.h>
+#include <sys/jail.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/mac.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/sdt.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+static void
+mac_prison_label_free(struct label *label)
+{
+	if (label == NULL)
+		return;
+
+	MAC_POLICY_PERFORM_NOSLEEP(prison_destroy_label, label);
+	mac_labelzone_free(label);
+}
+
+static struct label *
+mac_prison_label_alloc(int flag)
+{
+	struct label *label;
+	int error;
+
+	label = mac_labelzone_alloc(flag);
+	if (label == NULL)
+		return (NULL);
+
+	if (flag & M_WAITOK)
+		MAC_POLICY_CHECK(prison_init_label, label, flag);
+	else
+		MAC_POLICY_CHECK_NOSLEEP(prison_init_label, label, flag);
+	if (error) {
+		mac_prison_label_free(label);
+		return (NULL);
+	}
+	return (label);
+}
+
+/*
+ * The caller's expecting us to return with the prison locked if we were
+ * successful, since we're also setting pr->pr_label.  On error, it remains
+ * unlocked.
+ */
+int
+mac_prison_init(struct prison *pr, int flag)
+{
+	struct label *prlabel;
+
+	mtx_assert(&pr->pr_mtx, MA_NOTOWNED);
+	if ((mac_labeled & MPC_OBJECT_PRISON) == 0) {
+		mtx_lock(&pr->pr_mtx);
+		pr->pr_label = NULL;
+		return (0);
+	}
+
+	prlabel = mac_prison_label_alloc(flag);
+	if (prlabel == NULL) {
+		KASSERT((flag & M_WAITOK) == 0,
+		    ("MAC policy prison_init_label failed under M_WAITOK"));
+		return (ENOMEM);
+	}
+
+	mtx_lock(&pr->pr_mtx);
+	pr->pr_label = prlabel;
+	return (0);
+}
+
+void
+mac_prison_destroy(struct prison *pr)
+{
+	mtx_assert(&pr->pr_mtx, MA_OWNED);
+	mac_prison_label_free(pr->pr_label);
+	pr->pr_label = NULL;
+}
+
+int
+mac_prison_externalize_label(struct label *label, char *elements,
+    char *outbuf, size_t outbuflen)
+{
+	int error;
+
+	MAC_POLICY_EXTERNALIZE(prison, label, elements, outbuf, outbuflen);
+	return (error);
+}
+
+int
+mac_prison_internalize_label(struct label *label, char *string)
+{
+	int error;
+
+	MAC_POLICY_INTERNALIZE(prison, label, string);
+	return (error);
+}
+
+void
+mac_prison_relabel(struct ucred *cred, struct prison *pr,
+    struct label *newlabel)
+{
+	mtx_assert(&pr->pr_mtx, MA_OWNED);
+	MAC_POLICY_PERFORM_NOSLEEP(prison_relabel, cred, pr, pr->pr_label,
+	    newlabel);
+}
+
+MAC_CHECK_PROBE_DEFINE4(prison_check_relabel, "struct ucred *",
+    "struct prison *", "struct label *", "struct label *");
+int
+mac_prison_check_relabel(struct ucred *cred, struct prison *pr,
+    struct label *newlabel)
+{
+	int error;
+
+	mtx_assert(&pr->pr_mtx, MA_OWNED);
+	MAC_POLICY_CHECK_NOSLEEP(prison_check_relabel, cred, pr,
+	    pr->pr_label, newlabel);
+	MAC_CHECK_PROBE4(prison_check_relabel, error, cred, pr,
+	    pr->pr_label, newlabel);
+
+	return (error);
+}
diff --git a/sys/sys/jail.h b/sys/sys/jail.h
index e6a13e6719dd..5ac4c5f9008d 100644
--- a/sys/sys/jail.h
+++ b/sys/sys/jail.h
@@ -198,6 +198,7 @@ struct prison {
 	struct prison_ip  *pr_addrs[PR_FAMILY_MAX];	/* (p,n) IPs of jail */
 	struct prison_racct *pr_prison_racct;		/* (c) racct jail proxy */
 	struct knlist	*pr_klist;			/* (m) attached knotes */
+	struct label	*pr_label;			/* (m) MAC label */
 	LIST_HEAD(, jaildesc) pr_descs;			/* (a) attached descriptors */
 	void		*pr_sparep;
 	int		 pr_childcount;			/* (a) number of child jails */