Commit 610afc0b authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

ovl: pass ovl_fs down to functions accessing private xattrs



This paves the way for optionally using the "user.overlay." xattr
namespace.

Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 26150ab5
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -43,7 +43,8 @@ static bool ovl_must_copy_xattr(const char *name)
	       !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
}

int ovl_copy_xattr(struct dentry *old, struct dentry *new)
int ovl_copy_xattr(struct super_block *sb, struct dentry *old,
		   struct dentry *new)
{
	ssize_t list_size, size, value_size = 0;
	char *buf, *name, *value = NULL;
@@ -81,7 +82,7 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
		}
		list_size -= slen;

		if (ovl_is_private_xattr(name))
		if (ovl_is_private_xattr(sb, name))
			continue;
retry:
		size = vfs_getxattr(old, name, value, value_size);
@@ -355,7 +356,8 @@ int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
}

/* Store file handle of @upper dir in @index dir entry */
static int ovl_set_upper_fh(struct dentry *upper, struct dentry *index)
static int ovl_set_upper_fh(struct ovl_fs *ofs, struct dentry *upper,
			    struct dentry *index)
{
	const struct ovl_fh *fh;
	int err;
@@ -364,7 +366,7 @@ static int ovl_set_upper_fh(struct dentry *upper, struct dentry *index)
	if (IS_ERR(fh))
		return PTR_ERR(fh);

	err = ovl_do_setxattr(index, OVL_XATTR_UPPER, fh->buf, fh->fb.len);
	err = ovl_do_setxattr(ofs, index, OVL_XATTR_UPPER, fh->buf, fh->fb.len);

	kfree(fh);
	return err;
@@ -409,7 +411,7 @@ static int ovl_create_index(struct dentry *dentry, struct dentry *origin,
	if (IS_ERR(temp))
		goto free_name;

	err = ovl_set_upper_fh(upper, temp);
	err = ovl_set_upper_fh(OVL_FS(dentry->d_sb), upper, temp);
	if (err)
		goto out;

@@ -507,7 +509,7 @@ static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp)
			return err;
	}

	err = ovl_copy_xattr(c->lowerpath.dentry, temp);
	err = ovl_copy_xattr(c->dentry->d_sb, c->lowerpath.dentry, temp);
	if (err)
		return err;

@@ -847,7 +849,7 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
	}


	err = ovl_do_removexattr(upperpath.dentry, OVL_XATTR_METACOPY);
	err = ovl_do_removexattr(ofs, upperpath.dentry, OVL_XATTR_METACOPY);
	if (err)
		goto out_free;

+1 −1
Original line number Diff line number Diff line
@@ -394,7 +394,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
	if (IS_ERR(opaquedir))
		goto out_unlock;

	err = ovl_copy_xattr(upper, opaquedir);
	err = ovl_copy_xattr(dentry->d_sb, upper, opaquedir);
	if (err)
		goto out_cleanup;

+1 −1
Original line number Diff line number Diff line
@@ -752,7 +752,7 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
			goto out_err;
	}
	if (index) {
		err = ovl_verify_origin(index, origin.dentry, false);
		err = ovl_verify_origin(ofs, index, origin.dentry, false);
		if (err)
			goto out_err;
	}
+12 −10
Original line number Diff line number Diff line
@@ -327,7 +327,7 @@ static const char *ovl_get_link(struct dentry *dentry,
	return p;
}

bool ovl_is_private_xattr(const char *name)
bool ovl_is_private_xattr(struct super_block *sb, const char *name)
{
	return strncmp(name, OVL_XATTR_PREFIX,
		       sizeof(OVL_XATTR_PREFIX) - 1) == 0;
@@ -391,14 +391,14 @@ int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
	return res;
}

static bool ovl_can_list(const char *s)
static bool ovl_can_list(struct super_block *sb, const char *s)
{
	/* List all non-trusted xatts */
	if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
		return true;

	/* Never list trusted.overlay, list other trusted for superuser only */
	return !ovl_is_private_xattr(s) &&
	return !ovl_is_private_xattr(sb, s) &&
	       ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
}

@@ -425,7 +425,7 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
			return -EIO;

		len -= slen;
		if (!ovl_can_list(s)) {
		if (!ovl_can_list(dentry->d_sb, s)) {
			res -= slen;
			memmove(s, s + slen, len);
		} else {
@@ -722,7 +722,7 @@ static int ovl_set_nlink_common(struct dentry *dentry,
	if (WARN_ON(len >= sizeof(buf)))
		return -EIO;

	return ovl_do_setxattr(ovl_dentry_upper(dentry),
	return ovl_do_setxattr(OVL_FS(inode->i_sb), ovl_dentry_upper(dentry),
			       OVL_XATTR_NLINK, buf, len);
}

@@ -736,7 +736,7 @@ int ovl_set_nlink_lower(struct dentry *dentry)
	return ovl_set_nlink_common(dentry, ovl_dentry_lower(dentry), "L%+i");
}

unsigned int ovl_get_nlink(struct dentry *lowerdentry,
unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry,
			   struct dentry *upperdentry,
			   unsigned int fallback)
{
@@ -748,7 +748,7 @@ unsigned int ovl_get_nlink(struct dentry *lowerdentry,
	if (!lowerdentry || !upperdentry || d_inode(lowerdentry)->i_nlink == 1)
		return fallback;

	err = ovl_do_getxattr(upperdentry, OVL_XATTR_NLINK,
	err = ovl_do_getxattr(ofs, upperdentry, OVL_XATTR_NLINK,
			      &buf, sizeof(buf) - 1);
	if (err < 0)
		goto fail;
@@ -947,6 +947,7 @@ static struct inode *ovl_iget5(struct super_block *sb, struct inode *newinode,
struct inode *ovl_get_inode(struct super_block *sb,
			    struct ovl_inode_params *oip)
{
	struct ovl_fs *ofs = OVL_FS(sb);
	struct dentry *upperdentry = oip->upperdentry;
	struct ovl_path *lowerpath = oip->lowerpath;
	struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL;
@@ -994,7 +995,8 @@ struct inode *ovl_get_inode(struct super_block *sb,

		/* Recalculate nlink for non-dir due to indexing */
		if (!is_dir)
			nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink);
			nlink = ovl_get_nlink(ofs, lowerdentry, upperdentry,
					      nlink);
		set_nlink(inode, nlink);
		ino = key->i_ino;
	} else {
@@ -1010,7 +1012,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
	ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
	ovl_inode_init(inode, oip, ino, fsid);

	if (upperdentry && ovl_is_impuredir(upperdentry))
	if (upperdentry && ovl_is_impuredir(sb, upperdentry))
		ovl_set_flag(OVL_IMPURE, inode);

	if (oip->index)
@@ -1024,7 +1026,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
	/* Check for non-merge dir that may have whiteouts */
	if (is_dir) {
		if (((upperdentry && lowerdentry) || oip->numlower > 1) ||
		    ovl_check_origin_xattr(upperdentry ?: lowerdentry)) {
		    ovl_check_origin_xattr(ofs, upperdentry ?: lowerdentry)) {
			ovl_set_flag(OVL_WHITEOUTS, inode);
		}
	}
+30 −27
Original line number Diff line number Diff line
@@ -30,8 +30,9 @@ static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d,
{
	int res;
	char *buf;
	struct ovl_fs *ofs = OVL_FS(d->sb);

	buf = ovl_get_redirect_xattr(dentry, prelen + strlen(post));
	buf = ovl_get_redirect_xattr(ofs, dentry, prelen + strlen(post));
	if (IS_ERR_OR_NULL(buf))
		return PTR_ERR(buf);

@@ -104,12 +105,13 @@ int ovl_check_fb_len(struct ovl_fb *fb, int fb_len)
	return 0;
}

static struct ovl_fh *ovl_get_fh(struct dentry *dentry, const char *name)
static struct ovl_fh *ovl_get_fh(struct ovl_fs *ofs, struct dentry *dentry,
				 const char *name)
{
	int res, err;
	struct ovl_fh *fh = NULL;

	res = ovl_do_getxattr(dentry, name, NULL, 0);
	res = ovl_do_getxattr(ofs, dentry, name, NULL, 0);
	if (res < 0) {
		if (res == -ENODATA || res == -EOPNOTSUPP)
			return NULL;
@@ -123,7 +125,7 @@ static struct ovl_fh *ovl_get_fh(struct dentry *dentry, const char *name)
	if (!fh)
		return ERR_PTR(-ENOMEM);

	res = ovl_do_getxattr(dentry, name, fh->buf, res);
	res = ovl_do_getxattr(ofs, dentry, name, fh->buf, res);
	if (res < 0)
		goto fail;

@@ -186,9 +188,9 @@ struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt,
	return real;
}

static bool ovl_is_opaquedir(struct dentry *dentry)
static bool ovl_is_opaquedir(struct super_block *sb, struct dentry *dentry)
{
	return ovl_check_dir_xattr(dentry, OVL_XATTR_OPAQUE);
	return ovl_check_dir_xattr(sb, dentry, OVL_XATTR_OPAQUE);
}

static struct dentry *ovl_lookup_positive_unlocked(const char *name,
@@ -251,7 +253,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
			d->stop = true;
			goto put_and_out;
		}
		err = ovl_check_metacopy_xattr(this);
		err = ovl_check_metacopy_xattr(OVL_FS(d->sb), this);
		if (err < 0)
			goto out_err;

@@ -271,7 +273,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
		if (d->last)
			goto out;

		if (ovl_is_opaquedir(this)) {
		if (ovl_is_opaquedir(d->sb, this)) {
			d->stop = true;
			if (last_element)
				d->opaque = true;
@@ -391,7 +393,7 @@ invalid:
static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry,
			    struct ovl_path **stackp)
{
	struct ovl_fh *fh = ovl_get_fh(upperdentry, OVL_XATTR_ORIGIN);
	struct ovl_fh *fh = ovl_get_fh(ofs, upperdentry, OVL_XATTR_ORIGIN);
	int err;

	if (IS_ERR_OR_NULL(fh))
@@ -413,10 +415,10 @@ static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry,
 * Verify that @fh matches the file handle stored in xattr @name.
 * Return 0 on match, -ESTALE on mismatch, < 0 on error.
 */
static int ovl_verify_fh(struct dentry *dentry, const char *name,
			 const struct ovl_fh *fh)
static int ovl_verify_fh(struct ovl_fs *ofs, struct dentry *dentry,
			 const char *name, const struct ovl_fh *fh)
{
	struct ovl_fh *ofh = ovl_get_fh(dentry, name);
	struct ovl_fh *ofh = ovl_get_fh(ofs, dentry, name);
	int err = 0;

	if (!ofh)
@@ -440,8 +442,9 @@ static int ovl_verify_fh(struct dentry *dentry, const char *name,
 *
 * Return 0 on match, -ESTALE on mismatch, -ENODATA on no xattr, < 0 on error.
 */
int ovl_verify_set_fh(struct dentry *dentry, const char *name,
		      struct dentry *real, bool is_upper, bool set)
int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
		      const char *name, struct dentry *real, bool is_upper,
		      bool set)
{
	struct inode *inode;
	struct ovl_fh *fh;
@@ -454,9 +457,9 @@ int ovl_verify_set_fh(struct dentry *dentry, const char *name,
		goto fail;
	}

	err = ovl_verify_fh(dentry, name, fh);
	err = ovl_verify_fh(ofs, dentry, name, fh);
	if (set && err == -ENODATA)
		err = ovl_do_setxattr(dentry, name, fh->buf, fh->fb.len);
		err = ovl_do_setxattr(ofs, dentry, name, fh->buf, fh->fb.len);
	if (err)
		goto fail;

@@ -481,7 +484,7 @@ struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index)
	if (!d_is_dir(index))
		return dget(index);

	fh = ovl_get_fh(index, OVL_XATTR_UPPER);
	fh = ovl_get_fh(ofs, index, OVL_XATTR_UPPER);
	if (IS_ERR_OR_NULL(fh))
		return ERR_CAST(fh);

@@ -574,7 +577,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
		goto fail;
	}

	err = ovl_verify_fh(upper, OVL_XATTR_ORIGIN, fh);
	err = ovl_verify_fh(ofs, upper, OVL_XATTR_ORIGIN, fh);
	dput(upper);
	if (err)
		goto fail;
@@ -585,7 +588,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
		if (err)
			goto fail;

		if (ovl_get_nlink(origin.dentry, index, 0) == 0)
		if (ovl_get_nlink(ofs, origin.dentry, index, 0) == 0)
			goto orphan;
	}

@@ -741,7 +744,7 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
		}

		/* Verify that dir index 'upper' xattr points to upper dir */
		err = ovl_verify_upper(index, upper, false);
		err = ovl_verify_upper(ofs, index, upper, false);
		if (err) {
			if (err == -ESTALE) {
				pr_warn_ratelimited("suspected multiply redirected dir found (upper=%pd2, origin=%pd2, index=%pd2).\n",
@@ -790,12 +793,12 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path)
}

/* Fix missing 'origin' xattr */
static int ovl_fix_origin(struct dentry *dentry, struct dentry *lower,
			  struct dentry *upper)
static int ovl_fix_origin(struct ovl_fs *ofs, struct dentry *dentry,
			  struct dentry *lower, struct dentry *upper)
{
	int err;

	if (ovl_check_origin_xattr(upper))
	if (ovl_check_origin_xattr(ofs, upper))
		return 0;

	err = ovl_want_write(dentry);
@@ -920,7 +923,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
		 * of lower dir and set upper parent "impure".
		 */
		if (upperdentry && !ctr && !ofs->noxattr && d.is_dir) {
			err = ovl_fix_origin(dentry, this, upperdentry);
			err = ovl_fix_origin(ofs, dentry, this, upperdentry);
			if (err) {
				dput(this);
				goto out_put;
@@ -939,7 +942,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
		if (upperdentry && !ctr &&
		    ((d.is_dir && ovl_verify_lower(dentry->d_sb)) ||
		     (!d.is_dir && ofs->config.index && origin_path))) {
			err = ovl_verify_origin(upperdentry, this, false);
			err = ovl_verify_origin(ofs, upperdentry, this, false);
			if (err) {
				dput(this);
				if (d.is_dir)
@@ -1060,13 +1063,13 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
		ovl_dentry_set_upper_alias(dentry);
	else if (index) {
		upperdentry = dget(index);
		upperredirect = ovl_get_redirect_xattr(upperdentry, 0);
		upperredirect = ovl_get_redirect_xattr(ofs, upperdentry, 0);
		if (IS_ERR(upperredirect)) {
			err = PTR_ERR(upperredirect);
			upperredirect = NULL;
			goto out_free_oe;
		}
		err = ovl_check_metacopy_xattr(upperdentry);
		err = ovl_check_metacopy_xattr(ofs, upperdentry);
		if (err < 0)
			goto out_free_oe;
		uppermetacopy = err;
Loading