diff options
author | Eric Biggers <ebiggers@google.com> | 2019-12-09 21:43:59 +0100 |
---|---|---|
committer | Eric Biggers <ebiggers@google.com> | 2019-12-31 17:33:50 +0100 |
commit | 2ebdef6d8c766ab7da532002091ad486f9db88ed (patch) | |
tree | e5610ff175989c9d70c6da9e13b3a41604379c7b /fs/crypto/fname.c | |
parent | fscrypt: constify inode parameter to filename encryption functions (diff) | |
download | linux-2ebdef6d8c766ab7da532002091ad486f9db88ed.tar.xz linux-2ebdef6d8c766ab7da532002091ad486f9db88ed.zip |
fscrypt: move fscrypt_d_revalidate() to fname.c
fscrypt_d_revalidate() and fscrypt_d_ops really belong in fname.c, since
they're specific to filenames encryption. crypto.c is for contents
encryption and general fs/crypto/ initialization and utilities.
Link: https://lore.kernel.org/r/20191209204359.228544-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
Diffstat (limited to 'fs/crypto/fname.c')
-rw-r--r-- | fs/crypto/fname.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index c87b71aa2353..3fd27e14ebdd 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -11,6 +11,7 @@ * This has not yet undergone a rigorous security audit. */ +#include <linux/namei.h> #include <linux/scatterlist.h> #include <crypto/skcipher.h> #include "fscrypt_private.h" @@ -400,3 +401,51 @@ errout: return ret; } EXPORT_SYMBOL(fscrypt_setup_filename); + +/* + * Validate dentries in encrypted directories to make sure we aren't potentially + * caching stale dentries after a key has been added. + */ +static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) +{ + struct dentry *dir; + int err; + int valid; + + /* + * Plaintext names are always valid, since fscrypt doesn't support + * reverting to ciphertext names without evicting the directory's inode + * -- which implies eviction of the dentries in the directory. + */ + if (!(dentry->d_flags & DCACHE_ENCRYPTED_NAME)) + return 1; + + /* + * Ciphertext name; valid if the directory's key is still unavailable. + * + * Although fscrypt forbids rename() on ciphertext names, we still must + * use dget_parent() here rather than use ->d_parent directly. That's + * because a corrupted fs image may contain directory hard links, which + * the VFS handles by moving the directory's dentry tree in the dcache + * each time ->lookup() finds the directory and it already has a dentry + * elsewhere. Thus ->d_parent can be changing, and we must safely grab + * a reference to some ->d_parent to prevent it from being freed. + */ + + if (flags & LOOKUP_RCU) + return -ECHILD; + + dir = dget_parent(dentry); + err = fscrypt_get_encryption_info(d_inode(dir)); + valid = !fscrypt_has_encryption_key(d_inode(dir)); + dput(dir); + + if (err < 0) + return err; + + return valid; +} + +const struct dentry_operations fscrypt_d_ops = { + .d_revalidate = fscrypt_d_revalidate, +}; |