Commit 116cc0225381415b96551f725455d067f63a76a0

Authored by Miklos Szeredi
Committed by Al Viro
1 parent 01c919abaf

vfs: don't set FILE_CREATED before calling ->atomic_open()

If O_CREAT|O_EXCL are passed to open, then we know that either

 - the file is successfully created, or
 - the operation fails in some way.

So previously we set FILE_CREATED before calling ->atomic_open() so the
filesystem doesn't have to.  This, however, led to bugs in the
implementation that went unnoticed when the filesystem didn't check for
existence, yet returned success.  To prevent this kind of bug, require
filesystems to always explicitly set FILE_CREATED on O_CREAT|O_EXCL and
verify this in the VFS.

Also added a couple more verifications for the result of atomic_open():

 - Warn if filesystem set FILE_CREATED despite the lack of O_CREAT.
 - Warn if filesystem set FILE_CREATED but gave a negative dentry.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 1 changed file with 8 additions and 3 deletions Side-by-side Diff

... ... @@ -2656,6 +2656,7 @@
2656 2656 int acc_mode;
2657 2657 int create_error = 0;
2658 2658 struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
  2659 + bool excl;
2659 2660  
2660 2661 BUG_ON(dentry->d_inode);
2661 2662  
2662 2663  
... ... @@ -2669,10 +2670,9 @@
2669 2670 if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
2670 2671 mode &= ~current_umask();
2671 2672  
2672   - if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT)) {
  2673 + excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT);
  2674 + if (excl)
2673 2675 open_flag &= ~O_TRUNC;
2674   - *opened |= FILE_CREATED;
2675   - }
2676 2676  
2677 2677 /*
2678 2678 * Checking write permission is tricky, bacuse we don't know if we are
2679 2679  
... ... @@ -2726,7 +2726,11 @@
2726 2726 }
2727 2727  
2728 2728 acc_mode = op->acc_mode;
  2729 + if (WARN_ON(excl && !(*opened & FILE_CREATED)))
  2730 + *opened |= FILE_CREATED;
  2731 +
2729 2732 if (*opened & FILE_CREATED) {
  2733 + WARN_ON(!(open_flag & O_CREAT));
2730 2734 fsnotify_create(dir, dentry);
2731 2735 acc_mode = MAY_OPEN;
2732 2736 }
... ... @@ -2740,6 +2744,7 @@
2740 2744 dput(dentry);
2741 2745 dentry = file->f_path.dentry;
2742 2746 }
  2747 + WARN_ON(!dentry->d_inode && (*opened & FILE_CREATED));
2743 2748 if (create_error && dentry->d_inode == NULL) {
2744 2749 error = create_error;
2745 2750 goto out;