Commit fd8c37c7 authored by Eric Biggers's avatar Eric Biggers Committed by Herbert Xu

crypto: testmgr - test setting misaligned keys

The alignment bug in ghash_setkey() fixed by commit 5c6bc4df
("crypto: ghash - fix unaligned memory access in ghash_setkey()")
wasn't reliably detected by the crypto self-tests on ARM because the
tests only set the keys directly from the test vectors.

To improve test coverage, update the tests to sometimes pass misaligned
keys to setkey().  This applies to shash, ahash, skcipher, and aead.
Signed-off-by: default avatarEric Biggers <ebiggers@google.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent fd60f727
...@@ -259,6 +259,9 @@ struct test_sg_division { ...@@ -259,6 +259,9 @@ struct test_sg_division {
* where 0 is aligned to a 2*(MAX_ALGAPI_ALIGNMASK+1) byte boundary * where 0 is aligned to a 2*(MAX_ALGAPI_ALIGNMASK+1) byte boundary
* @iv_offset_relative_to_alignmask: if true, add the algorithm's alignmask to * @iv_offset_relative_to_alignmask: if true, add the algorithm's alignmask to
* the @iv_offset * the @iv_offset
* @key_offset: misalignment of the key, where 0 is default alignment
* @key_offset_relative_to_alignmask: if true, add the algorithm's alignmask to
* the @key_offset
* @finalization_type: what finalization function to use for hashes * @finalization_type: what finalization function to use for hashes
* @nosimd: execute with SIMD disabled? Requires !CRYPTO_TFM_REQ_MAY_SLEEP. * @nosimd: execute with SIMD disabled? Requires !CRYPTO_TFM_REQ_MAY_SLEEP.
*/ */
...@@ -269,7 +272,9 @@ struct testvec_config { ...@@ -269,7 +272,9 @@ struct testvec_config {
struct test_sg_division src_divs[XBUFSIZE]; struct test_sg_division src_divs[XBUFSIZE];
struct test_sg_division dst_divs[XBUFSIZE]; struct test_sg_division dst_divs[XBUFSIZE];
unsigned int iv_offset; unsigned int iv_offset;
unsigned int key_offset;
bool iv_offset_relative_to_alignmask; bool iv_offset_relative_to_alignmask;
bool key_offset_relative_to_alignmask;
enum finalization_type finalization_type; enum finalization_type finalization_type;
bool nosimd; bool nosimd;
}; };
...@@ -297,6 +302,7 @@ static const struct testvec_config default_cipher_testvec_configs[] = { ...@@ -297,6 +302,7 @@ static const struct testvec_config default_cipher_testvec_configs[] = {
.name = "unaligned buffer, offset=1", .name = "unaligned buffer, offset=1",
.src_divs = { { .proportion_of_total = 10000, .offset = 1 } }, .src_divs = { { .proportion_of_total = 10000, .offset = 1 } },
.iv_offset = 1, .iv_offset = 1,
.key_offset = 1,
}, { }, {
.name = "buffer aligned only to alignmask", .name = "buffer aligned only to alignmask",
.src_divs = { .src_divs = {
...@@ -308,6 +314,8 @@ static const struct testvec_config default_cipher_testvec_configs[] = { ...@@ -308,6 +314,8 @@ static const struct testvec_config default_cipher_testvec_configs[] = {
}, },
.iv_offset = 1, .iv_offset = 1,
.iv_offset_relative_to_alignmask = true, .iv_offset_relative_to_alignmask = true,
.key_offset = 1,
.key_offset_relative_to_alignmask = true,
}, { }, {
.name = "two even aligned splits", .name = "two even aligned splits",
.src_divs = { .src_divs = {
...@@ -323,6 +331,7 @@ static const struct testvec_config default_cipher_testvec_configs[] = { ...@@ -323,6 +331,7 @@ static const struct testvec_config default_cipher_testvec_configs[] = {
{ .proportion_of_total = 4800, .offset = 18 }, { .proportion_of_total = 4800, .offset = 18 },
}, },
.iv_offset = 3, .iv_offset = 3,
.key_offset = 3,
}, { }, {
.name = "misaligned splits crossing pages, inplace", .name = "misaligned splits crossing pages, inplace",
.inplace = true, .inplace = true,
...@@ -355,6 +364,7 @@ static const struct testvec_config default_hash_testvec_configs[] = { ...@@ -355,6 +364,7 @@ static const struct testvec_config default_hash_testvec_configs[] = {
.name = "init+update+final misaligned buffer", .name = "init+update+final misaligned buffer",
.src_divs = { { .proportion_of_total = 10000, .offset = 1 } }, .src_divs = { { .proportion_of_total = 10000, .offset = 1 } },
.finalization_type = FINALIZATION_TYPE_FINAL, .finalization_type = FINALIZATION_TYPE_FINAL,
.key_offset = 1,
}, { }, {
.name = "digest buffer aligned only to alignmask", .name = "digest buffer aligned only to alignmask",
.src_divs = { .src_divs = {
...@@ -365,6 +375,8 @@ static const struct testvec_config default_hash_testvec_configs[] = { ...@@ -365,6 +375,8 @@ static const struct testvec_config default_hash_testvec_configs[] = {
}, },
}, },
.finalization_type = FINALIZATION_TYPE_DIGEST, .finalization_type = FINALIZATION_TYPE_DIGEST,
.key_offset = 1,
.key_offset_relative_to_alignmask = true,
}, { }, {
.name = "init+update+update+final two even splits", .name = "init+update+update+final two even splits",
.src_divs = { .src_divs = {
...@@ -740,6 +752,49 @@ static int build_cipher_test_sglists(struct cipher_test_sglists *tsgls, ...@@ -740,6 +752,49 @@ static int build_cipher_test_sglists(struct cipher_test_sglists *tsgls,
alignmask, dst_total_len, NULL, NULL); alignmask, dst_total_len, NULL, NULL);
} }
/*
* Support for testing passing a misaligned key to setkey():
*
* If cfg->key_offset is set, copy the key into a new buffer at that offset,
* optionally adding alignmask. Else, just use the key directly.
*/
static int prepare_keybuf(const u8 *key, unsigned int ksize,
const struct testvec_config *cfg,
unsigned int alignmask,
const u8 **keybuf_ret, const u8 **keyptr_ret)
{
unsigned int key_offset = cfg->key_offset;
u8 *keybuf = NULL, *keyptr = (u8 *)key;
if (key_offset != 0) {
if (cfg->key_offset_relative_to_alignmask)
key_offset += alignmask;
keybuf = kmalloc(key_offset + ksize, GFP_KERNEL);
if (!keybuf)
return -ENOMEM;
keyptr = keybuf + key_offset;
memcpy(keyptr, key, ksize);
}
*keybuf_ret = keybuf;
*keyptr_ret = keyptr;
return 0;
}
/* Like setkey_f(tfm, key, ksize), but sometimes misalign the key */
#define do_setkey(setkey_f, tfm, key, ksize, cfg, alignmask) \
({ \
const u8 *keybuf, *keyptr; \
int err; \
\
err = prepare_keybuf((key), (ksize), (cfg), (alignmask), \
&keybuf, &keyptr); \
if (err == 0) { \
err = setkey_f((tfm), keyptr, (ksize)); \
kfree(keybuf); \
} \
err; \
})
#ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS #ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
/* Generate a random length in range [0, max_len], but prefer smaller values */ /* Generate a random length in range [0, max_len], but prefer smaller values */
...@@ -966,6 +1021,11 @@ static void generate_random_testvec_config(struct testvec_config *cfg, ...@@ -966,6 +1021,11 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
p += scnprintf(p, end - p, " iv_offset=%u", cfg->iv_offset); p += scnprintf(p, end - p, " iv_offset=%u", cfg->iv_offset);
} }
if (prandom_u32() % 2 == 0) {
cfg->key_offset = 1 + (prandom_u32() % MAX_ALGAPI_ALIGNMASK);
p += scnprintf(p, end - p, " key_offset=%u", cfg->key_offset);
}
WARN_ON_ONCE(!valid_testvec_config(cfg)); WARN_ON_ONCE(!valid_testvec_config(cfg));
} }
...@@ -1103,7 +1163,8 @@ static int test_shash_vec_cfg(const char *driver, ...@@ -1103,7 +1163,8 @@ static int test_shash_vec_cfg(const char *driver,
/* Set the key, if specified */ /* Set the key, if specified */
if (vec->ksize) { if (vec->ksize) {
err = crypto_shash_setkey(tfm, vec->key, vec->ksize); err = do_setkey(crypto_shash_setkey, tfm, vec->key, vec->ksize,
cfg, alignmask);
if (err) { if (err) {
if (err == vec->setkey_error) if (err == vec->setkey_error)
return 0; return 0;
...@@ -1290,7 +1351,8 @@ static int test_ahash_vec_cfg(const char *driver, ...@@ -1290,7 +1351,8 @@ static int test_ahash_vec_cfg(const char *driver,
/* Set the key, if specified */ /* Set the key, if specified */
if (vec->ksize) { if (vec->ksize) {
err = crypto_ahash_setkey(tfm, vec->key, vec->ksize); err = do_setkey(crypto_ahash_setkey, tfm, vec->key, vec->ksize,
cfg, alignmask);
if (err) { if (err) {
if (err == vec->setkey_error) if (err == vec->setkey_error)
return 0; return 0;
...@@ -1861,7 +1923,9 @@ static int test_aead_vec_cfg(const char *driver, int enc, ...@@ -1861,7 +1923,9 @@ static int test_aead_vec_cfg(const char *driver, int enc,
crypto_aead_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); crypto_aead_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
else else
crypto_aead_clear_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); crypto_aead_clear_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
err = crypto_aead_setkey(tfm, vec->key, vec->klen);
err = do_setkey(crypto_aead_setkey, tfm, vec->key, vec->klen,
cfg, alignmask);
if (err && err != vec->setkey_error) { if (err && err != vec->setkey_error) {
pr_err("alg: aead: %s setkey failed on test vector %s; expected_error=%d, actual_error=%d, flags=%#x\n", pr_err("alg: aead: %s setkey failed on test vector %s; expected_error=%d, actual_error=%d, flags=%#x\n",
driver, vec_name, vec->setkey_error, err, driver, vec_name, vec->setkey_error, err,
...@@ -2460,7 +2524,8 @@ static int test_skcipher_vec_cfg(const char *driver, int enc, ...@@ -2460,7 +2524,8 @@ static int test_skcipher_vec_cfg(const char *driver, int enc,
else else
crypto_skcipher_clear_flags(tfm, crypto_skcipher_clear_flags(tfm,
CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
err = crypto_skcipher_setkey(tfm, vec->key, vec->klen); err = do_setkey(crypto_skcipher_setkey, tfm, vec->key, vec->klen,
cfg, alignmask);
if (err) { if (err) {
if (err == vec->setkey_error) if (err == vec->setkey_error)
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment