aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinaro CI <ci-bot@linaro.org>2020-05-14 22:07:29 +0000
committerLinaro CI <ci-bot@linaro.org>2020-05-14 22:07:29 +0000
commit86a60c2c349e59bd3e26fdcfb5216c4a98c775bf (patch)
treeedca42553df0f344628f7f12fe639c49ad960e82
parent0bc653cf37344600f0ac5831643644ef8463359b (diff)
parent6be68d89b4d524dde1476be8f895a69cc08237ee (diff)
downloadhikey-linaro-86a60c2c349e59bd3e26fdcfb5216c4a98c775bf.tar.gz
Merge remote-tracking branch 'aosp/mirror-android-4.14-stable' into android-hikey-linaro-4.14-stable-lkftv4.14.180-2968-g6be68d89b4d5-20200514-65
-rw-r--r--block/blk-crypto.c22
-rw-r--r--block/keyslot-manager.c24
-rw-r--r--drivers/md/dm-default-key.c20
-rw-r--r--drivers/scsi/ufs/ufshcd-crypto.c1
-rw-r--r--fs/crypto/inline_crypt.c31
-rw-r--r--include/linux/bio-crypt-ctx.h28
-rw-r--r--include/linux/blk-crypto.h2
-rw-r--r--include/linux/keyslot-manager.h4
8 files changed, 120 insertions, 12 deletions
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index f56bbec1132f..e07a37cf8b5f 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -108,9 +108,10 @@ int blk_crypto_submit_bio(struct bio **bio_ptr)
/* Get device keyslot if supported */
if (keyslot_manager_crypto_mode_supported(q->ksm,
- bc->bc_key->crypto_mode,
- bc->bc_key->data_unit_size,
- bc->bc_key->is_hw_wrapped)) {
+ bc->bc_key->crypto_mode,
+ blk_crypto_key_dun_bytes(bc->bc_key),
+ bc->bc_key->data_unit_size,
+ bc->bc_key->is_hw_wrapped)) {
err = bio_crypt_ctx_acquire_keyslot(bc, q->ksm);
if (!err)
return 0;
@@ -180,6 +181,8 @@ bool blk_crypto_endio(struct bio *bio)
* @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
+ * @dun_bytes: number of bytes that will be used to specify the DUN when this
+ * key is used
* @data_unit_size: the data unit size to use for en/decryption
*
* Return: The blk_crypto_key that was prepared, or an ERR_PTR() on error. When
@@ -189,10 +192,12 @@ 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 dun_bytes,
unsigned int data_unit_size)
{
const struct blk_crypto_mode *mode;
static siphash_key_t hash_key;
+ u32 hash;
memset(blk_key, 0, sizeof(*blk_key));
@@ -211,6 +216,9 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
return -EINVAL;
}
+ if (dun_bytes <= 0 || dun_bytes > BLK_CRYPTO_MAX_IV_SIZE)
+ return -EINVAL;
+
if (!is_power_of_2(data_unit_size))
return -EINVAL;
@@ -227,7 +235,8 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
* precomputed here so that it only needs to be computed once per key.
*/
get_random_once(&hash_key, sizeof(hash_key));
- blk_key->hash = siphash(raw_key, raw_key_size, &hash_key);
+ hash = (u32)siphash(raw_key, raw_key_size, &hash_key);
+ blk_crypto_key_set_hash_and_dun_bytes(blk_key, hash, dun_bytes);
return 0;
}
@@ -236,6 +245,7 @@ EXPORT_SYMBOL_GPL(blk_crypto_init_key);
/**
* blk_crypto_start_using_mode() - Start using blk-crypto on a device
* @crypto_mode: the crypto mode that will be used
+ * @dun_bytes: number of bytes that will be used to specify the DUN
* @data_unit_size: the data unit size that will be used
* @is_hw_wrapped_key: whether the key will be hardware-wrapped
* @q: the request queue for the device
@@ -249,12 +259,13 @@ EXPORT_SYMBOL_GPL(blk_crypto_init_key);
* algorithm is disabled in the crypto API; or another -errno code.
*/
int blk_crypto_start_using_mode(enum blk_crypto_mode_num crypto_mode,
+ unsigned int dun_bytes,
unsigned int data_unit_size,
bool is_hw_wrapped_key,
struct request_queue *q)
{
if (keyslot_manager_crypto_mode_supported(q->ksm, crypto_mode,
- data_unit_size,
+ dun_bytes, data_unit_size,
is_hw_wrapped_key))
return 0;
if (is_hw_wrapped_key) {
@@ -285,6 +296,7 @@ int blk_crypto_evict_key(struct request_queue *q,
{
if (q->ksm &&
keyslot_manager_crypto_mode_supported(q->ksm, key->crypto_mode,
+ blk_crypto_key_dun_bytes(key),
key->data_unit_size,
key->is_hw_wrapped))
return keyslot_manager_evict_key(q->ksm, key);
diff --git a/block/keyslot-manager.c b/block/keyslot-manager.c
index fe7dff3cae79..901545c5854c 100644
--- a/block/keyslot-manager.c
+++ b/block/keyslot-manager.c
@@ -46,6 +46,7 @@ struct keyslot_manager {
struct keyslot_mgmt_ll_ops ksm_ll_ops;
unsigned int features;
unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX];
+ unsigned int max_dun_bytes_supported;
void *ll_priv_data;
#ifdef CONFIG_PM
@@ -183,6 +184,7 @@ struct keyslot_manager *keyslot_manager_create(
ksm->features = features;
memcpy(ksm->crypto_mode_supported, crypto_mode_supported,
sizeof(ksm->crypto_mode_supported));
+ ksm->max_dun_bytes_supported = BLK_CRYPTO_MAX_IV_SIZE;
ksm->ll_priv_data = ll_priv_data;
keyslot_manager_set_dev(ksm, dev);
@@ -215,11 +217,19 @@ err_free_ksm:
}
EXPORT_SYMBOL_GPL(keyslot_manager_create);
+void keyslot_manager_set_max_dun_bytes(struct keyslot_manager *ksm,
+ unsigned int max_dun_bytes)
+{
+ ksm->max_dun_bytes_supported = max_dun_bytes;
+}
+EXPORT_SYMBOL_GPL(keyslot_manager_set_max_dun_bytes);
+
static inline struct hlist_head *
hash_bucket_for_key(struct keyslot_manager *ksm,
const struct blk_crypto_key *key)
{
- return &ksm->slot_hashtable[key->hash & (ksm->slot_hashtable_size - 1)];
+ return &ksm->slot_hashtable[blk_crypto_key_hash(key) &
+ (ksm->slot_hashtable_size - 1)];
}
static void remove_slot_from_lru_list(struct keyslot_manager *ksm, int slot)
@@ -392,6 +402,7 @@ void keyslot_manager_put_slot(struct keyslot_manager *ksm, unsigned int slot)
* combination is supported by a ksm.
* @ksm: The keyslot manager to check
* @crypto_mode: The crypto mode to check for.
+ * @dun_bytes: The number of bytes that will be used to specify the DUN
* @data_unit_size: The data_unit_size for the mode.
* @is_hw_wrapped_key: Whether a hardware-wrapped key will be used.
*
@@ -403,6 +414,7 @@ void keyslot_manager_put_slot(struct keyslot_manager *ksm, unsigned int slot)
*/
bool keyslot_manager_crypto_mode_supported(struct keyslot_manager *ksm,
enum blk_crypto_mode_num crypto_mode,
+ unsigned int dun_bytes,
unsigned int data_unit_size,
bool is_hw_wrapped_key)
{
@@ -419,7 +431,10 @@ bool keyslot_manager_crypto_mode_supported(struct keyslot_manager *ksm,
if (!(ksm->features & BLK_CRYPTO_FEATURE_STANDARD_KEYS))
return false;
}
- return ksm->crypto_mode_supported[crypto_mode] & data_unit_size;
+ if (!(ksm->crypto_mode_supported[crypto_mode] & data_unit_size))
+ return false;
+
+ return ksm->max_dun_bytes_supported >= dun_bytes;
}
/**
@@ -566,6 +581,7 @@ struct keyslot_manager *keyslot_manager_create_passthrough(
ksm->features = features;
memcpy(ksm->crypto_mode_supported, crypto_mode_supported,
sizeof(ksm->crypto_mode_supported));
+ ksm->max_dun_bytes_supported = BLK_CRYPTO_MAX_IV_SIZE;
ksm->ll_priv_data = ll_priv_data;
keyslot_manager_set_dev(ksm, dev);
@@ -593,12 +609,16 @@ void keyslot_manager_intersect_modes(struct keyslot_manager *parent,
unsigned int i;
parent->features &= child->features;
+ parent->max_dun_bytes_supported =
+ min(parent->max_dun_bytes_supported,
+ child->max_dun_bytes_supported);
for (i = 0; i < ARRAY_SIZE(child->crypto_mode_supported); i++) {
parent->crypto_mode_supported[i] &=
child->crypto_mode_supported[i];
}
} else {
parent->features = 0;
+ parent->max_dun_bytes_supported = 0;
memset(parent->crypto_mode_supported, 0,
sizeof(parent->crypto_mode_supported));
}
diff --git a/drivers/md/dm-default-key.c b/drivers/md/dm-default-key.c
index 8820d4f8464d..3b92b7d4249a 100644
--- a/drivers/md/dm-default-key.c
+++ b/drivers/md/dm-default-key.c
@@ -40,6 +40,7 @@ static const struct dm_default_key_cipher {
* @sector_size: crypto sector size in bytes (usually 4096)
* @sector_bits: log2(sector_size)
* @key: the encryption key to use
+ * @max_dun: the maximum DUN that may be used (computed from other params)
*/
struct default_key_c {
struct dm_dev *dev;
@@ -50,6 +51,7 @@ struct default_key_c {
unsigned int sector_bits;
struct blk_crypto_key key;
bool is_hw_wrapped;
+ u64 max_dun;
};
static const struct dm_default_key_cipher *
@@ -149,6 +151,7 @@ static int default_key_ctr(struct dm_target *ti, unsigned int argc, char **argv)
const struct dm_default_key_cipher *cipher;
u8 raw_key[DM_DEFAULT_KEY_MAX_WRAPPED_KEY_SIZE];
unsigned int raw_key_size;
+ unsigned int dun_bytes;
unsigned long long tmpll;
char dummy;
int err;
@@ -232,16 +235,20 @@ static int default_key_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad;
}
+ dkc->max_dun = (dkc->iv_offset + ti->len - 1) >>
+ (dkc->sector_bits - SECTOR_SHIFT);
+ dun_bytes = DIV_ROUND_UP(fls64(dkc->max_dun), 8);
+
err = blk_crypto_init_key(&dkc->key, raw_key, raw_key_size,
dkc->is_hw_wrapped, cipher->mode_num,
- dkc->sector_size);
+ dun_bytes, dkc->sector_size);
if (err) {
ti->error = "Error initializing blk-crypto key";
goto bad;
}
- err = blk_crypto_start_using_mode(cipher->mode_num, dkc->sector_size,
- dkc->is_hw_wrapped,
+ err = blk_crypto_start_using_mode(cipher->mode_num, dun_bytes,
+ dkc->sector_size, dkc->is_hw_wrapped,
dkc->dev->bdev->bd_queue);
if (err) {
ti->error = "Error starting to use blk-crypto";
@@ -302,6 +309,13 @@ static int default_key_map(struct dm_target *ti, struct bio *bio)
return DM_MAPIO_KILL;
dun[0] >>= dkc->sector_bits - SECTOR_SHIFT; /* crypto sectors */
+ /*
+ * This check isn't necessary as we should have calculated max_dun
+ * correctly, but be safe.
+ */
+ if (WARN_ON_ONCE(dun[0] > dkc->max_dun))
+ return DM_MAPIO_KILL;
+
bio_crypt_set_ctx(bio, &dkc->key, dun, GFP_NOIO);
return DM_MAPIO_REMAPPED;
diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c
index d62ab7a9faff..cbe61ee9f612 100644
--- a/drivers/scsi/ufs/ufshcd-crypto.c
+++ b/drivers/scsi/ufs/ufshcd-crypto.c
@@ -344,6 +344,7 @@ int ufshcd_hba_init_crypto_spec(struct ufs_hba *hba,
err = -ENOMEM;
goto out_free_caps;
}
+ keyslot_manager_set_max_dun_bytes(hba->ksm, sizeof(u64));
return 0;
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index e1bbaeff1c43..f96e2972a003 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -42,6 +42,24 @@ static void fscrypt_get_devices(struct super_block *sb, int num_devs,
sb->s_cop->get_devices(sb, devs);
}
+static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci)
+{
+ struct super_block *sb = ci->ci_inode->i_sb;
+ unsigned int flags = fscrypt_policy_flags(&ci->ci_policy);
+ int ino_bits = 64, lblk_bits = 64;
+
+ if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY)
+ return offsetofend(union fscrypt_iv, nonce);
+
+ if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64)
+ return sizeof(__le64);
+
+ /* Default case: IVs are just the file logical block number */
+ if (sb->s_cop->get_ino_and_lblk_bits)
+ sb->s_cop->get_ino_and_lblk_bits(sb, &ino_bits, &lblk_bits);
+ return DIV_ROUND_UP(lblk_bits, 8);
+}
+
/* Enable inline encryption for this file if supported. */
int fscrypt_select_encryption_impl(struct fscrypt_info *ci,
bool is_hw_wrapped_key)
@@ -49,6 +67,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci,
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;
+ unsigned int dun_bytes;
struct request_queue **devs;
int num_devs;
int i;
@@ -84,9 +103,12 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci,
fscrypt_get_devices(sb, num_devs, devs);
+ dun_bytes = fscrypt_get_dun_bytes(ci);
+
for (i = 0; i < num_devs; i++) {
if (!keyslot_manager_crypto_mode_supported(devs[i]->ksm,
crypto_mode,
+ dun_bytes,
sb->s_blocksize,
is_hw_wrapped_key))
goto out_free_devs;
@@ -107,6 +129,7 @@ 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;
+ unsigned int dun_bytes;
int num_devs;
int queue_refs = 0;
struct fscrypt_blk_crypto_key *blk_key;
@@ -124,11 +147,14 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
blk_key->num_devs = num_devs;
fscrypt_get_devices(sb, num_devs, blk_key->devs);
+ dun_bytes = fscrypt_get_dun_bytes(ci);
+
BUILD_BUG_ON(FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE >
BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE);
err = blk_crypto_init_key(&blk_key->base, raw_key, raw_key_size,
- is_hw_wrapped, crypto_mode, sb->s_blocksize);
+ is_hw_wrapped, crypto_mode, dun_bytes,
+ sb->s_blocksize);
if (err) {
fscrypt_err(inode, "error %d initializing blk-crypto key", err);
goto fail;
@@ -149,7 +175,8 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
}
queue_refs++;
- err = blk_crypto_start_using_mode(crypto_mode, sb->s_blocksize,
+ err = blk_crypto_start_using_mode(crypto_mode, dun_bytes,
+ sb->s_blocksize,
is_hw_wrapped,
blk_key->devs[i]);
if (err) {
diff --git a/include/linux/bio-crypt-ctx.h b/include/linux/bio-crypt-ctx.h
index 8456a409fc21..9df113f74e9e 100644
--- a/include/linux/bio-crypt-ctx.h
+++ b/include/linux/bio-crypt-ctx.h
@@ -43,7 +43,15 @@ struct blk_crypto_key {
unsigned int data_unit_size;
unsigned int data_unit_size_bits;
unsigned int size;
+
+ /*
+ * Hack to avoid breaking KMI: pack both hash and dun_bytes into the
+ * hash field...
+ */
+#define BLK_CRYPTO_KEY_HASH_MASK 0xffffff
+#define BLK_CRYPTO_KEY_DUN_BYTES_SHIFT 24
unsigned int hash;
+
bool is_hw_wrapped;
u8 raw[BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE];
};
@@ -51,6 +59,26 @@ struct blk_crypto_key {
#define BLK_CRYPTO_MAX_IV_SIZE 32
#define BLK_CRYPTO_DUN_ARRAY_SIZE (BLK_CRYPTO_MAX_IV_SIZE/sizeof(u64))
+static inline void
+blk_crypto_key_set_hash_and_dun_bytes(struct blk_crypto_key *key,
+ u32 hash, unsigned int dun_bytes)
+{
+ key->hash = (dun_bytes << BLK_CRYPTO_KEY_DUN_BYTES_SHIFT) |
+ (hash & BLK_CRYPTO_KEY_HASH_MASK);
+}
+
+static inline u32
+blk_crypto_key_hash(const struct blk_crypto_key *key)
+{
+ return key->hash & BLK_CRYPTO_KEY_HASH_MASK;
+}
+
+static inline unsigned int
+blk_crypto_key_dun_bytes(const struct blk_crypto_key *key)
+{
+ return key->hash >> BLK_CRYPTO_KEY_DUN_BYTES_SHIFT;
+}
+
/**
* struct bio_crypt_ctx - an inline encryption context
* @bc_key: the key, algorithm, and data unit size to use
diff --git a/include/linux/blk-crypto.h b/include/linux/blk-crypto.h
index 7dc478a8c3ed..6062002555e1 100644
--- a/include/linux/blk-crypto.h
+++ b/include/linux/blk-crypto.h
@@ -20,9 +20,11 @@ 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 dun_bytes,
unsigned int data_unit_size);
int blk_crypto_start_using_mode(enum blk_crypto_mode_num crypto_mode,
+ unsigned int dun_bytes,
unsigned int data_unit_size,
bool is_hw_wrapped_key,
struct request_queue *q);
diff --git a/include/linux/keyslot-manager.h b/include/linux/keyslot-manager.h
index cd65bea927db..f5e0eed468b0 100644
--- a/include/linux/keyslot-manager.h
+++ b/include/linux/keyslot-manager.h
@@ -58,6 +58,9 @@ struct keyslot_manager *keyslot_manager_create(
const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX],
void *ll_priv_data);
+void keyslot_manager_set_max_dun_bytes(struct keyslot_manager *ksm,
+ unsigned int max_dun_bytes);
+
int keyslot_manager_get_slot_for_key(struct keyslot_manager *ksm,
const struct blk_crypto_key *key);
@@ -67,6 +70,7 @@ void keyslot_manager_put_slot(struct keyslot_manager *ksm, unsigned int slot);
bool keyslot_manager_crypto_mode_supported(struct keyslot_manager *ksm,
enum blk_crypto_mode_num crypto_mode,
+ unsigned int dun_bytes,
unsigned int data_unit_size,
bool is_hw_wrapped_key);