summaryrefslogtreecommitdiffstats
path: root/fs/crypto/fname.c
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2019-12-09 21:43:59 +0100
committerEric Biggers <ebiggers@google.com>2019-12-31 17:33:50 +0100
commit2ebdef6d8c766ab7da532002091ad486f9db88ed (patch)
treee5610ff175989c9d70c6da9e13b3a41604379c7b /fs/crypto/fname.c
parentfscrypt: constify inode parameter to filename encryption functions (diff)
downloadlinux-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.c49
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,
+};