summaryrefslogtreecommitdiff
path: root/fs/crypto/keysetup.c
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2020-09-16 21:11:35 -0700
committerEric Biggers <ebiggers@google.com>2020-09-22 06:48:49 -0700
commitac4acb1f4b2b6b7e8d913537cccec8789903e164 (patch)
treee6999a5cae6cb884d844450d19b59da6049186e5 /fs/crypto/keysetup.c
parent31114726b69364f3bf8dd945c600ceed4c430f4f (diff)
fscrypt: handle test_dummy_encryption in more logical way
The behavior of the test_dummy_encryption mount option is that when a new file (or directory or symlink) is created in an unencrypted directory, it's automatically encrypted using a dummy encryption policy. That's it; in particular, the encryption (or lack thereof) of existing files (or directories or symlinks) doesn't change. Unfortunately the implementation of test_dummy_encryption is a bit weird and confusing. When test_dummy_encryption is enabled and a file is being created in an unencrypted directory, we set up an encryption key (->i_crypt_info) for the directory. This isn't actually used to do any encryption, however, since the directory is still unencrypted! Instead, ->i_crypt_info is only used for inheriting the encryption policy. One consequence of this is that the filesystem ends up providing a "dummy context" (policy + nonce) instead of a "dummy policy". In commit ed318a6cc0b6 ("fscrypt: support test_dummy_encryption=v2"), I mistakenly thought this was required. However, actually the nonce only ends up being used to derive a key that is never used. Another consequence of this implementation is that it allows for 'inode->i_crypt_info != NULL && !IS_ENCRYPTED(inode)', which is an edge case that can be forgotten about. For example, currently FS_IOC_GET_ENCRYPTION_POLICY on an unencrypted directory may return the dummy encryption policy when the filesystem is mounted with test_dummy_encryption. That seems like the wrong thing to do, since again, the directory itself is not actually encrypted. Therefore, switch to a more logical and maintainable implementation where the dummy encryption policy inheritance is done without setting up keys for unencrypted directories. This involves: - Adding a function fscrypt_policy_to_inherit() which returns the encryption policy to inherit from a directory. This can be a real policy, a dummy policy, or no policy. - Replacing struct fscrypt_dummy_context, ->get_dummy_context(), etc. with struct fscrypt_dummy_policy, ->get_dummy_policy(), etc. - Making fscrypt_fname_encrypted_size() take an fscrypt_policy instead of an inode. Acked-by: Jaegeuk Kim <jaegeuk@kernel.org> Acked-by: Jeff Layton <jlayton@kernel.org> Link: https://lore.kernel.org/r/20200917041136.178600-13-ebiggers@kernel.org Signed-off-by: Eric Biggers <ebiggers@google.com>
Diffstat (limited to 'fs/crypto/keysetup.c')
-rw-r--r--fs/crypto/keysetup.c33
1 files changed, 9 insertions, 24 deletions
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index 47f19061ba10..d3c3e5d9b41f 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -547,7 +547,7 @@ out:
/**
* fscrypt_get_encryption_info() - set up an inode's encryption key
- * @inode: the inode to set up the key for
+ * @inode: the inode to set up the key for. Must be encrypted.
*
* Set up ->i_crypt_info, if it hasn't already been done.
*
@@ -569,18 +569,8 @@ int fscrypt_get_encryption_info(struct inode *inode)
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
if (res < 0) {
- const union fscrypt_context *dummy_ctx =
- fscrypt_get_dummy_context(inode->i_sb);
-
- if (IS_ENCRYPTED(inode) || !dummy_ctx) {
- fscrypt_warn(inode,
- "Error %d getting encryption context",
- res);
- return res;
- }
- /* Fake up a context for an unencrypted directory */
- res = fscrypt_context_size(dummy_ctx);
- memcpy(&ctx, dummy_ctx, res);
+ fscrypt_warn(inode, "Error %d getting encryption context", res);
+ return res;
}
res = fscrypt_policy_from_context(&policy, &ctx, res);
@@ -627,17 +617,14 @@ EXPORT_SYMBOL(fscrypt_get_encryption_info);
int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
bool *encrypt_ret)
{
- int err;
+ const union fscrypt_policy *policy;
u8 nonce[FSCRYPT_FILE_NONCE_SIZE];
- if (!IS_ENCRYPTED(dir) && fscrypt_get_dummy_context(dir->i_sb) == NULL)
+ policy = fscrypt_policy_to_inherit(dir);
+ if (policy == NULL)
return 0;
-
- err = fscrypt_get_encryption_info(dir);
- if (err)
- return err;
- if (!fscrypt_has_encryption_key(dir))
- return -ENOKEY;
+ if (IS_ERR(policy))
+ return PTR_ERR(policy);
if (WARN_ON_ONCE(inode->i_mode == 0))
return -EINVAL;
@@ -654,9 +641,7 @@ int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
*encrypt_ret = true;
get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE);
- return fscrypt_setup_encryption_info(inode,
- &dir->i_crypt_info->ci_policy,
- nonce,
+ return fscrypt_setup_encryption_info(inode, policy, nonce,
IS_CASEFOLDED(dir) &&
S_ISDIR(inode->i_mode));
}