aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2013-09-16 08:52:05 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-09-16 19:17:24 -0400
commit116cc0225381415b96551f725455d067f63a76a0 (patch)
treeb30640ef8f0c7ef1b412d08f50f3ab28f69e5127 /fs/namei.c
parent01c919abaf2f3d6a8e59eddf4ee22df1631ab067 (diff)
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>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 0dc4cbf21f37..22eb5484774c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2656,6 +2656,7 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
2656 int acc_mode; 2656 int acc_mode;
2657 int create_error = 0; 2657 int create_error = 0;
2658 struct dentry *const DENTRY_NOT_SET = (void *) -1UL; 2658 struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
2659 bool excl;
2659 2660
2660 BUG_ON(dentry->d_inode); 2661 BUG_ON(dentry->d_inode);
2661 2662
@@ -2669,10 +2670,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
2669 if ((open_flag & O_CREAT) && !IS_POSIXACL(dir)) 2670 if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
2670 mode &= ~current_umask(); 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 open_flag &= ~O_TRUNC; 2675 open_flag &= ~O_TRUNC;
2674 *opened |= FILE_CREATED;
2675 }
2676 2676
2677 /* 2677 /*
2678 * Checking write permission is tricky, bacuse we don't know if we are 2678 * Checking write permission is tricky, bacuse we don't know if we are
@@ -2726,7 +2726,11 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
2726 } 2726 }
2727 2727
2728 acc_mode = op->acc_mode; 2728 acc_mode = op->acc_mode;
2729 if (WARN_ON(excl && !(*opened & FILE_CREATED)))
2730 *opened |= FILE_CREATED;
2731
2729 if (*opened & FILE_CREATED) { 2732 if (*opened & FILE_CREATED) {
2733 WARN_ON(!(open_flag & O_CREAT));
2730 fsnotify_create(dir, dentry); 2734 fsnotify_create(dir, dentry);
2731 acc_mode = MAY_OPEN; 2735 acc_mode = MAY_OPEN;
2732 } 2736 }
@@ -2740,6 +2744,7 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
2740 dput(dentry); 2744 dput(dentry);
2741 dentry = file->f_path.dentry; 2745 dentry = file->f_path.dentry;
2742 } 2746 }
2747 WARN_ON(!dentry->d_inode && (*opened & FILE_CREATED));
2743 if (create_error && dentry->d_inode == NULL) { 2748 if (create_error && dentry->d_inode == NULL) {
2744 error = create_error; 2749 error = create_error;
2745 goto out; 2750 goto out;