Signed-off-by: Stephen Smalley <stephen.smalley.work@xxxxxxxxx> --- security/selinux/include/classmap.h | 2 +- security/selinux/selinuxfs.c | 66 +++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 2bc20135324a..84285fba2c06 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -50,7 +50,7 @@ const struct security_class_mapping secclass_map[] = { { "compute_av", "compute_create", "compute_member", "check_context", "load_policy", "compute_relabel", "compute_user", "setenforce", "setbool", "setsecparam", "setcheckreqprot", "read_policy", - "validate_trans", NULL } }, + "validate_trans", "unshare", NULL } }, { "process", { "fork", "transition", "sigchld", "sigkill", "sigstop", "signull", "signal", "ptrace", diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index a59153c322cc..120cfff35029 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -64,6 +64,7 @@ enum sel_inos { SEL_STATUS, /* export current status using mmap() */ SEL_POLICY, /* allow userspace to read the in kernel policy */ SEL_VALIDATE_TRANS, /* compute validatetrans decision */ + SEL_UNSHARE, /* unshare selinux namespace */ SEL_INO_NEXT, /* The next inode number to use */ }; @@ -318,6 +319,70 @@ static const struct file_operations sel_disable_ops = { .llseek = generic_file_llseek, }; +static ssize_t sel_write_unshare(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + +{ + struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; + struct selinux_state *state = fsi->state; + char *page; + ssize_t length; + bool set; + int rc; + + if (count >= PAGE_SIZE) + return -ENOMEM; + + /* No partial writes. */ + if (*ppos != 0) + return -EINVAL; + + rc = avc_has_perm(current_selinux_state, current_sid(), + SECINITSID_SECURITY, SECCLASS_SECURITY, + SECURITY__UNSHARE, NULL); + if (rc) + return rc; + + page = memdup_user_nul(buf, count); + if (IS_ERR(page)) + return PTR_ERR(page); + + length = -EINVAL; + if (kstrtobool(page, &set)) + goto out; + + if (set) { + struct cred *cred = prepare_creds(); + struct task_security_struct *tsec; + + if (!cred) { + length = -ENOMEM; + goto out; + } + tsec = selinux_cred(cred); + if (selinux_state_create(state, &tsec->state)) { + abort_creds(cred); + length = -ENOMEM; + goto out; + } + tsec->osid = tsec->sid = SECINITSID_KERNEL; + tsec->exec_sid = tsec->create_sid = tsec->keycreate_sid = + tsec->sockcreate_sid = SECSID_NULL; + tsec->parent_cred = get_current_cred(); + commit_creds(cred); + } + + length = count; +out: + kfree(page); + return length; +} + +static const struct file_operations sel_unshare_ops = { + .write = sel_write_unshare, + .llseek = generic_file_llseek, +}; + static ssize_t sel_read_policyvers(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { @@ -2052,6 +2117,7 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO}, [SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops, S_IWUGO}, + [SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0200}, /* last one */ {""} }; -- 2.47.1