Commit 116cc0225381415b96551f725455d067f63a76a0
Committed by
Al Viro
1 parent
01c919abaf
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
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
fs/namei.c
... | ... | @@ -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; |