git: bd55cbb50c58 - main - kern: add a mac.label jail parameter
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 16 Jan 2026 00:24:23 UTC
The branch main has been updated by kevans:
URL: https://cgit.FreeBSD.org/src/commit/?id=bd55cbb50c58876281f925cfd91961544f0153ad
commit bd55cbb50c58876281f925cfd91961544f0153ad
Author: Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-11-07 04:19:31 +0000
Commit: Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2026-01-16 00:23:39 +0000
kern: add a mac.label jail parameter
Have it take a `struct mac` and we'll paper over the difference for
jail(8)/jls(8) in libjail(3). The mac_syscalls.h model is taken from
mac_set_proc_*() that were previously done.
Reviewed by: olce
Differential Revision: https://reviews.freebsd.org/D53958
---
sys/kern/kern_jail.c | 52 +++++++++++++-
sys/security/mac/mac_syscalls.c | 154 ++++++++++++++++++++++++++++++++++++++++
sys/security/mac/mac_syscalls.h | 10 +++
3 files changed, 215 insertions(+), 1 deletion(-)
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index b5f61e3957d9..5111b98bf221 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -80,6 +80,8 @@
#endif /* DDB */
#include <security/mac/mac_framework.h>
+#include <security/mac/mac_policy.h>
+#include <security/mac/mac_syscalls.h>
#define PRISON0_HOSTUUID_MODULE "hostuuid"
@@ -1027,6 +1029,10 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
#endif
unsigned long hid;
size_t namelen, onamelen, pnamelen;
+#ifdef MAC
+ void *mac_set_prison_data = NULL;
+ int gotmaclabel;
+#endif
int created, cuflags, descend, drflags, enforce;
int error, errmsg_len, errmsg_pos;
int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel;
@@ -1349,6 +1355,17 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
pr_flags |= PR_HOST;
}
+#ifdef MAC
+ /* Process the mac.label vfsopt */
+ error = mac_set_prison_prepare(td, opts, &mac_set_prison_data);
+ if (error == ENOENT)
+ gotmaclabel = 0;
+ else if (error != 0)
+ goto done_errmsg;
+ else
+ gotmaclabel = 1;
+#endif
+
#ifdef INET
error = vfs_getopt(opts, "ip4.addr", &op, &ip4s);
if (error == ENOENT)
@@ -2182,6 +2199,17 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
}
}
pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags;
+
+#ifdef MAC
+ /* Apply any request MAC label before we let modules do their work. */
+ if (gotmaclabel) {
+ error = mac_set_prison_core(td, pr, mac_set_prison_data);
+ if (error) {
+ vfs_opterror(opts, "mac relabel denied");
+ goto done_deref;
+ }
+ }
+#endif
mtx_unlock(&pr->pr_mtx);
drflags &= ~PD_LOCKED;
/*
@@ -2370,6 +2398,10 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
#endif
#ifdef INET6
prison_ip_free(ip6);
+#endif
+#ifdef MAC
+ if (mac_set_prison_data != NULL)
+ mac_set_prison_finish(td, error == 0, mac_set_prison_data);
#endif
if (jfp_out != NULL)
fdrop(jfp_out, td);
@@ -2835,9 +2867,22 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
if (error != 0 && error != ENOENT)
goto done;
- /* Get the module parameters. */
+#ifdef MAC
+ /*
+ * We get the MAC label last because we'll let the MAC framework drop
+ * pr_mtx to externalize the label.
+ */
+ error = mac_get_prison(td, pr, opts);
+ mtx_assert(&pr->pr_mtx, MA_NOTOWNED);
+ drflags &= ~PD_LOCKED;
+ if (error != 0 && error != ENOENT)
+ goto done;
+#else
mtx_unlock(&pr->pr_mtx);
drflags &= ~PD_LOCKED;
+#endif
+
+ /* Get the module parameters. */
error = osd_jail_call(pr, PR_METHOD_GET, opts);
if (error)
goto done;
@@ -5107,6 +5152,11 @@ SYSCTL_JAIL_PARAM(_host, hostid, CTLTYPE_ULONG | CTLFLAG_RW,
SYSCTL_JAIL_PARAM_NODE(cpuset, "Jail cpuset");
SYSCTL_JAIL_PARAM(_cpuset, id, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID");
+#ifdef MAC
+SYSCTL_JAIL_PARAM_STRUCT(_mac, label, CTLFLAG_RW, sizeof(struct mac),
+ "S,mac", "Jail MAC label");
+#endif
+
#ifdef INET
SYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RDTUN,
"Jail IPv4 address virtualization");
diff --git a/sys/security/mac/mac_syscalls.c b/sys/security/mac/mac_syscalls.c
index 2a8b8d1f18ce..1035c6dbb84b 100644
--- a/sys/security/mac/mac_syscalls.c
+++ b/sys/security/mac/mac_syscalls.c
@@ -302,6 +302,160 @@ mac_set_proc_finish(struct thread *const td, bool proc_label_set,
mac_cred_label_free(intlabel);
}
+int
+mac_get_prison(struct thread *const td, struct prison *pr,
+ struct vfsoptlist *opts)
+{
+ char *buffer = NULL, *u_buffer;
+ struct label *intlabel = NULL;
+ struct mac mac;
+ int error;
+ bool locked = true;
+
+ mtx_assert(&pr->pr_mtx, MA_OWNED);
+#ifdef COMPAT_FREEBSD32
+ if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
+ struct mac32 mac32;
+
+ error = vfs_copyopt(opts, "mac.label", &mac32, sizeof(mac32));
+ if (error == 0) {
+ CP(mac32, mac, m_buflen);
+ PTRIN_CP(mac32, mac, m_string);
+ }
+ } else
+#endif
+ error = vfs_copyopt(opts, "mac.label", &mac, sizeof(mac));
+ if (error) {
+ if (error != ENOENT)
+ vfs_opterror(opts, "bad mac.label");
+ goto out_nomac;
+ }
+
+ if (!(mac_labeled & MPC_OBJECT_PRISON)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ intlabel = mac_prison_label_alloc(M_NOWAIT);
+ if (intlabel == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ mac_prison_copy_label(pr->pr_label, intlabel);
+
+ /*
+ * Externalization may want to acquire an rmlock. We already tapped out
+ * a copy of the label from when the jail_get(2) operation started and
+ * we're expected to be called near the end of jail_get(2) when the lock
+ * is about to be dropped anyways, so this is safe.
+ */
+ mtx_unlock(&pr->pr_mtx);
+ locked = false;
+
+ error = mac_label_copyin_string(&mac, &u_buffer, M_WAITOK);
+ if (error) {
+ vfs_opterror(opts, "mac.label: string copy failure");
+ goto out;
+ }
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
+ if (buffer == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ error = mac_prison_externalize_label(intlabel, mac.m_string,
+ buffer, mac.m_buflen);
+
+ if (error == 0)
+ error = copyout(buffer, u_buffer, strlen(buffer)+1);
+
+out:
+ mac_prison_label_free(intlabel);
+ free_copied_label(&mac);
+ free(buffer, M_MACTEMP);
+
+out_nomac:
+ if (locked) {
+ MPASS(error != 0);
+ mtx_unlock(&pr->pr_mtx);
+ }
+
+ return (error);
+}
+
+int
+mac_set_prison_prepare(struct thread *const td, struct vfsoptlist *opts,
+ void **const mac_set_prison_data)
+{
+ struct mac mac;
+ struct label *intlabel;
+ int error;
+
+#ifdef COMPAT_FREEBSD32
+ if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
+ struct mac32 mac32;
+
+ error = vfs_copyopt(opts, "mac.label", &mac32, sizeof(mac32));
+ if (error == 0) {
+ CP(mac32, mac, m_buflen);
+ PTRIN_CP(mac32, mac, m_string);
+ }
+ } else
+#endif
+ error = vfs_copyopt(opts, "mac.label", &mac, sizeof(mac));
+ if (error) {
+ if (error != ENOENT)
+ vfs_opterror(opts, "bad mac.label");
+ return (error);
+ }
+
+ error = mac_label_copyin_string(&mac, NULL, M_WAITOK);
+ if (error) {
+ vfs_opterror(opts, "mac.label: string copy failure");
+ return (error);
+ }
+
+ /*
+ * If the option wasn't set, then we return ENOENT above. If we don't
+ * have any policies applicable to prisons, we can return EINVAL early.
+ */
+ if (!(mac_labeled & MPC_OBJECT_PRISON)) {
+ vfs_opterror(opts, "no labelled jail policies");
+ return (EINVAL);
+ }
+
+ intlabel = mac_prison_label_alloc(M_WAITOK);
+ error = mac_prison_internalize_label(intlabel, mac.m_string);
+ if (error) {
+ mac_prison_label_free(intlabel);
+ vfs_opterror(opts, "internalize_label error");
+ return (error);
+ }
+
+ *mac_set_prison_data = intlabel;
+ return (0);
+}
+
+int
+mac_set_prison_core(struct thread *const td, struct prison *pr,
+ void *const mac_set_prison_data)
+{
+ struct label *const intlabel = mac_set_prison_data;
+
+ return (mac_prison_label_set(td->td_ucred, pr, intlabel));
+}
+
+void
+mac_set_prison_finish(struct thread *const td, bool prison_label_set __unused,
+ void *const mac_set_prison_data)
+{
+ struct label *const intlabel = mac_set_prison_data;
+
+ mac_prison_label_free(intlabel);
+}
+
int
sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
{
diff --git a/sys/security/mac/mac_syscalls.h b/sys/security/mac/mac_syscalls.h
index f95ff3ef1264..76c8e6d188bb 100644
--- a/sys/security/mac/mac_syscalls.h
+++ b/sys/security/mac/mac_syscalls.h
@@ -30,4 +30,14 @@ int mac_set_proc_core(struct thread *const td, struct ucred *const newcred,
void mac_set_proc_finish(struct thread *const td, bool proc_label_set,
void *const mac_set_proc_data);
+struct vfsoptlist;
+int mac_get_prison(struct thread *const td, struct prison *pr,
+ struct vfsoptlist *opts);
+int mac_set_prison_prepare(struct thread *const td, struct vfsoptlist *opts,
+ void **const mac_set_prison_data);
+int mac_set_prison_core(struct thread *const td, struct prison *pr,
+ void *const mac_set_prison_data);
+void mac_set_prison_finish(struct thread *const td, bool prison_label_set,
+ void *const mac_set_prison_data);
+
#endif /* !_SECURITY_MAC_MAC_SYSCALLS_H_ */