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:
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user