diff options
author | Eric Biggers <ebiggers@google.com> | 2020-11-17 23:56:05 -0800 |
---|---|---|
committer | Eric Biggers <ebiggers@google.com> | 2020-11-24 15:10:27 -0800 |
commit | 159e1de201b6fca10bfec50405a3b53a561096a8 (patch) | |
tree | c2800ad873c8238a3017413f67e910a47f726875 /fs/crypto/hooks.c | |
parent | 3ceb6543e9cf6ed87cc1fbc6f23ca2db903564cd (diff) | |
download | lwn-159e1de201b6fca10bfec50405a3b53a561096a8.tar.gz lwn-159e1de201b6fca10bfec50405a3b53a561096a8.zip |
fscrypt: add fscrypt_is_nokey_name()
It's possible to create a duplicate filename in an encrypted directory
by creating a file concurrently with adding the encryption key.
Specifically, sys_open(O_CREAT) (or sys_mkdir(), sys_mknod(), or
sys_symlink()) can lookup the target filename while the directory's
encryption key hasn't been added yet, resulting in a negative no-key
dentry. The VFS then calls ->create() (or ->mkdir(), ->mknod(), or
->symlink()) because the dentry is negative. Normally, ->create() would
return -ENOKEY due to the directory's key being unavailable. However,
if the key was added between the dentry lookup and ->create(), then the
filesystem will go ahead and try to create the file.
If the target filename happens to already exist as a normal name (not a
no-key name), a duplicate filename may be added to the directory.
In order to fix this, we need to fix the filesystems to prevent
->create(), ->mkdir(), ->mknod(), and ->symlink() on no-key names.
(->rename() and ->link() need it too, but those are already handled
correctly by fscrypt_prepare_rename() and fscrypt_prepare_link().)
In preparation for this, add a helper function fscrypt_is_nokey_name()
that filesystems can use to do this check. Use this helper function for
the existing checks that fs/crypto/ does for rename and link.
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20201118075609.120337-2-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
Diffstat (limited to 'fs/crypto/hooks.c')
-rw-r--r-- | fs/crypto/hooks.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index 20b0df47fe6a..061418be4b08 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -61,7 +61,7 @@ int __fscrypt_prepare_link(struct inode *inode, struct inode *dir, return err; /* ... in case we looked up no-key name before key was added */ - if (dentry->d_flags & DCACHE_NOKEY_NAME) + if (fscrypt_is_nokey_name(dentry)) return -ENOKEY; if (!fscrypt_has_permitted_context(dir, inode)) @@ -86,7 +86,8 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry, return err; /* ... in case we looked up no-key name(s) before key was added */ - if ((old_dentry->d_flags | new_dentry->d_flags) & DCACHE_NOKEY_NAME) + if (fscrypt_is_nokey_name(old_dentry) || + fscrypt_is_nokey_name(new_dentry)) return -ENOKEY; if (old_dir != new_dir) { |