The branch main has been updated by kevans:

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

commit 11d6ea47f06a38f66536b173e85ddf2674da6aff
Author:     Kyle Evans <[email protected]>
AuthorDate: 2025-10-04 03:46:03 +0000
Commit:     Kyle Evans <[email protected]>
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 <[email protected]>
+ *
+ * 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 */

Reply via email to