Example #1
0
/* copyup all extended attrs for a given dentry */
static int copyup_xattrs(struct dentry *old_lower_dentry,
			 struct dentry *new_lower_dentry)
{
	int err = 0;
	ssize_t list_size = -1;
	char *name_list = NULL;
	char *attr_value = NULL;
	char *name_list_buf = NULL;

	/* query the actual size of the xattr list */
	list_size = vfs_listxattr(old_lower_dentry, NULL, 0);
	if (list_size <= 0) {
		err = list_size;
		goto out;
	}

	/* allocate space for the actual list */
	name_list = unionfs_xattr_alloc(list_size + 1, XATTR_LIST_MAX);
	if (unlikely(!name_list || IS_ERR(name_list))) {
		err = PTR_ERR(name_list);
		goto out;
	}

	name_list_buf = name_list; /* save for kfree at end */

	/* now get the actual xattr list of the source file */
	list_size = vfs_listxattr(old_lower_dentry, name_list, list_size);
	if (list_size <= 0) {
		err = list_size;
		goto out;
	}

	/* allocate space to hold each xattr's value */
	attr_value = unionfs_xattr_alloc(XATTR_SIZE_MAX, XATTR_SIZE_MAX);
	if (unlikely(!attr_value || IS_ERR(attr_value))) {
		err = PTR_ERR(name_list);
		goto out;
	}

	/* in a loop, get and set each xattr from src to dst file */
	while (*name_list) {
		ssize_t size;

		/* Lock here since vfs_getxattr doesn't lock for us */
		mutex_lock(&old_lower_dentry->d_inode->i_mutex);
		size = vfs_getxattr(old_lower_dentry, name_list,
				    attr_value, XATTR_SIZE_MAX);
		mutex_unlock(&old_lower_dentry->d_inode->i_mutex);
		if (size < 0) {
			err = size;
			goto out;
		}
		if (size > XATTR_SIZE_MAX) {
			err = -E2BIG;
			goto out;
		}
		/* Don't lock here since vfs_setxattr does it for us. */
		err = vfs_setxattr(new_lower_dentry, name_list, attr_value,
				   size, 0);
		/*
		 * Selinux depends on "security.*" xattrs, so to maintain
		 * the security of copied-up files, if Selinux is active,
		 * then we must copy these xattrs as well.  So we need to
		 * temporarily get FOWNER privileges.
		 * XXX: move entire copyup code to SIOQ.
		 */
		if (err == -EPERM && !capable(CAP_FOWNER)) {
			cap_raise(current->cap_effective, CAP_FOWNER);
			err = vfs_setxattr(new_lower_dentry, name_list,
					   attr_value, size, 0);
			cap_lower(current->cap_effective, CAP_FOWNER);
		}
		if (err < 0)
			goto out;
		name_list += strlen(name_list) + 1;
	}
out:
	unionfs_xattr_kfree(name_list_buf);
	unionfs_xattr_kfree(attr_value);
	/* Ignore if xattr isn't supported */
	if (err == -ENOTSUPP || err == -EOPNOTSUPP)
		err = 0;
	return err;
}
Example #2
0
/* copyup all extended attrs for a given dentry */
static int copyup_xattrs(struct dentry *old_hidden_dentry,
			 struct dentry *new_hidden_dentry)
{
	int err = 0;
	ssize_t list_size = -1;
	char *name_list = NULL;
	char *attr_value = NULL;
	char *name_list_orig = NULL;

	list_size = vfs_listxattr(old_hidden_dentry, NULL, 0);

	if (list_size <= 0) {
		err = list_size;
		goto out;
	}

	name_list = unionfs_xattr_alloc(list_size + 1, XATTR_LIST_MAX);
	if (!name_list || IS_ERR(name_list)) {
		err = PTR_ERR(name_list);
		goto out;
	}
	list_size = vfs_listxattr(old_hidden_dentry, name_list, list_size);
	attr_value = unionfs_xattr_alloc(XATTR_SIZE_MAX, XATTR_SIZE_MAX);
	if (!attr_value || IS_ERR(attr_value)) {
		err = PTR_ERR(name_list);
		goto out;
	}
	name_list_orig = name_list;
	while (*name_list) {
		ssize_t size;

		/* Lock here since vfs_getxattr doesn't lock for us */
		mutex_lock(&old_hidden_dentry->d_inode->i_mutex);
		size = vfs_getxattr(old_hidden_dentry, name_list,
				    attr_value, XATTR_SIZE_MAX);
		mutex_unlock(&old_hidden_dentry->d_inode->i_mutex);
		if (size < 0) {
			err = size;
			goto out;
		}

		if (size > XATTR_SIZE_MAX) {
			err = -E2BIG;
			goto out;
		}
		/* Don't lock here since vfs_setxattr does it for us. */
		err = vfs_setxattr(new_hidden_dentry, name_list, attr_value,
				   size, 0);

		if (err < 0)
			goto out;
		name_list += strlen(name_list) + 1;
	}
      out:
	name_list = name_list_orig;

	if (name_list)
		unionfs_xattr_free(name_list, list_size + 1);
	if (attr_value)
		unionfs_xattr_free(attr_value, XATTR_SIZE_MAX);
	/* It is no big deal if this fails, we just roll with the punches. */
	if (err == -ENOTSUPP || err == -EOPNOTSUPP)
		err = 0;
	return err;
}