linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] fs/vfs: Release allocated dentry on failure in do_last()
@ 2017-12-07  2:46 穆阿浩(姜弋)
  2017-12-07  5:30 ` Matthew Wilcox
  2017-12-07 12:39 ` Al Viro
  0 siblings, 2 replies; 5+ messages in thread
From: 穆阿浩(姜弋) @ 2017-12-07  2:46 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: viro, 渡波,
	穆阿浩(姜弋),
	张礼广(乱石)

This issue is found when creating /dev/sdtest with flags (O_CREAT |
O_DIRECT). The file still can be retrieved even after system reports
failure (-EINVAL) for it. Reporting error on creating the file is
correct behaviour because either devtmpfs or tmpfs doesn't support
O_DIRECT for regular file. However, it's incorrect that the file is
still existing. The cause is the newly allocated dentry and inode
aren't released on failure in do_last().

   # rm /dev/sdtest
   # dd if=/dev/urandom of=/dev/sdtest bs=4k count=1 oflag=direct
     <-EINVAL is returned>
   # ls /dev/sdtest
     <File is still existing>

This fixes the issue by releasing the dentry, thus the inode on failure
in do_last(). With this applied, the file (/dev/sdtest) isn't seen
in this scenario.

Reported-by: YouYou <youyou.wy.huang@foxconn.com>
Signed-off-by: Gavin Shan <dubo.sgw@alibaba-inc.com>
Signed-off-by: Liguang Zhang <liguang.zlg@alibaba-inc.com>
Signed-off-by: Ahao Mu <ahao.mah@alibaba-inc.com>
---
 fs/namei.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/namei.c b/fs/namei.c
index 9cc91fb..607c357 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3382,6 +3382,8 @@ static int do_last(struct nameidata *nd,
 	*opened |= FILE_OPENED;
 opened:
 	error = open_check_o_direct(file);
+	if (error && (*opened & FILE_OPENED))
+		dput(path.dentry);
 	if (!error)
 		error = ima_file_check(file, op->acc_mode, *opened);
 	if (!error && will_truncate)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] fs/vfs: Release allocated dentry on failure in do_last()
  2017-12-07  2:46 [PATCH] fs/vfs: Release allocated dentry on failure in do_last() 穆阿浩(姜弋)
@ 2017-12-07  5:30 ` Matthew Wilcox
  2017-12-08  3:14   ` 渡波
  2017-12-07 12:39 ` Al Viro
  1 sibling, 1 reply; 5+ messages in thread
From: Matthew Wilcox @ 2017-12-07  5:30 UTC (permalink / raw)
  To: 穆阿浩(姜弋)
  Cc: linux-fsdevel, viro, 渡波,
	张礼广(乱石)

On Thu, Dec 07, 2017 at 10:46:22AM +0800, 穆阿浩(姜弋) wrote:
> This issue is found when creating /dev/sdtest with flags (O_CREAT |
> O_DIRECT). The file still can be retrieved even after system reports
> failure (-EINVAL) for it. Reporting error on creating the file is
> correct behaviour because either devtmpfs or tmpfs doesn't support
> O_DIRECT for regular file. However, it's incorrect that the file is
> still existing. The cause is the newly allocated dentry and inode
> aren't released on failure in do_last().

Previously reported:

https://www.spinics.net/lists/linux-fsdevel/msg89317.html
https://www.spinics.net/lists/linux-fsdevel/msg113680.html
http://lkml.iu.edu/hypermail/linux/kernel/1609.0/04556.html

> +++ b/fs/namei.c
> @@ -3382,6 +3382,8 @@ static int do_last(struct nameidata *nd,
>  	*opened |= FILE_OPENED;
>  opened:
>  	error = open_check_o_direct(file);
> +	if (error && (*opened & FILE_OPENED))
> +		dput(path.dentry);
>  	if (!error)
>  		error = ima_file_check(file, op->acc_mode, *opened);
>  	if (!error && will_truncate)

Umm ... I think it's too late.  This will work well enough for in-memory
filesystems, but if you have a real filesystem, there's no call back to
the filesystem to remove the directory entry, right?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] fs/vfs: Release allocated dentry on failure in do_last()
  2017-12-07  2:46 [PATCH] fs/vfs: Release allocated dentry on failure in do_last() 穆阿浩(姜弋)
  2017-12-07  5:30 ` Matthew Wilcox
@ 2017-12-07 12:39 ` Al Viro
  2017-12-08  3:11   ` 渡波
  1 sibling, 1 reply; 5+ messages in thread
From: Al Viro @ 2017-12-07 12:39 UTC (permalink / raw)
  To: 穆阿浩(姜弋)
  Cc: linux-fsdevel, 渡波,
	张礼广(乱石)

On Thu, Dec 07, 2017 at 10:46:22AM +0800, 穆阿浩(姜弋) wrote:
> This issue is found when creating /dev/sdtest with flags (O_CREAT |
> O_DIRECT). The file still can be retrieved even after system reports
> failure (-EINVAL) for it. Reporting error on creating the file is
> correct behaviour because either devtmpfs or tmpfs doesn't support
> O_DIRECT for regular file. However, it's incorrect that the file is
> still existing. The cause is the newly allocated dentry and inode
> aren't released on failure in do_last().

>    # rm /dev/sdtest
>    # dd if=/dev/urandom of=/dev/sdtest bs=4k count=1 oflag=direct
>      <-EINVAL is returned>
>    # ls /dev/sdtest
>      <File is still existing>
> 
> This fixes the issue by releasing the dentry, thus the inode on failure
> in do_last(). With this applied, the file (/dev/sdtest) isn't seen
> in this scenario.

> +	if (error && (*opened & FILE_OPENED))
> +		dput(path.dentry);

NAK.  For one thing, it's racy as hell even on tmpfs - plain open()
from another process would've succeeded in that window.  For another,
it's outright exploitable on filesystems where dentry tree does not
contain all the existing directory tree (anything disk-based, for
starters).

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] fs/vfs: Release allocated dentry on failure in do_last()
  2017-12-07 12:39 ` Al Viro
@ 2017-12-08  3:11   ` 渡波
  0 siblings, 0 replies; 5+ messages in thread
From: 渡波 @ 2017-12-08  3:11 UTC (permalink / raw)
  To: Al Viro
  Cc: 穆阿浩(姜弋), linux-fsdevel,
	张礼广(乱石)

On Thu, Dec 07, 2017 at 08:39:37PM +0800, Al Viro wrote:
> On Thu, Dec 07, 2017 at 10:46:22AM +0800, 锟铰帮拷锟斤拷(锟斤拷弋) wrote:
> > This issue is found when creating /dev/sdtest with flags (O_CREAT |
> > O_DIRECT). The file still can be retrieved even after system reports
> > failure (-EINVAL) for it. Reporting error on creating the file is
> > correct behaviour because either devtmpfs or tmpfs doesn't support
> > O_DIRECT for regular file. However, it's incorrect that the file is
> > still existing. The cause is the newly allocated dentry and inode
> > aren't released on failure in do_last().
> 
> >    # rm /dev/sdtest
> >    # dd if=/dev/urandom of=/dev/sdtest bs=4k count=1 oflag=direct
> >      <-EINVAL is returned>
> >    # ls /dev/sdtest
> >      <File is still existing>
> > 
> > This fixes the issue by releasing the dentry, thus the inode on failure
> > in do_last(). With this applied, the file (/dev/sdtest) isn't seen
> > in this scenario.
> 
> > +	if (error && (*opened & FILE_OPENED))
> > +		dput(path.dentry);
> 
> NAK.  For one thing, it's racy as hell even on tmpfs - plain open()
> from another process would've succeeded in that window.  For another,
> it's outright exploitable on filesystems where dentry tree does not
> contain all the existing directory tree (anything disk-based, for
> starters).

Al, thanks for your reply. Another approach would be passing the flag
O_DIRECT to struct inode_operations::create(). The specific filesystem
rejects to create the inode if O_DIRECT isn't supported there. I can
send patches for review if you think it's reasonable.

Cheers,
Gavin

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] fs/vfs: Release allocated dentry on failure in do_last()
  2017-12-07  5:30 ` Matthew Wilcox
@ 2017-12-08  3:14   ` 渡波
  0 siblings, 0 replies; 5+ messages in thread
From: 渡波 @ 2017-12-08  3:14 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: 穆阿浩(姜弋), linux-fsdevel, viro,
	张礼广(乱石)

On Thu, Dec 07, 2017 at 01:30:03PM +0800, Matthew Wilcox wrote:
> On Thu, Dec 07, 2017 at 10:46:22AM +0800, 锟铰帮拷锟斤拷(锟斤拷弋) wrote:
> > This issue is found when creating /dev/sdtest with flags (O_CREAT |
> > O_DIRECT). The file still can be retrieved even after system reports
> > failure (-EINVAL) for it. Reporting error on creating the file is
> > correct behaviour because either devtmpfs or tmpfs doesn't support
> > O_DIRECT for regular file. However, it's incorrect that the file is
> > still existing. The cause is the newly allocated dentry and inode
> > aren't released on failure in do_last().
> 
> Previously reported:
> 
> https://www.spinics.net/lists/linux-fsdevel/msg89317.html
> https://www.spinics.net/lists/linux-fsdevel/msg113680.html
> http://lkml.iu.edu/hypermail/linux/kernel/1609.0/04556.html
> 

Thanks, Matthew. I start to realize it's a long-standing issue :)

> > +++ b/fs/namei.c
> > @@ -3382,6 +3382,8 @@ static int do_last(struct nameidata *nd,
> >  	*opened |= FILE_OPENED;
> >  opened:
> >  	error = open_check_o_direct(file);
> > +	if (error && (*opened & FILE_OPENED))
> > +		dput(path.dentry);
> >  	if (!error)
> >  		error = ima_file_check(file, op->acc_mode, *opened);
> >  	if (!error && will_truncate)
> 
> Umm ... I think it's too late.  This will work well enough for in-memory
> filesystems, but if you have a real filesystem, there's no call back to
> the filesystem to remove the directory entry, right?

Yeah, it's late to roll back on real filesystem like ext4. As I replied
to Al Viro in another thread, the doable fix would be pass O_DIRECT down
to struct inode_operations::create() and the specific filesystem rejects
creating inode if O_DIRECT isn't supported there.

Cheers,
Gavin

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-12-08  3:14 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-12-07  2:46 [PATCH] fs/vfs: Release allocated dentry on failure in do_last() 穆阿浩(姜弋)
2017-12-07  5:30 ` Matthew Wilcox
2017-12-08  3:14   ` 渡波
2017-12-07 12:39 ` Al Viro
2017-12-08  3:11   ` 渡波

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).