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

Commit 06de8144 authored by Neeraj Soni's avatar Neeraj Soni Committed by Gerrit - the friendly Code Review server
Browse files

fs: crypto: support IV_INO_LBLK_32 for legacy (V1) format



New file encryption V2 format suports IV_INO_LBLK_32 but this is
needed in V1 to support over the air upgrade which uses
FS_ENCRYPTION_MODE_PRIVATE data encryption mode. Also randomness of
encrypted data for eMMC devices is fixed.

Test: vts-kernel-encryption test after Q to R update.

Change-Id: Idb9f5a140e755a9f5c9aa26d5f0e900252f441e8
Signed-off-by: default avatarNeeraj Soni <neersoni@codeaurora.org>
parent fbd29cbb
Loading
Loading
Loading
Loading
+18 −12
Original line number Diff line number Diff line
@@ -89,25 +89,31 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
#endif
	memset(iv, 0, ci->ci_mode->ivsize);

	if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
		WARN_ON_ONCE(lblk_num > U32_MAX);
		WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX);
		lblk_num |= (u64)ci->ci_inode->i_ino << 32;
	} else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
		WARN_ON_ONCE(lblk_num > U32_MAX);
		lblk_num = (u32)(ci->ci_hashed_ino + lblk_num);
	} else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) {
		memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE);
	} else if ((fscrypt_policy_contents_mode(&ci->ci_policy) ==
	if ((fscrypt_policy_contents_mode(&ci->ci_policy) ==
					  FSCRYPT_MODE_PRIVATE)
					  && inlinecrypt) {
		if (ci->ci_inode->i_sb->s_type->name) {
			if (!strcmp(ci->ci_inode->i_sb->s_type->name, "f2fs")) {
		if (ci->ci_inode->i_sb->s_type->name &&
		    !strcmp(ci->ci_inode->i_sb->s_type->name, "f2fs")) {
			if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
				WARN_ON_ONCE(lblk_num > U32_MAX);
				lblk_num = (u32)(ci->ci_hashed_ino + lblk_num);
			} else {
				WARN_ON_ONCE(lblk_num > U32_MAX);
				WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX);
				lblk_num |= (u64)ci->ci_inode->i_ino << 32;
			}
		}
	} else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
		WARN_ON_ONCE(lblk_num > U32_MAX);
		WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX);
		lblk_num |= (u64)ci->ci_inode->i_ino << 32;
	} else if ((flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) &&
		   !(fscrypt_policy_contents_mode(&ci->ci_policy) ==
		     FSCRYPT_MODE_PRIVATE)) {
		WARN_ON_ONCE(lblk_num > U32_MAX);
		lblk_num = (u32)(ci->ci_hashed_ino + lblk_num);
	} else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) {
		memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE);
	}
	iv->lblk_num = cpu_to_le64(lblk_num);
}
+7 −0
Original line number Diff line number Diff line
@@ -371,6 +371,8 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
	return READ_ONCE(prep_key->tfm) != NULL;
}

extern int fscrypt_find_storage_type(char **device);

#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */

static inline int fscrypt_select_encryption_impl(struct fscrypt_info *ci,
@@ -417,6 +419,11 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
{
	return READ_ONCE(prep_key->tfm) != NULL;
}

static inline int fscrypt_find_storage_type(char **device)
{
	return -EOPNOTSUPP;
}
#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */

/* keyring.c */
+2 −1
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ static void fscrypt_get_devices(struct super_block *sb, int num_devs,

#define SDHCI "sdhci"

static int fscrypt_find_storage_type(char **device)
int fscrypt_find_storage_type(char **device)
{
	char boot[20] = {'\0'};
	char *match = (char *)strnstr(saved_command_line,
@@ -62,6 +62,7 @@ static int fscrypt_find_storage_type(char **device)
	}
	return -EINVAL;
}
EXPORT_SYMBOL(fscrypt_find_storage_type);

static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci)
{
+53 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@
#include <linux/hashtable.h>
#include <linux/scatterlist.h>
#include <linux/bio-crypt-ctx.h>
#include <linux/siphash.h>
#include <crypto/sha.h>

#include "fscrypt_private.h"

@@ -33,6 +35,8 @@
static DEFINE_HASHTABLE(fscrypt_direct_keys, 6); /* 6 bits = 64 buckets */
static DEFINE_SPINLOCK(fscrypt_direct_keys_lock);

static struct crypto_shash *essiv_hash_tfm;

/*
 * v1 key derivation function.  This generates the derived key by encrypting the
 * master key with AES-128-ECB using the nonce as the AES key.  This provides a
@@ -84,6 +88,36 @@ static int derive_key_aes(const u8 *master_key,
	return res;
}

static int fscrypt_do_sha256(const u8 *src, int srclen, u8 *dst)
{
	struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm);

	/* init hash transform on demand */
	if (unlikely(!tfm)) {
		struct crypto_shash *prev_tfm;

		tfm = crypto_alloc_shash("sha256", 0, 0);
		if (IS_ERR(tfm)) {
			fscrypt_warn(NULL,
				     "error allocating SHA-256 transform: %ld",
				     PTR_ERR(tfm));
			return PTR_ERR(tfm);
		}
		prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm);
		if (prev_tfm) {
			crypto_free_shash(tfm);
			tfm = prev_tfm;
		}
	}

	{
		SHASH_DESC_ON_STACK(desc, tfm);
		desc->tfm = tfm;
		desc->flags = 0;
		return crypto_shash_digest(desc, src, srclen, dst);
	}
}

/*
 * Search the current task's subscribed keyrings for a "logon" key with
 * description prefix:descriptor, and if found acquire a read lock on it and
@@ -280,6 +314,25 @@ static int setup_v1_file_key_derived(struct fscrypt_info *ci,
					  FSCRYPT_MODE_PRIVATE) &&
					  fscrypt_using_inline_encryption(ci)) {
		ci->ci_owns_key = true;
		if (ci->ci_policy.v1.flags &
		    FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
			union {
				siphash_key_t k;
				u8 bytes[SHA256_DIGEST_SIZE];
			} ino_hash_key;
			int err;

			/* hashed_ino = SipHash(key=SHA256(master_key),
			 * data=i_ino)
			 */
			err = fscrypt_do_sha256(raw_master_key,
						ci->ci_mode->keysize / 2,
						ino_hash_key.bytes);
			if (err)
				return err;
			ci->ci_hashed_ino = siphash_1u64(ci->ci_inode->i_ino,
							 &ino_hash_key.k);
		}
		memcpy(key_new.bytes, raw_master_key, ci->ci_mode->keysize);

		for (i = 0; i < ARRAY_SIZE(key_new.words); i++)
+36 −3
Original line number Diff line number Diff line
@@ -29,6 +29,19 @@ bool fscrypt_policies_equal(const union fscrypt_policy *policy1,
	if (policy1->version != policy2->version)
		return false;

	if (fscrypt_policy_contents_mode(policy1) == FSCRYPT_MODE_PRIVATE)
		return(!memcmp(policy1->v1.master_key_descriptor,
		       policy2->v1.master_key_descriptor,
		       FSCRYPT_KEY_DESCRIPTOR_SIZE)) &&
		      (fscrypt_policy_contents_mode(policy1) ==
		       fscrypt_policy_contents_mode(policy2)) &&
		      (fscrypt_policy_fnames_mode(policy1) ==
		       fscrypt_policy_fnames_mode(policy2)) &&
		      ((fscrypt_policy_flags(policy1) &
			~FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) ==
		       (fscrypt_policy_flags(policy2) &
			~FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32));
	else
		return !memcmp(policy1, policy2, fscrypt_policy_size(policy1));
}

@@ -122,7 +135,8 @@ static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy,
	}

	if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK |
			      FSCRYPT_POLICY_FLAG_DIRECT_KEY)) {
			      FSCRYPT_POLICY_FLAG_DIRECT_KEY |
			      FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) {
		fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)",
			     policy->flags);
		return false;
@@ -610,6 +624,20 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
}
EXPORT_SYMBOL(fscrypt_has_permitted_context);

#define SDHCI "sdhci"

static int fscrypt_update_context(union fscrypt_context *ctx)
{
	char *boot = "ufs";

	if (!fscrypt_find_storage_type(&boot)) {
		if (!strcmp(boot, SDHCI))
			ctx->v1.flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32;
			return 0;
	}
	return -EINVAL;
}

/**
 * fscrypt_inherit_context() - Sets a child context from its parent
 * @parent: Parent inode from which the context is inherited.
@@ -636,7 +664,12 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child,
		return -ENOKEY;

	ctxsize = fscrypt_new_context_from_policy(&ctx, &ci->ci_policy);

	if (fscrypt_policy_contents_mode(&ci->ci_policy) ==
	    FSCRYPT_MODE_PRIVATE) {
		res = fscrypt_update_context(&ctx);
		if (res)
			return res;
	}
	BUILD_BUG_ON(sizeof(ctx) != FSCRYPT_SET_CONTEXT_MAX_SIZE);
	res = parent->i_sb->s_cop->set_context(child, &ctx, ctxsize, fs_data);
	if (res)