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
This commit is contained in:
+51
-1
@@ -80,6 +80,8 @@
|
|||||||
#endif /* DDB */
|
#endif /* DDB */
|
||||||
|
|
||||||
#include <security/mac/mac_framework.h>
|
#include <security/mac/mac_framework.h>
|
||||||
|
#include <security/mac/mac_policy.h>
|
||||||
|
#include <security/mac/mac_syscalls.h>
|
||||||
|
|
||||||
#define PRISON0_HOSTUUID_MODULE "hostuuid"
|
#define PRISON0_HOSTUUID_MODULE "hostuuid"
|
||||||
|
|
||||||
@@ -1027,6 +1029,10 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
|||||||
#endif
|
#endif
|
||||||
unsigned long hid;
|
unsigned long hid;
|
||||||
size_t namelen, onamelen, pnamelen;
|
size_t namelen, onamelen, pnamelen;
|
||||||
|
#ifdef MAC
|
||||||
|
void *mac_set_prison_data = NULL;
|
||||||
|
int gotmaclabel;
|
||||||
|
#endif
|
||||||
int created, cuflags, descend, drflags, enforce;
|
int created, cuflags, descend, drflags, enforce;
|
||||||
int error, errmsg_len, errmsg_pos;
|
int error, errmsg_len, errmsg_pos;
|
||||||
int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel;
|
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;
|
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
|
#ifdef INET
|
||||||
error = vfs_getopt(opts, "ip4.addr", &op, &ip4s);
|
error = vfs_getopt(opts, "ip4.addr", &op, &ip4s);
|
||||||
if (error == ENOENT)
|
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;
|
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);
|
mtx_unlock(&pr->pr_mtx);
|
||||||
drflags &= ~PD_LOCKED;
|
drflags &= ~PD_LOCKED;
|
||||||
/*
|
/*
|
||||||
@@ -2370,6 +2398,10 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
|||||||
#endif
|
#endif
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
prison_ip_free(ip6);
|
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
|
#endif
|
||||||
if (jfp_out != NULL)
|
if (jfp_out != NULL)
|
||||||
fdrop(jfp_out, td);
|
fdrop(jfp_out, td);
|
||||||
@@ -2835,9 +2867,22 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
|
|||||||
if (error != 0 && error != ENOENT)
|
if (error != 0 && error != ENOENT)
|
||||||
goto done;
|
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);
|
mtx_unlock(&pr->pr_mtx);
|
||||||
drflags &= ~PD_LOCKED;
|
drflags &= ~PD_LOCKED;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Get the module parameters. */
|
||||||
error = osd_jail_call(pr, PR_METHOD_GET, opts);
|
error = osd_jail_call(pr, PR_METHOD_GET, opts);
|
||||||
if (error)
|
if (error)
|
||||||
goto done;
|
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_NODE(cpuset, "Jail cpuset");
|
||||||
SYSCTL_JAIL_PARAM(_cpuset, id, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID");
|
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
|
#ifdef INET
|
||||||
SYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RDTUN,
|
SYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RDTUN,
|
||||||
"Jail IPv4 address virtualization");
|
"Jail IPv4 address virtualization");
|
||||||
|
|||||||
@@ -302,6 +302,160 @@ mac_set_proc_finish(struct thread *const td, bool proc_label_set,
|
|||||||
mac_cred_label_free(intlabel);
|
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
|
int
|
||||||
sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
|
sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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 mac_set_proc_finish(struct thread *const td, bool proc_label_set,
|
||||||
void *const mac_set_proc_data);
|
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_ */
|
#endif /* !_SECURITY_MAC_MAC_SYSCALLS_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user