diff options
author | Eric Biggers <ebiggers@google.com> | 2020-09-16 21:11:35 -0700 |
---|---|---|
committer | Eric Biggers <ebiggers@google.com> | 2020-09-22 06:48:49 -0700 |
commit | ac4acb1f4b2b6b7e8d913537cccec8789903e164 (patch) | |
tree | e6999a5cae6cb884d844450d19b59da6049186e5 /fs/crypto/keysetup.c | |
parent | 31114726b69364f3bf8dd945c600ceed4c430f4f (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.c | 33 |
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)); } |