On Thursday, October 29, 2015 02:01:42 PM Andrew Perepechko wrote:
> Make validatetrans decisions available through selinuxfs.
> "/validatetrans" is added to selinuxfs for this purpose.
> This functionality is needed by file system servers
> implemented in userspace or kernelspace without the VFS
> layer.
>
> Writing "$oldcontext $newcontext $tclass $taskcontext"
> to /validatetrans is expected to return 0 if the transition
> is allowed and -EPERM otherwise.
>
> Signed-off-by: Andrew Perepechko <[email protected]>
> CC: [email protected]
Added to the selinux#next queue, thanks.
> diff --git a/security/selinux/include/classmap.h
> b/security/selinux/include/classmap.h index 5a4eef5..ef83c4b 100644
> --- a/security/selinux/include/classmap.h
> +++ b/security/selinux/include/classmap.h
> @@ -21,7 +21,7 @@ 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", NULL } },
> + "setcheckreqprot", "read_policy", "validate_trans", NULL } },
> { "process",
> { "fork", "transition", "sigchld", "sigkill",
> "sigstop", "signull", "signal", "ptrace", "getsched", "setsched",
> diff --git a/security/selinux/include/security.h
> b/security/selinux/include/security.h index 223e9fd..38feb55 100644
> --- a/security/selinux/include/security.h
> +++ b/security/selinux/include/security.h
> @@ -187,6 +187,9 @@ int security_node_sid(u16 domain, void *addr, u32
> addrlen, int security_validate_transition(u32 oldsid, u32 newsid, u32
> tasksid, u16 tclass);
>
> +int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
> + u16 tclass);
> +
> int security_bounded_transition(u32 oldsid, u32 newsid);
>
> int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
> diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
> index c02da25..0dc407d 100644
> --- a/security/selinux/selinuxfs.c
> +++ b/security/selinux/selinuxfs.c
> @@ -116,6 +116,7 @@ enum sel_inos {
> SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
> SEL_STATUS, /* export current status using mmap() */
> SEL_POLICY, /* allow userspace to read the in kernel policy */
> + SEL_VALIDATE_TRANS, /* compute validatetrans decision */
> SEL_INO_NEXT, /* The next inode number to use */
> };
>
> @@ -653,6 +654,83 @@ static const struct file_operations
> sel_checkreqprot_ops = { .llseek = generic_file_llseek,
> };
>
> +static ssize_t sel_write_validatetrans(struct file *file,
> + const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + char *oldcon = NULL, *newcon = NULL, *taskcon = NULL;
> + char *req = NULL;
> + u32 osid, nsid, tsid;
> + u16 tclass;
> + int rc;
> +
> + rc = task_has_security(current, SECURITY__VALIDATE_TRANS);
> + if (rc)
> + goto out;
> +
> + rc = -ENOMEM;
> + if (count >= PAGE_SIZE)
> + goto out;
> +
> + /* No partial writes. */
> + rc = -EINVAL;
> + if (*ppos != 0)
> + goto out;
> +
> + rc = -ENOMEM;
> + req = kzalloc(count + 1, GFP_KERNEL);
> + if (!req)
> + goto out;
> +
> + rc = -EFAULT;
> + if (copy_from_user(req, buf, count))
> + goto out;
> +
> + rc = -ENOMEM;
> + oldcon = kzalloc(count + 1, GFP_KERNEL);
> + if (!oldcon)
> + goto out;
> +
> + newcon = kzalloc(count + 1, GFP_KERNEL);
> + if (!newcon)
> + goto out;
> +
> + taskcon = kzalloc(count + 1, GFP_KERNEL);
> + if (!taskcon)
> + goto out;
> +
> + rc = -EINVAL;
> + if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4)
> + goto out;
> +
> + rc = security_context_str_to_sid(oldcon, &osid, GFP_KERNEL);
> + if (rc)
> + goto out;
> +
> + rc = security_context_str_to_sid(newcon, &nsid, GFP_KERNEL);
> + if (rc)
> + goto out;
> +
> + rc = security_context_str_to_sid(taskcon, &tsid, GFP_KERNEL);
> + if (rc)
> + goto out;
> +
> + rc = security_validate_transition_user(osid, nsid, tsid, tclass);
> + if (!rc)
> + rc = count;
> +out:
> + kfree(req);
> + kfree(oldcon);
> + kfree(newcon);
> + kfree(taskcon);
> + return rc;
> +}
> +
> +static const struct file_operations sel_transition_ops = {
> + .write = sel_write_validatetrans,
> + .llseek = generic_file_llseek,
> +};
> +
> /*
> * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
> */
> @@ -1759,6 +1837,8 @@ static int sel_fill_super(struct super_block *sb, void
> *data, int silent) [SEL_DENY_UNKNOWN] = {"deny_unknown",
> &sel_handle_unknown_ops, S_IRUGO}, [SEL_STATUS] = {"status",
> &sel_handle_status_ops, S_IRUGO},
> [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
> + [SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
> + S_IWUGO},
> /* last one */ {""}
> };
> ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index ebb5eb3..ebda973 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -778,8 +778,8 @@ out:
> return -EPERM;
> }
>
> -int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
> - u16 orig_tclass)
> +static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32
> tasksid, + u16 orig_tclass, bool user)
> {
> struct context *ocontext;
> struct context *ncontext;
> @@ -794,11 +794,12 @@ int security_validate_transition(u32 oldsid, u32
> newsid, u32 tasksid,
>
> read_lock(&policy_rwlock);
>
> - tclass = unmap_class(orig_tclass);
> + if (!user)
> + tclass = unmap_class(orig_tclass);
> + else
> + tclass = orig_tclass;
>
> if (!tclass || tclass > policydb.p_classes.nprim) {
> - printk(KERN_ERR "SELinux: %s: unrecognized class %d\n",
> - __func__, tclass);
> rc = -EINVAL;
> goto out;
> }
> @@ -832,8 +833,13 @@ int security_validate_transition(u32 oldsid, u32
> newsid, u32 tasksid, while (constraint) {
> if (!constraint_expr_eval(ocontext, ncontext, tcontext,
> constraint->expr)) {
> - rc = security_validtrans_handle_fail(ocontext, ncontext,
> - tcontext, tclass);
> + if (user)
> + rc = -EPERM;
> + else
> + rc = security_validtrans_handle_fail(ocontext,
> + ncontext,
> + tcontext,
> + tclass);
> goto out;
> }
> constraint = constraint->next;
> @@ -844,6 +850,20 @@ out:
> return rc;
> }
>
> +int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
> + u16 tclass)
> +{
> + return security_compute_validatetrans(oldsid, newsid, tasksid,
> + tclass, true);
> +}
> +
> +int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
> + u16 orig_tclass)
> +{
> + return security_compute_validatetrans(oldsid, newsid, tasksid,
> + orig_tclass, false);
> +}
> +
> /*
> * security_bounded_transition - check whether the given
> * transition is directed to bounded, or not.
--
paul moore
www.paul-moore.com
--
To unsubscribe from this list: send the line "unsubscribe
linux-security-module" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html