Пример #1
0
static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
{
	char *scon = NULL, *tcon = NULL;
	u32 ssid, tsid, newsid;
	u16 tclass;
	ssize_t length;
	char *newcon = NULL;
	u32 len;

	length = task_has_security(current, SECURITY__COMPUTE_RELABEL);
	if (length)
		goto out;

	length = -ENOMEM;
	scon = kzalloc(size + 1, GFP_KERNEL);
	if (!scon)
		goto out;

	length = -ENOMEM;
	tcon = kzalloc(size + 1, GFP_KERNEL);
	if (!tcon)
		goto out;

	length = -EINVAL;
	if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
		goto out;

	length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
	if (length)
		goto out;

	length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
	if (length)
		goto out;

	length = security_change_sid(ssid, tsid, tclass, &newsid);
	if (length)
		goto out;

	length = security_sid_to_context(newsid, &newcon, &len);
	if (length)
		goto out;

	length = -ERANGE;
	if (len > SIMPLE_TRANSACTION_LIMIT)
		goto out;

	memcpy(buf, newcon, len);
	length = len;
out:
	kfree(newcon);
	kfree(tcon);
	kfree(scon);
	return length;
}
static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
			      size_t count, loff_t *ppos)
{
	char *page = NULL;
	ssize_t length;
	int new_value;
	struct inode *inode = filep->f_path.dentry->d_inode;
	unsigned index = inode->i_ino & SEL_INO_MASK;
	const char *name = filep->f_path.dentry->d_name.name;

	mutex_lock(&sel_mutex);

	length = task_has_security(current, SECURITY__SETBOOL);
	if (length)
		goto out;

	length = -EINVAL;
	if (index >= bool_num || strcmp(name, bool_pending_names[index]))
		goto out;

	length = -ENOMEM;
	if (count >= PAGE_SIZE)
		goto out;

	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
		goto out;

	length = -ENOMEM;
	page = (char *)get_zeroed_page(GFP_KERNEL);
	if (!page)
		goto out;

	length = -EFAULT;
	if (copy_from_user(page, buf, count))
		goto out;

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;

	if (new_value)
		new_value = 1;

	bool_pending_values[index] = new_value;
	length = count;

out:
	mutex_unlock(&sel_mutex);
	free_page((unsigned long) page);
	return length;
}
Пример #3
0
static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
				 size_t count, loff_t *ppos)

{
	char *page = NULL;
	ssize_t length;
	int new_value;

	length = -ENOMEM;
	if (count >= PAGE_SIZE)
		goto out;

	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
		goto out;

	length = -ENOMEM;
	page = (char *)get_zeroed_page(GFP_KERNEL);
	if (!page)
		goto out;

	length = -EFAULT;
	if (copy_from_user(page, buf, count))
		goto out;

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;
	
	new_value = 0;

	if (new_value != selinux_enforcing) {
		length = task_has_security(current, SECURITY__SETENFORCE);
		if (length)
			goto out;
		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
			"enforcing=%d old_enforcing=%d auid=%u ses=%u",
			new_value, selinux_enforcing,
			from_kuid(&init_user_ns, audit_get_loginuid(current)),
			audit_get_sessionid(current));
		selinux_enforcing = new_value;
		if (selinux_enforcing)
			avc_ss_reset(0);
		selnl_notify_setenforce(selinux_enforcing);
		selinux_status_update_setenforce(selinux_enforcing);
	}
	length = count;
out:
	free_page((unsigned long) page);
	return length;
}
Пример #4
0
static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
			      size_t count, loff_t *ppos)
{
	char *page = NULL;
	ssize_t length;
	int new_value;
	unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
	const char *name = filep->f_path.dentry->d_name.name;

	mutex_lock(&sel_mutex);

	length = task_has_security(current, SECURITY__SETBOOL);
	if (length)
		goto out;

	length = -EINVAL;
	if (index >= bool_num || strcmp(name, bool_pending_names[index]))
		goto out;

	length = -ENOMEM;
	if (count >= PAGE_SIZE)
		goto out;

	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
		goto out;

	page = memdup_user_nul(buf, count);
	if (IS_ERR(page)) {
		length = PTR_ERR(page);
		page = NULL;
		goto out;
	}

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;

	if (new_value)
		new_value = 1;

	bool_pending_values[index] = new_value;
	length = count;

out:
	mutex_unlock(&sel_mutex);
	kfree(page);
	return length;
}
static ssize_t sel_commit_bools_write(struct file *filep,
				      const char __user *buf,
				      size_t count, loff_t *ppos)
{
	char *page = NULL;
	ssize_t length;
	int new_value;

	mutex_lock(&sel_mutex);

	length = task_has_security(current, SECURITY__SETBOOL);
	if (length)
		goto out;

	length = -ENOMEM;
	if (count >= PAGE_SIZE)
		goto out;

	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
		goto out;

	length = -ENOMEM;
	page = (char *)get_zeroed_page(GFP_KERNEL);
	if (!page)
		goto out;

	length = -EFAULT;
	if (copy_from_user(page, buf, count))
		goto out;

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;

	length = 0;
	if (new_value && bool_pending_values)
		length = security_set_bools(bool_num, bool_pending_values);

	if (!length)
		length = count;

out:
	mutex_unlock(&sel_mutex);
	free_page((unsigned long) page);
	return length;
}
Пример #6
0
static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
{
	char *scon, *tcon;
	u32 ssid, tsid;
	u16 tclass;
	u32 req;
	struct av_decision avd;
	ssize_t length;

	length = task_has_security(current, SECURITY__COMPUTE_AV);
	if (length)
		return length;

	length = -ENOMEM;
	scon = kzalloc(size+1, GFP_KERNEL);
	if (!scon)
		return length;

	tcon = kzalloc(size+1, GFP_KERNEL);
	if (!tcon)
		goto out;

	length = -EINVAL;
	if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4)
		goto out2;

	length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
	if (length < 0)
		goto out2;
	length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
	if (length < 0)
		goto out2;

	length = security_compute_av_user(ssid, tsid, tclass, req, &avd);
	if (length < 0)
		goto out2;

	length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
			  "%x %x %x %x %u %x",
			  avd.allowed, 0xffffffff,
			  avd.auditallow, avd.auditdeny,
			  avd.seqno, avd.flags);
out2:
	kfree(tcon);
out:
	kfree(scon);
	return length;
}
Пример #7
0
static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
{
	char *scon = NULL, *tcon = NULL;
	u32 ssid, tsid;
	u16 tclass;
	struct av_decision avd;
	ssize_t length;
	char format[32];

	length = task_has_security(current, SECURITY__COMPUTE_AV);
	if (length)
		goto out;

	length = -ENOMEM;
	scon = kzalloc(size + 1, GFP_KERNEL);
	if (!scon)
		goto out;

	length = -ENOMEM;
	tcon = kzalloc(size + 1, GFP_KERNEL);
	if (!tcon)
		goto out;

	length = -EINVAL;
	snprintf(format, sizeof(format), "%%%ds %%%ds %%hu", size, size);
	if (sscanf(buf, format, scon, tcon, &tclass) != 3)
		goto out;

	length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
	if (length)
		goto out;

	length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
	if (length)
		goto out;

	security_compute_av_user(ssid, tsid, tclass, &avd);

	length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
			  "%x %x %x %x %u %x",
			  avd.allowed, 0xffffffff,
			  avd.auditallow, avd.auditdeny,
			  avd.seqno, avd.flags);
out:
	kfree(tcon);
	kfree(scon);
	return length;
}
Пример #8
0
static ssize_t sel_write_avc_cache_threshold(struct file *file,
					     const char __user *buf,
					     size_t count, loff_t *ppos)

{
	char *page;
	ssize_t ret;
	int new_value;

	if (count >= PAGE_SIZE) {
		ret = -ENOMEM;
		goto out;
	}

	if (*ppos != 0) {
		/* No partial writes. */
		ret = -EINVAL;
		goto out;
	}

	page = (char *)get_zeroed_page(GFP_KERNEL);
	if (!page) {
		ret = -ENOMEM;
		goto out;
	}

	if (copy_from_user(page, buf, count)) {
		ret = -EFAULT;
		goto out_free;
	}

	if (sscanf(page, "%u", &new_value) != 1) {
		ret = -EINVAL;
		goto out;
	}

	if (new_value != avc_cache_threshold) {
		ret = task_has_security(current, SECURITY__SETSECPARAM);
		if (ret)
			goto out_free;
		avc_cache_threshold = new_value;
	}
	ret = count;
out_free:
	free_page((unsigned long)page);
out:
	return ret;
}
static int sel_open_policy(struct inode *inode, struct file *filp)
{
	struct policy_load_memory *plm = NULL;
	int rc;

	BUG_ON(filp->private_data);

	mutex_lock(&sel_mutex);

	rc = task_has_security(current, SECURITY__READ_POLICY);
	if (rc)
		goto err;

	rc = -EBUSY;
	if (policy_opened)
		goto err;

	rc = -ENOMEM;
	plm = kzalloc(sizeof(*plm), GFP_KERNEL);
	if (!plm)
		goto err;

	if (i_size_read(inode) != security_policydb_len()) {
		mutex_lock(&inode->i_mutex);
		i_size_write(inode, security_policydb_len());
		mutex_unlock(&inode->i_mutex);
	}

	rc = security_read_policy(&plm->data, &plm->len);
	if (rc)
		goto err;

	policy_opened = 1;

	filp->private_data = plm;

	mutex_unlock(&sel_mutex);

	return 0;
err:
	mutex_unlock(&sel_mutex);

	if (plm)
		vfree(plm->data);
	kfree(plm);
	return rc;
}
static ssize_t sel_read_policy(struct file *filp, char __user *buf,
			       size_t count, loff_t *ppos)
{
	struct policy_load_memory *plm = filp->private_data;
	int ret;

	mutex_lock(&sel_mutex);

	ret = task_has_security(current, SECURITY__READ_POLICY);
	if (ret)
		goto out;

	ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
out:
	mutex_unlock(&sel_mutex);
	return ret;
}
Пример #11
0
static ssize_t sel_commit_bools_write(struct file *filep,
				      const char __user *buf,
				      size_t count, loff_t *ppos)
{
	char *page = NULL;
	ssize_t length;
	int new_value;

	mutex_lock(&sel_mutex);

	length = task_has_security(current, SECURITY__SETBOOL);
	if (length)
		goto out;

	length = -ENOMEM;
	if (count >= PAGE_SIZE)
		goto out;

	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
		goto out;

	page = memdup_user_nul(buf, count);
	if (IS_ERR(page)) {
		length = PTR_ERR(page);
		page = NULL;
		goto out;
	}

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;

	length = 0;
	if (new_value && bool_pending_values)
		length = security_set_bools(bool_num, bool_pending_values);

	if (!length)
		length = count;

out:
	mutex_unlock(&sel_mutex);
	kfree(page);
	return length;
}
Пример #12
0
static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
				 size_t count, loff_t *ppos)

{
	char *page = NULL;
	ssize_t length;
	int new_value;

	if (count >= PAGE_SIZE)
		return -ENOMEM;

	/* No partial writes. */
	if (*ppos != 0)
		return -EINVAL;

	page = memdup_user_nul(buf, count);
	if (IS_ERR(page))
		return PTR_ERR(page);

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;

	new_value = !!new_value;

	if (new_value != selinux_enforcing) {
		length = task_has_security(current, SECURITY__SETENFORCE);
		if (length)
			goto out;
		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
			"enforcing=%d old_enforcing=%d auid=%u ses=%u",
			new_value, selinux_enforcing,
			from_kuid(&init_user_ns, audit_get_loginuid(current)),
			audit_get_sessionid(current));
		selinux_enforcing = new_value;
		if (selinux_enforcing)
			avc_ss_reset(0);
		selnl_notify_setenforce(selinux_enforcing);
		selinux_status_update_setenforce(selinux_enforcing);
	}
	length = count;
out:
	kfree(page);
	return length;
}
static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
				      size_t count, loff_t *ppos)
{
	char *page = NULL;
	ssize_t length;
	unsigned int new_value;

	length = task_has_security(current, SECURITY__SETCHECKREQPROT);
	if (length)
		goto out;

	length = -ENOMEM;
	if (count >= PAGE_SIZE)
		goto out;

	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
		goto out;

	length = -ENOMEM;
	page = (char *)get_zeroed_page(GFP_KERNEL);
	if (!page)
		goto out;

	length = -EFAULT;
	if (copy_from_user(page, buf, count))
		goto out;

	length = -EINVAL;
	if (sscanf(page, "%u", &new_value) != 1)
		goto out;

	selinux_checkreqprot = new_value ? 1 : 0;
	length = count;
out:
	free_page((unsigned long) page);
	return length;
}
Пример #14
0
static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
{
	char *scon = NULL, *tcon = NULL;
	char *namebuf = NULL, *objname = NULL;
	u32 ssid, tsid, newsid;
	u16 tclass;
	ssize_t length;
	char *newcon = NULL;
	u32 len;
	int nargs;
	char format[32];

	length = task_has_security(current, SECURITY__COMPUTE_CREATE);
	if (length)
		goto out;

	length = -ENOMEM;
	scon = kzalloc(size + 1, GFP_KERNEL);
	if (!scon)
		goto out;

	length = -ENOMEM;
	tcon = kzalloc(size + 1, GFP_KERNEL);
	if (!tcon)
		goto out;

	length = -ENOMEM;
	namebuf = kzalloc(size + 1, GFP_KERNEL);
	if (!namebuf)
		goto out;

	length = -EINVAL;
	snprintf(format, sizeof(format), "%%%ds %%%ds %%hu %%%ds", size, size, size);
	nargs = sscanf(buf, format, scon, tcon, &tclass, namebuf);
	if (nargs < 3 || nargs > 4)
		goto out;
	if (nargs == 4) {
		char   *r, *w;
		int     c1, c2;

		r = w = namebuf;
		do {
			c1 = *r++;
			if (c1 == '+')
				c1 = ' ';
			else if (c1 == '%') {
				c1 = hex_to_bin(*r++);
				if (c1 < 0)
					goto out;
				c2 = hex_to_bin(*r++);
				if (c2 < 0)
					goto out;
				c1 = (c1 << 4) | c2;
			}
			*w++ = c1;
		} while (c1 != '\0');

		objname = namebuf;
	}

	length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
	if (length)
		goto out;

	length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
	if (length)
		goto out;

	length = security_transition_sid_user(ssid, tsid, tclass,
					      objname, &newsid);
	if (length)
		goto out;

	length = security_sid_to_context(newsid, &newcon, &len);
	if (length)
		goto out;

	length = -ERANGE;
	if (len > SIMPLE_TRANSACTION_LIMIT) {
		printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
			"payload max\n", __func__, len);
		goto out;
	}

	memcpy(buf, newcon, len);
	length = len;
out:
	kfree(newcon);
	kfree(namebuf);
	kfree(tcon);
	kfree(scon);
	return length;
}
Пример #15
0
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;
}
Пример #16
0
static ssize_t sel_write_load(struct file *file, const char __user *buf,
			      size_t count, loff_t *ppos)

{
	int ret;
	ssize_t length;
	void *data = NULL;

	mutex_lock(&sel_mutex);

	length = task_has_security(current, SECURITY__LOAD_POLICY);
	if (length)
		goto out;

	if (*ppos != 0) {
		/* No partial writes. */
		length = -EINVAL;
		goto out;
	}

	if ((count > 64 * 1024 * 1024)
	    || (data = vmalloc(count)) == NULL) {
		length = -ENOMEM;
		goto out;
	}

	length = -EFAULT;
	if (copy_from_user(data, buf, count) != 0)
		goto out;

	length = security_load_policy(data, count);
	if (length)
		goto out;

	ret = sel_make_bools();
	if (ret) {
		length = ret;
		goto out1;
	}

	ret = sel_make_classes();
	if (ret) {
		length = ret;
		goto out1;
	}

	ret = sel_make_policycap();
	if (ret)
		length = ret;
	else
		length = count;

out1:
	audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
		"policy loaded auid=%u ses=%u",
		audit_get_loginuid(current),
		audit_get_sessionid(current));
out:
	mutex_unlock(&sel_mutex);
	vfree(data);
	return length;
}
Пример #17
0
static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
{
	char *con = NULL, *user = NULL, *ptr;
	u32 sid, *sids = NULL;
	ssize_t length;
	char *newcon;
	int i, rc;
	u32 len, nsids;
	char format[32];

	length = task_has_security(current, SECURITY__COMPUTE_USER);
	if (length)
		goto out;

	length = -ENOMEM;
	con = kzalloc(size + 1, GFP_KERNEL);
	if (!con)
		goto out;

	length = -ENOMEM;
	user = kzalloc(size + 1, GFP_KERNEL);
	if (!user)
		goto out;

	length = -EINVAL;
	snprintf(format, sizeof(format), "%%%ds %%%ds", size, size);
	if (sscanf(buf, format, con, user) != 2)
		goto out;

	length = security_context_to_sid(con, strlen(con) + 1, &sid);
	if (length)
		goto out;

	length = security_get_user_sids(sid, user, &sids, &nsids);
	if (length)
		goto out;

	length = snprintf(buf, PAGE_SIZE, "%u", nsids) + 1;
	ptr = buf + length;
	for (i = 0; i < nsids; i++) {
		rc = security_sid_to_context(sids[i], &newcon, &len);
		if (rc) {
			length = rc;
			goto out;
		}
		if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) {
			kfree(newcon);
			length = -ERANGE;
			goto out;
		}
		memcpy(ptr, newcon, len);
		kfree(newcon);
		ptr += len;
		length += len;
	}
out:
	kfree(sids);
	kfree(user);
	kfree(con);
	return length;
}
Пример #18
0
static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
				 size_t count, loff_t *ppos)

{
	char *page = NULL;
	ssize_t length;
	int new_value;

	length = -ENOMEM;
	if (count >= PAGE_SIZE)
		goto out;

	/* No partial writes. */
	length = EINVAL;
	if (*ppos != 0)
		goto out;

	length = -ENOMEM;
	page = (char *)get_zeroed_page(GFP_KERNEL);
	if (!page)
		goto out;

	length = -EFAULT;
	if (copy_from_user(page, buf, count))
		goto out;

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;
#ifdef CONFIG_ALWAYS_ENFORCE
	// If build is user build and enforce option is set, selinux is always enforcing
	new_value = 1;
	length = task_has_security(current, SECURITY__SETENFORCE);
	audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
                        "config_always_enforce - true; enforcing=%d old_enforcing=%d auid=%u ses=%u",
                        new_value, selinux_enforcing,
                        from_kuid(&init_user_ns, audit_get_loginuid(current)),
                        audit_get_sessionid(current));
	selinux_enforcing = new_value;
	avc_ss_reset(0);
	selnl_notify_setenforce(new_value);
	selinux_status_update_setenforce(new_value);
#else
	new_value = 0; /* Bye NSA! Nobody invited you here, so go back into reclusion and be permissive */
	if (new_value != selinux_enforcing) {
		length = task_has_security(current, SECURITY__SETENFORCE);
		if (length)
			goto out;
		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
			"enforcing=%d old_enforcing=%d auid=%u ses=%u",
			new_value, selinux_enforcing,
			from_kuid(&init_user_ns, audit_get_loginuid(current)),
			audit_get_sessionid(current));
		selinux_enforcing = new_value;
		if (selinux_enforcing)
			avc_ss_reset(0);
		selnl_notify_setenforce(selinux_enforcing);
		selinux_status_update_setenforce(selinux_enforcing);
	}
#endif
	length = count;
out:
	free_page((unsigned long) page);
	return length;
}
static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
{
	char *scon = NULL, *tcon = NULL;
	char *namebuf = NULL, *objname = NULL;
	u32 ssid, tsid, newsid;
	u16 tclass;
	ssize_t length;
	char *newcon = NULL;
	u32 len;
	int nargs;

	length = task_has_security(current, SECURITY__COMPUTE_CREATE);
	if (length)
		goto out;

	length = -ENOMEM;
	scon = kzalloc(size + 1, GFP_KERNEL);
	if (!scon)
		goto out;

	length = -ENOMEM;
	tcon = kzalloc(size + 1, GFP_KERNEL);
	if (!tcon)
		goto out;

	length = -ENOMEM;
	namebuf = kzalloc(size + 1, GFP_KERNEL);
	if (!namebuf)
		goto out;

	length = -EINVAL;
	nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
	if (nargs < 3 || nargs > 4)
		goto out;
	if (nargs == 4) {
		/*
		 * If and when the name of new object to be queried contains
		 * either whitespace or multibyte characters, they shall be
		 * encoded based on the percentage-encoding rule.
		 * If not encoded, the sscanf logic picks up only left-half
		 * of the supplied name; splitted by a whitespace unexpectedly.
		 */
		char   *r, *w;
		int     c1, c2;

		r = w = namebuf;
		do {
			c1 = *r++;
			if (c1 == '+')
				c1 = ' ';
			else if (c1 == '%') {
				c1 = hex_to_bin(*r++);
				if (c1 < 0)
					goto out;
				c2 = hex_to_bin(*r++);
				if (c2 < 0)
					goto out;
				c1 = (c1 << 4) | c2;
			}
			*w++ = c1;
		} while (c1 != '\0');

		objname = namebuf;
	}

	length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
	if (length)
		goto out;

	length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
	if (length)
		goto out;

	length = security_transition_sid_user(ssid, tsid, tclass,
					      objname, &newsid);
	if (length)
		goto out;

	length = security_sid_to_context(newsid, &newcon, &len);
	if (length)
		goto out;

	length = -ERANGE;
	if (len > SIMPLE_TRANSACTION_LIMIT) {
		printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
			"payload max\n", __func__, len);
		goto out;
	}

	memcpy(buf, newcon, len);
	length = len;
out:
	kfree(newcon);
	kfree(namebuf);
	kfree(tcon);
	kfree(scon);
	return length;
}
Пример #20
0
static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
{
	char *scon = NULL, *tcon = NULL;
	char *namebuf = NULL, *objname = NULL;
	u32 ssid, tsid, newsid;
	u16 tclass;
	ssize_t length;
	char *newcon = NULL;
	u32 len;
	int nargs;

	length = task_has_security(current, SECURITY__COMPUTE_CREATE);
	if (length)
		goto out;

	length = -ENOMEM;
	scon = kzalloc(size + 1, GFP_KERNEL);
	if (!scon)
		goto out;

	length = -ENOMEM;
	tcon = kzalloc(size + 1, GFP_KERNEL);
	if (!tcon)
		goto out;

	length = -ENOMEM;
	namebuf = kzalloc(size + 1, GFP_KERNEL);
	if (!namebuf)
		goto out;

	length = -EINVAL;
	nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
	if (nargs < 3 || nargs > 4)
		goto out;
	if (nargs == 4)
		objname = namebuf;

	length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
	if (length)
		goto out;

	length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
	if (length)
		goto out;

	length = security_transition_sid_user(ssid, tsid, tclass,
					      objname, &newsid);
	if (length)
		goto out;

	length = security_sid_to_context(newsid, &newcon, &len);
	if (length)
		goto out;

	length = -ERANGE;
	if (len > SIMPLE_TRANSACTION_LIMIT) {
		printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
			"payload max\n", __func__, len);
		goto out;
	}

	memcpy(buf, newcon, len);
	length = len;
out:
	kfree(newcon);
	kfree(namebuf);
	kfree(tcon);
	kfree(scon);
	return length;
}