Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80468fec authored by Eric Biggers's avatar Eric Biggers Committed by Gerrit - the friendly Code Review server
Browse files

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: default avatarEric Biggers <ebiggers@google.com>
Git-commit: b30501ef
Git-repo: https://android.googlesource.com/kernel/common/+/refs/heads/android-4.19


[neersoni@codeaurora.org: Back port the change]
Signed-off-by: default avatarNeeraj Soni <neersoni@codeaurora.org>
parent a8f636f2
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -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(
+58 −12
Original line number Diff line number Diff line
@@ -25,26 +25,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,
@@ -56,14 +106,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;

@@ -72,10 +121,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);
+8 −2
Original line number Diff line number Diff line
@@ -335,8 +335,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;
@@ -361,6 +359,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
@@ -395,6 +397,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);