Beispiel #1
0
/**
 * ccs_realpath - Returns realpath(3) of the given pathname but ignores chroot'ed root.
 *
 * @path: Pointer to "struct path".
 *
 * Returns the realpath of the given @path on success, NULL otherwise.
 *
 * This function uses kzalloc(), so caller must kfree() if this function
 * didn't return NULL.
 */
char *ccs_realpath(struct path *path)
{
	char *buf = NULL;
	char *name = NULL;
	unsigned int buf_len = PAGE_SIZE / 2;
	struct dentry *dentry = path->dentry;
	struct super_block *sb;
	if (!dentry)
		return NULL;
	sb = dentry->d_sb;
	while (1) {
		char *pos;
		struct inode *inode;
		buf_len <<= 1;
		kfree(buf);
		buf = kmalloc(buf_len, CCS_GFP_FLAGS);
		if (!buf)
			break;
		/* To make sure that pos is '\0' terminated. */
		buf[buf_len - 1] = '\0';
		/* Get better name for socket. */
		if (sb->s_magic == SOCKFS_MAGIC) {
			pos = ccs_get_socket_name(path, buf, buf_len - 1);
			goto encode;
		}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
		/* For "pipe:[\$]". */
		if (dentry->d_op && dentry->d_op->d_dname) {
			pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
			goto encode;
		}
#endif
		inode = sb->s_root->d_inode;
		/*
		 * Use local name for "filesystems without rename() operation"
		 * or "path without vfsmount" or "absolute name is unavailable"
		 * cases.
		 */
		if (!path->mnt || (inode->i_op && !inode->i_op->rename))
			pos = ERR_PTR(-EINVAL);
		else {
			/* Get absolute name for the rest. */
			ccs_realpath_lock();
			pos = ccs_get_absolute_path(path, buf, buf_len - 1);
			ccs_realpath_unlock();
		}
		if (pos == ERR_PTR(-EINVAL))
			pos = ccs_get_local_path(path->dentry, buf,
						 buf_len - 1);
encode:
		if (IS_ERR(pos))
			continue;
		name = ccs_encode(pos);
		break;
	}
	kfree(buf);
	if (!name)
		ccs_warn_oom(__func__);
	return name;
}
Beispiel #2
0
/**
 * ccs_write_transition - write() for /proc/ccs/.transition interface.
 *
 * @file:  Pointer to "struct file".
 * @buf:   Domainname to transit to. Must ends with '\0'.
 * @count: Size of @buf.
 * @ppos:  Unused.
 *
 * Returns @count on success, negative value otherwise.
 */
static ssize_t ccs_write_transition(struct file *file, const char __user *buf,
				    size_t count, loff_t *ppos)
{
	const char *self_domain = ccs_current_domain()->domainname->name;
	const int self_domain_len = strlen(self_domain);
	char *data;
	int data_len;
	char *tmp;
	int idx;
	int error = -ENOMEM;
	if (!count || count + self_domain_len >= CCS_EXEC_TMPSIZE - 10)
		return -ENOMEM;
	data = kmalloc(count, CCS_GFP_FLAGS);
	if (!data)
		return -ENOMEM;
	if (copy_from_user(data, buf, count)) {
		error = -EFAULT;
		goto out;
	}
	if (memchr(data, '\0', count) != data + count - 1) {
		error = -EINVAL;
		goto out;
	}
	tmp = ccs_encode(data);
	kfree(data);
	data = tmp;
	if (!data)
		goto out;
	data_len = strlen(data);
	tmp = kzalloc(self_domain_len + data_len + 5, CCS_GFP_FLAGS);
	if (!tmp)
		goto out;
	/*
	 * Add "//" prefix to requested name in order to distinguish domain
	 * transitions with execve().
	 */
	snprintf(tmp, self_domain_len + data_len + 4, "%s //%s", self_domain,
		 data);
	kfree(data);
	data = tmp;
	idx = ccs_read_lock();
	error = ccs_may_transit(data, data + self_domain_len + 1);
	ccs_read_unlock(idx);
 out:
	kfree(data);
	return error ? error : count;
}