ANDROID: fscrypt: fall back to filesystem-layer crypto when needed

When the filesystem is mounted with '-o inlinecrypt', make fscrypt fall
back to filesystem-layer crypto when inline crypto won't work, e.g. due
to the hardware not supporting the encryption algorithm.

When blk-crypto-fallback is disabled, this fixes '-o inlinecrypt' to not
break any fscrypt policies that would otherwise work.

This is needed for VtsKernelEncryptionTest to pass on some devices.

Bug: 137270441
Bug: 151100202
Test: 'atest vts_kernel_encryption_test' on Pixel 4 with the
      inline crypto patches backported, and also on Cuttlefish.
Change-Id: I3e730df4608efb12d7126d1a85faddcccb566764
Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
Eric Biggers
2020-04-03 12:06:11 -07:00
parent a14fa7bc5f
commit 4efb7e218a
3 changed files with 71 additions and 16 deletions

View File

@@ -326,7 +326,8 @@ extern void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf);
/* inline_crypt.c */
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
extern void fscrypt_select_encryption_impl(struct fscrypt_info *ci);
extern int fscrypt_select_encryption_impl(struct fscrypt_info *ci,
bool is_hw_wrapped_key);
static inline bool
fscrypt_using_inline_encryption(const struct fscrypt_info *ci)
@@ -370,8 +371,10 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
static inline void fscrypt_select_encryption_impl(struct fscrypt_info *ci)
static inline int fscrypt_select_encryption_impl(struct fscrypt_info *ci,
bool is_hw_wrapped_key)
{
return 0;
}
static inline bool fscrypt_using_inline_encryption(

View File

@@ -26,26 +26,76 @@ struct fscrypt_blk_crypto_key {
struct request_queue *devs[];
};
static int fscrypt_get_num_devices(struct super_block *sb)
{
if (sb->s_cop->get_num_devices)
return sb->s_cop->get_num_devices(sb);
return 1;
}
static void fscrypt_get_devices(struct super_block *sb, int num_devs,
struct request_queue **devs)
{
if (num_devs == 1)
devs[0] = bdev_get_queue(sb->s_bdev);
else
sb->s_cop->get_devices(sb, devs);
}
/* Enable inline encryption for this file if supported. */
void fscrypt_select_encryption_impl(struct fscrypt_info *ci)
int fscrypt_select_encryption_impl(struct fscrypt_info *ci,
bool is_hw_wrapped_key)
{
const struct inode *inode = ci->ci_inode;
struct super_block *sb = inode->i_sb;
enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode;
struct request_queue **devs;
int num_devs;
int i;
/* The file must need contents encryption, not filenames encryption */
if (!S_ISREG(inode->i_mode))
return;
return 0;
/* blk-crypto must implement the needed encryption algorithm */
if (ci->ci_mode->blk_crypto_mode == BLK_ENCRYPTION_MODE_INVALID)
return;
if (crypto_mode == BLK_ENCRYPTION_MODE_INVALID)
return 0;
/* The filesystem must be mounted with -o inlinecrypt */
if (!sb->s_cop->inline_crypt_enabled ||
!sb->s_cop->inline_crypt_enabled(sb))
return;
return 0;
/*
* The needed encryption settings must be supported either by
* blk-crypto-fallback, or by hardware on all the filesystem's devices.
*/
if (IS_ENABLED(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) &&
!is_hw_wrapped_key) {
ci->ci_inlinecrypt = true;
return 0;
}
num_devs = fscrypt_get_num_devices(sb);
devs = kmalloc_array(num_devs, sizeof(*devs), GFP_NOFS);
if (!devs)
return -ENOMEM;
fscrypt_get_devices(sb, num_devs, devs);
for (i = 0; i < num_devs; i++) {
if (!keyslot_manager_crypto_mode_supported(devs[i]->ksm,
crypto_mode,
sb->s_blocksize,
is_hw_wrapped_key))
goto out_free_devs;
}
ci->ci_inlinecrypt = true;
out_free_devs:
kfree(devs);
return 0;
}
int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
@@ -57,14 +107,13 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
const struct inode *inode = ci->ci_inode;
struct super_block *sb = inode->i_sb;
enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode;
int num_devs = 1;
int num_devs;
int queue_refs = 0;
struct fscrypt_blk_crypto_key *blk_key;
int err;
int i;
if (sb->s_cop->get_num_devices)
num_devs = sb->s_cop->get_num_devices(sb);
num_devs = fscrypt_get_num_devices(sb);
if (WARN_ON(num_devs < 1))
return -EINVAL;
@@ -73,10 +122,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
return -ENOMEM;
blk_key->num_devs = num_devs;
if (num_devs == 1)
blk_key->devs[0] = bdev_get_queue(sb->s_bdev);
else
sb->s_cop->get_devices(sb, blk_key->devs);
fscrypt_get_devices(sb, num_devs, blk_key->devs);
BUILD_BUG_ON(FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE >
BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE);

View File

@@ -328,8 +328,6 @@ static int setup_file_encryption_key(struct fscrypt_info *ci,
struct fscrypt_key_specifier mk_spec;
int err;
fscrypt_select_encryption_impl(ci);
switch (ci->ci_policy.version) {
case FSCRYPT_POLICY_V1:
mk_spec.type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
@@ -354,6 +352,10 @@ static int setup_file_encryption_key(struct fscrypt_info *ci,
ci->ci_policy.version != FSCRYPT_POLICY_V1)
return PTR_ERR(key);
err = fscrypt_select_encryption_impl(ci, false);
if (err)
return err;
/*
* As a legacy fallback for v1 policies, search for the key in
* the current task's subscribed keyrings too. Don't move this
@@ -388,6 +390,10 @@ static int setup_file_encryption_key(struct fscrypt_info *ci,
goto out_release_key;
}
err = fscrypt_select_encryption_impl(ci, mk->mk_secret.is_hw_wrapped);
if (err)
goto out_release_key;
switch (ci->ci_policy.version) {
case FSCRYPT_POLICY_V1:
err = fscrypt_setup_v1_file_key(ci, mk->mk_secret.raw);