Переглянути джерело

ovl: lookup: do getxattr with mounter's permission

The getxattr() in ovl_is_opaquedir() was missed when converting all
operations on underlying fs to be done under mounter's permission.

This patch fixes this by moving the ovl_override_creds()/revert_creds() out
from ovl_lookup_real() to ovl_lookup().

Also convert to using vfs_getxattr() instead of directly calling
i_op->getxattr().

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Miklos Szeredi 9 роки тому
батько
коміт
2b6bc7f48d
1 змінених файлів з 9 додано та 11 видалено
  1. 9 11
      fs/overlayfs/super.c

+ 9 - 11
fs/overlayfs/super.c

@@ -273,12 +273,11 @@ static bool ovl_is_opaquedir(struct dentry *dentry)
 {
 {
 	int res;
 	int res;
 	char val;
 	char val;
-	struct inode *inode = dentry->d_inode;
 
 
-	if (!S_ISDIR(inode->i_mode) || !inode->i_op->getxattr)
+	if (!d_is_dir(dentry))
 		return false;
 		return false;
 
 
-	res = inode->i_op->getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1);
+	res = vfs_getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1);
 	if (res == 1 && val == 'y')
 	if (res == 1 && val == 'y')
 		return true;
 		return true;
 
 
@@ -419,16 +418,12 @@ static bool ovl_dentry_weird(struct dentry *dentry)
 				  DCACHE_OP_COMPARE);
 				  DCACHE_OP_COMPARE);
 }
 }
 
 
-static inline struct dentry *ovl_lookup_real(struct super_block *ovl_sb,
-					     struct dentry *dir,
+static inline struct dentry *ovl_lookup_real(struct dentry *dir,
 					     const struct qstr *name)
 					     const struct qstr *name)
 {
 {
-	const struct cred *old_cred;
 	struct dentry *dentry;
 	struct dentry *dentry;
 
 
-	old_cred = ovl_override_creds(ovl_sb);
 	dentry = lookup_one_len_unlocked(name->name, dir, name->len);
 	dentry = lookup_one_len_unlocked(name->name, dir, name->len);
-	revert_creds(old_cred);
 
 
 	if (IS_ERR(dentry)) {
 	if (IS_ERR(dentry)) {
 		if (PTR_ERR(dentry) == -ENOENT)
 		if (PTR_ERR(dentry) == -ENOENT)
@@ -469,6 +464,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 			  unsigned int flags)
 			  unsigned int flags)
 {
 {
 	struct ovl_entry *oe;
 	struct ovl_entry *oe;
+	const struct cred *old_cred;
 	struct ovl_entry *poe = dentry->d_parent->d_fsdata;
 	struct ovl_entry *poe = dentry->d_parent->d_fsdata;
 	struct path *stack = NULL;
 	struct path *stack = NULL;
 	struct dentry *upperdir, *upperdentry = NULL;
 	struct dentry *upperdir, *upperdentry = NULL;
@@ -479,9 +475,10 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 	unsigned int i;
 	unsigned int i;
 	int err;
 	int err;
 
 
+	old_cred = ovl_override_creds(dentry->d_sb);
 	upperdir = ovl_upperdentry_dereference(poe);
 	upperdir = ovl_upperdentry_dereference(poe);
 	if (upperdir) {
 	if (upperdir) {
-		this = ovl_lookup_real(dentry->d_sb, upperdir, &dentry->d_name);
+		this = ovl_lookup_real(upperdir, &dentry->d_name);
 		err = PTR_ERR(this);
 		err = PTR_ERR(this);
 		if (IS_ERR(this))
 		if (IS_ERR(this))
 			goto out;
 			goto out;
@@ -514,8 +511,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 		bool opaque = false;
 		bool opaque = false;
 		struct path lowerpath = poe->lowerstack[i];
 		struct path lowerpath = poe->lowerstack[i];
 
 
-		this = ovl_lookup_real(dentry->d_sb,
-				       lowerpath.dentry, &dentry->d_name);
+		this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name);
 		err = PTR_ERR(this);
 		err = PTR_ERR(this);
 		if (IS_ERR(this)) {
 		if (IS_ERR(this)) {
 			/*
 			/*
@@ -588,6 +584,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 		ovl_copyattr(realdentry->d_inode, inode);
 		ovl_copyattr(realdentry->d_inode, inode);
 	}
 	}
 
 
+	revert_creds(old_cred);
 	oe->opaque = upperopaque;
 	oe->opaque = upperopaque;
 	oe->__upperdentry = upperdentry;
 	oe->__upperdentry = upperdentry;
 	memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
 	memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
@@ -606,6 +603,7 @@ out_put:
 out_put_upper:
 out_put_upper:
 	dput(upperdentry);
 	dput(upperdentry);
 out:
 out:
+	revert_creds(old_cred);
 	return ERR_PTR(err);
 	return ERR_PTR(err);
 }
 }