diff mbox series

[SRU,UNSTABLE/BIONIC/XENIAL] UBUNTU: SAUCE: shiftfs: remove custom tmpfile method

Message ID 20200414201737.173672-1-christian.brauner@ubuntu.com
State New
Headers show
Series [SRU,UNSTABLE/BIONIC/XENIAL] UBUNTU: SAUCE: shiftfs: remove custom tmpfile method | expand

Commit Message

Christian Brauner April 14, 2020, 8:17 p.m. UTC
BugLink: https://bugs.launchpad.net/bugs/1872757

Our revalidate methods were very opinionated about whether or not a
dentry was valid when we really should've just let the underlay tell us
what's what. This has led to bugs where a ESTALE was returned for e.g.
temporary files that were created and directly re-opened afterwards
through /proc/<pid>/fd/<nr-of-deleted-file>. When a file is re-opened
through /proc/<pid>/fd/<nr> LOOKUP_JUMP is set and the vfs will
revalidate via d_weak_revalidate(). Since the file has been unhashed or
even already gone negative we'd fail the open when we should've
succeeded.

I had also foolishly provided a .tmpfile method which so far only has
caused us trouble and which was involved in the ESTALE problem. If we
really need this then we can reimplement it properly but I doubt it.
Remove it for now.

Reported-by: Christian Kellner <ckellner@redhat.com>
Reported-by: Evgeny Vereshchagin >evvers@ya.ru>
Cc: Seth Forshee <seth.forshee@canonical.com>
Link: https://github.com/systemd/systemd/issues/14861
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
---
 fs/shiftfs.c | 45 +++++++++++++--------------------------------
 1 file changed, 13 insertions(+), 32 deletions(-)


base-commit: 1ff0ece4a5b555e1a72ec8d030b9410761174598

Comments

Kamal Mostafa April 23, 2020, 6:09 p.m. UTC | #1
Acked-by: Kamal Mostafa <kamal@canonical.com>

 -Kamal

On Tue, Apr 14, 2020 at 10:17:37PM +0200, Christian Brauner wrote:
> BugLink: https://bugs.launchpad.net/bugs/1872757
> 
> Our revalidate methods were very opinionated about whether or not a
> dentry was valid when we really should've just let the underlay tell us
> what's what. This has led to bugs where a ESTALE was returned for e.g.
> temporary files that were created and directly re-opened afterwards
> through /proc/<pid>/fd/<nr-of-deleted-file>. When a file is re-opened
> through /proc/<pid>/fd/<nr> LOOKUP_JUMP is set and the vfs will
> revalidate via d_weak_revalidate(). Since the file has been unhashed or
> even already gone negative we'd fail the open when we should've
> succeeded.
> 
> I had also foolishly provided a .tmpfile method which so far only has
> caused us trouble and which was involved in the ESTALE problem. If we
> really need this then we can reimplement it properly but I doubt it.
> Remove it for now.
> 
> Reported-by: Christian Kellner <ckellner@redhat.com>
> Reported-by: Evgeny Vereshchagin >evvers@ya.ru>
> Cc: Seth Forshee <seth.forshee@canonical.com>
> Link: https://github.com/systemd/systemd/issues/14861
> Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
> ---
>  fs/shiftfs.c | 45 +++++++++++++--------------------------------
>  1 file changed, 13 insertions(+), 32 deletions(-)
> 
> diff --git a/fs/shiftfs.c b/fs/shiftfs.c
> index 5c39529d0a17..39b878a6f820 100644
> --- a/fs/shiftfs.c
> +++ b/fs/shiftfs.c
> @@ -240,19 +240,17 @@ static int shiftfs_d_weak_revalidate(struct dentry *dentry, unsigned int flags)
>  	int err = 1;
>  	struct dentry *lowerd = dentry->d_fsdata;
>  
> -	if (d_is_negative(lowerd) != d_is_negative(dentry))
> -		return 0;
> -
> -	if ((lowerd->d_flags & DCACHE_OP_WEAK_REVALIDATE))
> +	if (lowerd->d_flags & DCACHE_OP_WEAK_REVALIDATE) {
>  		err = lowerd->d_op->d_weak_revalidate(lowerd, flags);
> +		if (err < 0)
> +			return err;
> +	}
>  
>  	if (d_really_is_positive(dentry)) {
>  		struct inode *inode = d_inode(dentry);
>  		struct inode *loweri = d_inode(lowerd);
>  
>  		shiftfs_copyattr(loweri, inode);
> -		if (!inode->i_nlink)
> -			err = 0;
>  	}
>  
>  	return err;
> @@ -263,23 +261,25 @@ static int shiftfs_d_revalidate(struct dentry *dentry, unsigned int flags)
>  	int err = 1;
>  	struct dentry *lowerd = dentry->d_fsdata;
>  
> -	if (d_unhashed(lowerd) ||
> -	    ((d_is_negative(lowerd) != d_is_negative(dentry))))
> -		return 0;
> -
>  	if (flags & LOOKUP_RCU)
>  		return -ECHILD;
>  
> -	if ((lowerd->d_flags & DCACHE_OP_REVALIDATE))
> +	if (lowerd->d_flags & DCACHE_OP_REVALIDATE) {
>  		err = lowerd->d_op->d_revalidate(lowerd, flags);
> +		if (err < 0)
> +			return err;
> +		if (!err) {
> +			if (!(flags & LOOKUP_RCU))
> +				d_invalidate(lowerd);
> +			return -ESTALE;
> +		}
> +	}
>  
>  	if (d_really_is_positive(dentry)) {
>  		struct inode *inode = d_inode(dentry);
>  		struct inode *loweri = d_inode(lowerd);
>  
>  		shiftfs_copyattr(loweri, inode);
> -		if (!inode->i_nlink)
> -			err = 0;
>  	}
>  
>  	return err;
> @@ -736,24 +736,6 @@ static int shiftfs_fiemap(struct inode *inode,
>  	return err;
>  }
>  
> -static int shiftfs_tmpfile(struct inode *dir, struct dentry *dentry,
> -			   umode_t mode)
> -{
> -	int err;
> -	const struct cred *oldcred;
> -	struct dentry *lowerd = dentry->d_fsdata;
> -	struct inode *loweri = dir->i_private;
> -
> -	if (!loweri->i_op->tmpfile)
> -		return -EOPNOTSUPP;
> -
> -	oldcred = shiftfs_override_creds(dir->i_sb);
> -	err = loweri->i_op->tmpfile(loweri, lowerd, mode);
> -	revert_creds(oldcred);
> -
> -	return err;
> -}
> -
>  static int shiftfs_setattr(struct dentry *dentry, struct iattr *attr)
>  {
>  	struct dentry *lowerd = dentry->d_fsdata;
> @@ -1020,7 +1002,6 @@ static const struct inode_operations shiftfs_file_inode_operations = {
>  	.listxattr	= shiftfs_listxattr,
>  	.permission	= shiftfs_permission,
>  	.setattr	= shiftfs_setattr,
> -	.tmpfile	= shiftfs_tmpfile,
>  };
>  
>  static const struct inode_operations shiftfs_special_inode_operations = {
> 
> base-commit: 1ff0ece4a5b555e1a72ec8d030b9410761174598
> -- 
> 2.26.0
> 
> 
> -- 
> kernel-team mailing list
> kernel-team@lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
Seth Forshee May 2, 2020, 1:59 a.m. UTC | #2
On Tue, Apr 14, 2020 at 10:17:37PM +0200, Christian Brauner wrote:
> BugLink: https://bugs.launchpad.net/bugs/1872757
> 
> Our revalidate methods were very opinionated about whether or not a
> dentry was valid when we really should've just let the underlay tell us
> what's what. This has led to bugs where a ESTALE was returned for e.g.
> temporary files that were created and directly re-opened afterwards
> through /proc/<pid>/fd/<nr-of-deleted-file>. When a file is re-opened
> through /proc/<pid>/fd/<nr> LOOKUP_JUMP is set and the vfs will
> revalidate via d_weak_revalidate(). Since the file has been unhashed or
> even already gone negative we'd fail the open when we should've
> succeeded.
> 
> I had also foolishly provided a .tmpfile method which so far only has
> caused us trouble and which was involved in the ESTALE problem. If we
> really need this then we can reimplement it properly but I doubt it.
> Remove it for now.
> 
> Reported-by: Christian Kellner <ckellner@redhat.com>
> Reported-by: Evgeny Vereshchagin >evvers@ya.ru>
> Cc: Seth Forshee <seth.forshee@canonical.com>
> Link: https://github.com/systemd/systemd/issues/14861
> Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>

Applied to unstable/master, thanks!
Seth Forshee May 2, 2020, 2 a.m. UTC | #3
On Fri, May 01, 2020 at 08:59:17PM -0500, Seth Forshee wrote:
> On Tue, Apr 14, 2020 at 10:17:37PM +0200, Christian Brauner wrote:
> > BugLink: https://bugs.launchpad.net/bugs/1872757
> > 
> > Our revalidate methods were very opinionated about whether or not a
> > dentry was valid when we really should've just let the underlay tell us
> > what's what. This has led to bugs where a ESTALE was returned for e.g.
> > temporary files that were created and directly re-opened afterwards
> > through /proc/<pid>/fd/<nr-of-deleted-file>. When a file is re-opened
> > through /proc/<pid>/fd/<nr> LOOKUP_JUMP is set and the vfs will
> > revalidate via d_weak_revalidate(). Since the file has been unhashed or
> > even already gone negative we'd fail the open when we should've
> > succeeded.
> > 
> > I had also foolishly provided a .tmpfile method which so far only has
> > caused us trouble and which was involved in the ESTALE problem. If we
> > really need this then we can reimplement it properly but I doubt it.
> > Remove it for now.
> > 
> > Reported-by: Christian Kellner <ckellner@redhat.com>
> > Reported-by: Evgeny Vereshchagin >evvers@ya.ru>
> > Cc: Seth Forshee <seth.forshee@canonical.com>
> > Link: https://github.com/systemd/systemd/issues/14861
> > Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
> 
> Applied to unstable/master, thanks!

Oops, replied to the wrong message. The one I actually applied was
"UBUNTU: SAUCE: shiftfs: fix dentry revalidation."
diff mbox series

Patch

diff --git a/fs/shiftfs.c b/fs/shiftfs.c
index 5c39529d0a17..39b878a6f820 100644
--- a/fs/shiftfs.c
+++ b/fs/shiftfs.c
@@ -240,19 +240,17 @@  static int shiftfs_d_weak_revalidate(struct dentry *dentry, unsigned int flags)
 	int err = 1;
 	struct dentry *lowerd = dentry->d_fsdata;
 
-	if (d_is_negative(lowerd) != d_is_negative(dentry))
-		return 0;
-
-	if ((lowerd->d_flags & DCACHE_OP_WEAK_REVALIDATE))
+	if (lowerd->d_flags & DCACHE_OP_WEAK_REVALIDATE) {
 		err = lowerd->d_op->d_weak_revalidate(lowerd, flags);
+		if (err < 0)
+			return err;
+	}
 
 	if (d_really_is_positive(dentry)) {
 		struct inode *inode = d_inode(dentry);
 		struct inode *loweri = d_inode(lowerd);
 
 		shiftfs_copyattr(loweri, inode);
-		if (!inode->i_nlink)
-			err = 0;
 	}
 
 	return err;
@@ -263,23 +261,25 @@  static int shiftfs_d_revalidate(struct dentry *dentry, unsigned int flags)
 	int err = 1;
 	struct dentry *lowerd = dentry->d_fsdata;
 
-	if (d_unhashed(lowerd) ||
-	    ((d_is_negative(lowerd) != d_is_negative(dentry))))
-		return 0;
-
 	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
-	if ((lowerd->d_flags & DCACHE_OP_REVALIDATE))
+	if (lowerd->d_flags & DCACHE_OP_REVALIDATE) {
 		err = lowerd->d_op->d_revalidate(lowerd, flags);
+		if (err < 0)
+			return err;
+		if (!err) {
+			if (!(flags & LOOKUP_RCU))
+				d_invalidate(lowerd);
+			return -ESTALE;
+		}
+	}
 
 	if (d_really_is_positive(dentry)) {
 		struct inode *inode = d_inode(dentry);
 		struct inode *loweri = d_inode(lowerd);
 
 		shiftfs_copyattr(loweri, inode);
-		if (!inode->i_nlink)
-			err = 0;
 	}
 
 	return err;
@@ -736,24 +736,6 @@  static int shiftfs_fiemap(struct inode *inode,
 	return err;
 }
 
-static int shiftfs_tmpfile(struct inode *dir, struct dentry *dentry,
-			   umode_t mode)
-{
-	int err;
-	const struct cred *oldcred;
-	struct dentry *lowerd = dentry->d_fsdata;
-	struct inode *loweri = dir->i_private;
-
-	if (!loweri->i_op->tmpfile)
-		return -EOPNOTSUPP;
-
-	oldcred = shiftfs_override_creds(dir->i_sb);
-	err = loweri->i_op->tmpfile(loweri, lowerd, mode);
-	revert_creds(oldcred);
-
-	return err;
-}
-
 static int shiftfs_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	struct dentry *lowerd = dentry->d_fsdata;
@@ -1020,7 +1002,6 @@  static const struct inode_operations shiftfs_file_inode_operations = {
 	.listxattr	= shiftfs_listxattr,
 	.permission	= shiftfs_permission,
 	.setattr	= shiftfs_setattr,
-	.tmpfile	= shiftfs_tmpfile,
 };
 
 static const struct inode_operations shiftfs_special_inode_operations = {