diff options
Diffstat (limited to 'fs/crypto/crypto.c')
| -rw-r--r-- | fs/crypto/crypto.c | 75 | 
1 files changed, 36 insertions, 39 deletions
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 4dc788e3bc96..335a362ee446 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only  /*   * This contains encryption functions for per-file encryption.   * @@ -87,23 +88,17 @@ EXPORT_SYMBOL(fscrypt_release_ctx);  /**   * fscrypt_get_ctx() - Gets an encryption context - * @inode:       The inode for which we are doing the crypto   * @gfp_flags:   The gfp flag for memory allocation   *   * Allocates and initializes an encryption context.   * - * Return: An allocated and initialized encryption context on success; error - * value or NULL otherwise. + * Return: A new encryption context on success; an ERR_PTR() otherwise.   */ -struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags) +struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags)  { -	struct fscrypt_ctx *ctx = NULL; -	struct fscrypt_info *ci = inode->i_crypt_info; +	struct fscrypt_ctx *ctx;  	unsigned long flags; -	if (ci == NULL) -		return ERR_PTR(-ENOKEY); -  	/*  	 * We first try getting the ctx from a free list because in  	 * the common case the ctx will have an allocated and @@ -258,9 +253,9 @@ struct page *fscrypt_encrypt_page(const struct inode *inode,  	BUG_ON(!PageLocked(page)); -	ctx = fscrypt_get_ctx(inode, gfp_flags); +	ctx = fscrypt_get_ctx(gfp_flags);  	if (IS_ERR(ctx)) -		return (struct page *)ctx; +		return ERR_CAST(ctx);  	/* The encryption operation will require a bounce page. */  	ciphertext_page = fscrypt_alloc_bounce_page(ctx, gfp_flags); @@ -313,45 +308,47 @@ int fscrypt_decrypt_page(const struct inode *inode, struct page *page,  EXPORT_SYMBOL(fscrypt_decrypt_page);  /* - * Validate dentries for encrypted directories to make sure we aren't - * potentially caching stale data after a key has been added or - * removed. + * 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 dir_has_key, cached_with_key; +	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); -	if (!IS_ENCRYPTED(d_inode(dir))) { -		dput(dir); -		return 0; -	} - -	spin_lock(&dentry->d_lock); -	cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY; -	spin_unlock(&dentry->d_lock); -	dir_has_key = (d_inode(dir)->i_crypt_info != NULL); +	err = fscrypt_get_encryption_info(d_inode(dir)); +	valid = !fscrypt_has_encryption_key(d_inode(dir));  	dput(dir); -	/* -	 * If the dentry was cached without the key, and it is a -	 * negative dentry, it might be a valid name.  We can't check -	 * if the key has since been made available due to locking -	 * reasons, so we fail the validation so ext4_lookup() can do -	 * this check. -	 * -	 * We also fail the validation if the dentry was created with -	 * the key present, but we no longer have the key, or vice versa. -	 */ -	if ((!cached_with_key && d_is_negative(dentry)) || -			(!cached_with_key && dir_has_key) || -			(cached_with_key && !dir_has_key)) -		return 0; -	return 1; +	if (err < 0) +		return err; + +	return valid;  }  const struct dentry_operations fscrypt_d_ops = {  |