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:
parent
d3d1ea7cae
commit
29db976690
5 changed files with 119 additions and 18 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue