blob: 0d00637fdcc8f56ab5bde5ac6eb23269d27766fb [file] [log] [blame]
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Barani Muthukumaran <bmuthuku@codeaurora.org>
Date: Thu, 6 Feb 2020 18:01:20 -0800
Subject: ANDROID: block: Prevent crypto fallback for wrapped keys
blk-crypto-fallback does not support wrapped keys, hence
prevent falling back when program_key fails. Add 'is_hw_wrapped'
flag to blk-crypto-key to mention if the key is wrapped
when the key is initialized.
Bug: 147209885
Test: Validate FBE, simulate a failure in the underlying blk
device and ensure the call fails without falling back
to blk-crypto-fallback.
Change-Id: I8bc301ca1ac9e55ba6ab622e8325486916b45c56
Signed-off-by: Barani Muthukumaran <bmuthuku@codeaurora.org>
---
block/blk-crypto-fallback.c | 6 ++++++
block/blk-crypto.c | 17 +++++++++++++----
drivers/md/dm-default-key.c | 2 +-
fs/crypto/fscrypt_private.h | 6 ++++--
fs/crypto/inline_crypt.c | 3 ++-
fs/crypto/keyring.c | 9 ++++-----
fs/crypto/keysetup.c | 14 +++++++-------
fs/crypto/keysetup_v1.c | 2 +-
include/linux/bio-crypt-ctx.h | 3 +++
include/linux/blk-crypto.h | 1 +
10 files changed, 42 insertions(+), 21 deletions(-)
diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c
--- a/block/blk-crypto-fallback.c
+++ b/block/blk-crypto-fallback.c
@@ -572,6 +572,12 @@ int blk_crypto_fallback_submit_bio(struct bio **bio_ptr)
struct bio_crypt_ctx *bc = bio->bi_crypt_context;
struct bio_fallback_crypt_ctx *f_ctx;
+ if (bc->bc_key->is_hw_wrapped) {
+ pr_warn_once("HW wrapped key cannot be used with fallback.\n");
+ bio->bi_status = BLK_STS_NOTSUPP;
+ return -EOPNOTSUPP;
+ }
+
if (!tfms_inited[bc->bc_key->crypto_mode]) {
bio->bi_status = BLK_STS_IOERR;
return -EIO;
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -175,7 +175,9 @@ bool blk_crypto_endio(struct bio *bio)
* @raw_key_size: Size of raw key. Must be at least the required size for the
* chosen @crypto_mode; see blk_crypto_modes[]. (It's allowed
* to be longer than the mode's actual key size, in order to
- * support inline encryption hardware that accepts wrapped keys.)
+ * support inline encryption hardware that accepts wrapped keys.
+ * @is_hw_wrapped has to be set for such keys)
+ * @is_hw_wrapped: Denotes @raw_key is wrapped.
* @crypto_mode: identifier for the encryption algorithm to use
* @data_unit_size: the data unit size to use for en/decryption
*
@@ -184,6 +186,7 @@ bool blk_crypto_endio(struct bio *bio)
*/
int blk_crypto_init_key(struct blk_crypto_key *blk_key,
const u8 *raw_key, unsigned int raw_key_size,
+ bool is_hw_wrapped,
enum blk_crypto_mode_num crypto_mode,
unsigned int data_unit_size)
{
@@ -198,9 +201,14 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
BUILD_BUG_ON(BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE < BLK_CRYPTO_MAX_KEY_SIZE);
mode = &blk_crypto_modes[crypto_mode];
- if (raw_key_size < mode->keysize ||
- raw_key_size > BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE)
- return -EINVAL;
+ if (is_hw_wrapped) {
+ if (raw_key_size < mode->keysize ||
+ raw_key_size > BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE)
+ return -EINVAL;
+ } else {
+ if (raw_key_size != mode->keysize)
+ return -EINVAL;
+ }
if (!is_power_of_2(data_unit_size))
return -EINVAL;
@@ -209,6 +217,7 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
blk_key->data_unit_size = data_unit_size;
blk_key->data_unit_size_bits = ilog2(data_unit_size);
blk_key->size = raw_key_size;
+ blk_key->is_hw_wrapped = is_hw_wrapped;
memcpy(blk_key->raw, raw_key, raw_key_size);
/*
diff --git a/drivers/md/dm-default-key.c b/drivers/md/dm-default-key.c
--- a/drivers/md/dm-default-key.c
+++ b/drivers/md/dm-default-key.c
@@ -224,7 +224,7 @@ static int default_key_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
err = blk_crypto_init_key(&dkc->key, raw_key, cipher->key_size,
- cipher->mode_num, dkc->sector_size);
+ false, cipher->mode_num, dkc->sector_size);
if (err) {
ti->error = "Error initializing blk-crypto key";
goto bad;
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -341,6 +341,7 @@ extern int fscrypt_prepare_inline_crypt_key(
struct fscrypt_prepared_key *prep_key,
const u8 *raw_key,
unsigned int raw_key_size,
+ bool is_hw_wrapped,
const struct fscrypt_info *ci);
extern void fscrypt_destroy_inline_crypt_key(
@@ -385,6 +386,7 @@ static inline bool fscrypt_using_inline_encryption(
static inline int
fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
const u8 *raw_key, unsigned int raw_key_size,
+ bool is_hw_wrapped,
const struct fscrypt_info *ci)
{
WARN_ON(1);
@@ -585,8 +587,8 @@ struct fscrypt_mode {
extern struct fscrypt_mode fscrypt_modes[];
int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
- const u8 *raw_key, unsigned int raw_key_size,
- const struct fscrypt_info *ci);
+ const u8 *raw_key, unsigned int raw_key_size,
+ bool is_hw_wrapped, const struct fscrypt_info *ci);
void fscrypt_destroy_prepared_key(struct fscrypt_prepared_key *prep_key);
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -50,6 +50,7 @@ void fscrypt_select_encryption_impl(struct fscrypt_info *ci)
int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
const u8 *raw_key,
unsigned int raw_key_size,
+ bool is_hw_wrapped,
const struct fscrypt_info *ci)
{
const struct inode *inode = ci->ci_inode;
@@ -80,7 +81,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE);
err = blk_crypto_init_key(&blk_key->base, raw_key, raw_key_size,
- crypto_mode, sb->s_blocksize);
+ is_hw_wrapped, crypto_mode, sb->s_blocksize);
if (err) {
fscrypt_err(inode, "error %d initializing blk-crypto key", err);
goto fail;
diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
--- a/fs/crypto/keyring.c
+++ b/fs/crypto/keyring.c
@@ -681,14 +681,13 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg)
if (err)
goto out_wipe_secret;
err = -EINVAL;
- if (!(arg.__flags & __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED) &&
- secret.size > FSCRYPT_MAX_KEY_SIZE)
+ if (secret.size > FSCRYPT_MAX_KEY_SIZE && !secret.is_hw_wrapped)
goto out_wipe_secret;
} else {
if (arg.raw_size < FSCRYPT_MIN_KEY_SIZE ||
- arg.raw_size >
- ((arg.__flags & __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED) ?
- FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE : FSCRYPT_MAX_KEY_SIZE))
+ arg.raw_size > (secret.is_hw_wrapped ?
+ FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE :
+ FSCRYPT_MAX_KEY_SIZE))
return -EINVAL;
secret.size = arg.raw_size;
err = -EFAULT;
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -119,15 +119,15 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key,
*/
int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
const u8 *raw_key, unsigned int raw_key_size,
- const struct fscrypt_info *ci)
+ bool is_hw_wrapped, const struct fscrypt_info *ci)
{
struct crypto_skcipher *tfm;
if (fscrypt_using_inline_encryption(ci))
return fscrypt_prepare_inline_crypt_key(prep_key,
- raw_key, raw_key_size, ci);
+ raw_key, raw_key_size, is_hw_wrapped, ci);
- if (WARN_ON(raw_key_size != ci->ci_mode->keysize))
+ if (WARN_ON(is_hw_wrapped || raw_key_size != ci->ci_mode->keysize))
return -EINVAL;
tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode);
@@ -152,8 +152,8 @@ void fscrypt_destroy_prepared_key(struct fscrypt_prepared_key *prep_key)
int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key)
{
ci->ci_owns_key = true;
- return fscrypt_prepare_key(&ci->ci_key, raw_key,
- ci->ci_mode->keysize, ci);
+ return fscrypt_prepare_key(&ci->ci_key, raw_key, ci->ci_mode->keysize,
+ false /*is_hw_wrapped*/, ci);
}
static int setup_per_mode_enc_key(struct fscrypt_info *ci,
@@ -203,7 +203,7 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci,
}
}
err = fscrypt_prepare_key(prep_key, mk->mk_secret.raw,
- mk->mk_secret.size, ci);
+ mk->mk_secret.size, true, ci);
if (err)
goto out_unlock;
} else {
@@ -222,7 +222,7 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci,
if (err)
goto out_unlock;
err = fscrypt_prepare_key(prep_key, mode_key, mode->keysize,
- ci);
+ false /*is_hw_wrapped*/, ci);
memzero_explicit(mode_key, mode->keysize);
if (err)
goto out_unlock;
diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c
--- a/fs/crypto/keysetup_v1.c
+++ b/fs/crypto/keysetup_v1.c
@@ -234,7 +234,7 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key)
refcount_set(&dk->dk_refcount, 1);
dk->dk_mode = ci->ci_mode;
err = fscrypt_prepare_key(&dk->dk_key, raw_key, ci->ci_mode->keysize,
- ci);
+ false /*is_hw_wrapped*/, ci);
if (err)
goto err_free_dk;
memcpy(dk->dk_descriptor, ci->ci_policy.v1.master_key_descriptor,
diff --git a/include/linux/bio-crypt-ctx.h b/include/linux/bio-crypt-ctx.h
--- a/include/linux/bio-crypt-ctx.h
+++ b/include/linux/bio-crypt-ctx.h
@@ -31,6 +31,8 @@ enum blk_crypto_mode_num {
* @data_unit_size_bits: log2 of data_unit_size
* @size: size of this key in bytes (determined by @crypto_mode)
* @hash: hash of this key, for keyslot manager use only
+ * @is_hw_wrapped: @raw points to a wrapped key to be used by an inline
+ * encryption hardware that accepts wrapped keys.
* @raw: the raw bytes of this key. Only the first @size bytes are used.
*
* A blk_crypto_key is immutable once created, and many bios can reference it at
@@ -42,6 +44,7 @@ struct blk_crypto_key {
unsigned int data_unit_size_bits;
unsigned int size;
unsigned int hash;
+ bool is_hw_wrapped;
u8 raw[BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE];
};
diff --git a/include/linux/blk-crypto.h b/include/linux/blk-crypto.h
--- a/include/linux/blk-crypto.h
+++ b/include/linux/blk-crypto.h
@@ -16,6 +16,7 @@ bool blk_crypto_endio(struct bio *bio);
int blk_crypto_init_key(struct blk_crypto_key *blk_key,
const u8 *raw_key, unsigned int raw_key_size,
+ bool is_hw_wrapped,
enum blk_crypto_mode_num crypto_mode,
unsigned int data_unit_size);