fscrypt: add fscrypt_is_nokey_name()
commit 159e1de201b6fca10bfec50405a3b53a561096a8 upstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
3b7c17a814
commit
2da473e59e
@@ -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) {
|
||||
|
Reference in New Issue
Block a user