|
@@ -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);
|