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 OTA.

Change-Id: Idb9f5a140e755a9f5c9aa26d5f0e900252f441e8
Signed-off-by: Neeraj Soni <neersoni@codeaurora.org>
This commit is contained in:
Neeraj Soni 2020-10-21 15:17:16 +05:30
parent d3d1ea7cae
commit 29db976690
5 changed files with 119 additions and 18 deletions

View file

@ -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) ==
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 ((fscrypt_policy_contents_mode(&ci->ci_policy) ==
FSCRYPT_MODE_PRIVATE)
&& inlinecrypt) {
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);
}

View file

@ -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 */

View file

@ -44,7 +44,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,
@ -61,6 +61,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)
{

View file

@ -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,37 @@ out:
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 +315,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++)

View file

@ -29,7 +29,20 @@ bool fscrypt_policies_equal(const union fscrypt_policy *policy1,
if (policy1->version != policy2->version)
return false;
return !memcmp(policy1, policy2, fscrypt_policy_size(policy1));
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));
}
static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode)
@ -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)