wusb: Stop using the stack for sg crypto scratch space
Pointing an sg list at the stack is verboten and, with CONFIG_VMAP_STACK=y, will malfunction. Use kmalloc for the wusb crypto stack space instead. Untested -- I'm not entirely convinced that this hardware exists in the wild. Signed-off-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
1001354ca3
commit
a19b882c07
|
@ -133,6 +133,13 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
|
||||||
bo[itr] = bi1[itr] ^ bi2[itr];
|
bo[itr] = bi1[itr] ^ bi2[itr];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Scratch space for MAC calculations. */
|
||||||
|
struct wusb_mac_scratch {
|
||||||
|
struct aes_ccm_b0 b0;
|
||||||
|
struct aes_ccm_b1 b1;
|
||||||
|
struct aes_ccm_a ax;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CC-MAC function WUSB1.0[6.5]
|
* CC-MAC function WUSB1.0[6.5]
|
||||||
*
|
*
|
||||||
|
@ -197,16 +204,15 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
|
||||||
* what sg[4] is for. Maybe there is a smarter way to do this.
|
* what sg[4] is for. Maybe there is a smarter way to do this.
|
||||||
*/
|
*/
|
||||||
static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
|
static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
|
||||||
struct crypto_cipher *tfm_aes, void *mic,
|
struct crypto_cipher *tfm_aes,
|
||||||
|
struct wusb_mac_scratch *scratch,
|
||||||
|
void *mic,
|
||||||
const struct aes_ccm_nonce *n,
|
const struct aes_ccm_nonce *n,
|
||||||
const struct aes_ccm_label *a, const void *b,
|
const struct aes_ccm_label *a, const void *b,
|
||||||
size_t blen)
|
size_t blen)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc);
|
SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc);
|
||||||
struct aes_ccm_b0 b0;
|
|
||||||
struct aes_ccm_b1 b1;
|
|
||||||
struct aes_ccm_a ax;
|
|
||||||
struct scatterlist sg[4], sg_dst;
|
struct scatterlist sg[4], sg_dst;
|
||||||
void *dst_buf;
|
void *dst_buf;
|
||||||
size_t dst_size;
|
size_t dst_size;
|
||||||
|
@ -218,16 +224,17 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
|
||||||
* These checks should be compile time optimized out
|
* These checks should be compile time optimized out
|
||||||
* ensure @a fills b1's mac_header and following fields
|
* ensure @a fills b1's mac_header and following fields
|
||||||
*/
|
*/
|
||||||
WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la));
|
WARN_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
|
||||||
WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block));
|
WARN_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
|
||||||
WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block));
|
WARN_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
|
||||||
WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block));
|
WARN_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));
|
||||||
|
|
||||||
result = -ENOMEM;
|
result = -ENOMEM;
|
||||||
zero_padding = blen % sizeof(struct aes_ccm_block);
|
zero_padding = blen % sizeof(struct aes_ccm_block);
|
||||||
if (zero_padding)
|
if (zero_padding)
|
||||||
zero_padding = sizeof(struct aes_ccm_block) - zero_padding;
|
zero_padding = sizeof(struct aes_ccm_block) - zero_padding;
|
||||||
dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding;
|
dst_size = blen + sizeof(scratch->b0) + sizeof(scratch->b1) +
|
||||||
|
zero_padding;
|
||||||
dst_buf = kzalloc(dst_size, GFP_KERNEL);
|
dst_buf = kzalloc(dst_size, GFP_KERNEL);
|
||||||
if (!dst_buf)
|
if (!dst_buf)
|
||||||
goto error_dst_buf;
|
goto error_dst_buf;
|
||||||
|
@ -235,9 +242,9 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
|
||||||
memset(iv, 0, sizeof(iv));
|
memset(iv, 0, sizeof(iv));
|
||||||
|
|
||||||
/* Setup B0 */
|
/* Setup B0 */
|
||||||
b0.flags = 0x59; /* Format B0 */
|
scratch->b0.flags = 0x59; /* Format B0 */
|
||||||
b0.ccm_nonce = *n;
|
scratch->b0.ccm_nonce = *n;
|
||||||
b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */
|
scratch->b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */
|
||||||
|
|
||||||
/* Setup B1
|
/* Setup B1
|
||||||
*
|
*
|
||||||
|
@ -246,12 +253,12 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
|
||||||
* 14'--after clarification, it means to use A's contents
|
* 14'--after clarification, it means to use A's contents
|
||||||
* for MAC Header, EO, sec reserved and padding.
|
* for MAC Header, EO, sec reserved and padding.
|
||||||
*/
|
*/
|
||||||
b1.la = cpu_to_be16(blen + 14);
|
scratch->b1.la = cpu_to_be16(blen + 14);
|
||||||
memcpy(&b1.mac_header, a, sizeof(*a));
|
memcpy(&scratch->b1.mac_header, a, sizeof(*a));
|
||||||
|
|
||||||
sg_init_table(sg, ARRAY_SIZE(sg));
|
sg_init_table(sg, ARRAY_SIZE(sg));
|
||||||
sg_set_buf(&sg[0], &b0, sizeof(b0));
|
sg_set_buf(&sg[0], &scratch->b0, sizeof(scratch->b0));
|
||||||
sg_set_buf(&sg[1], &b1, sizeof(b1));
|
sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1));
|
||||||
sg_set_buf(&sg[2], b, blen);
|
sg_set_buf(&sg[2], b, blen);
|
||||||
/* 0 if well behaved :) */
|
/* 0 if well behaved :) */
|
||||||
sg_set_buf(&sg[3], bzero, zero_padding);
|
sg_set_buf(&sg[3], bzero, zero_padding);
|
||||||
|
@ -276,11 +283,12 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
|
||||||
* POS Crypto API: size is assumed to be AES's block size.
|
* POS Crypto API: size is assumed to be AES's block size.
|
||||||
* Thanks for documenting it -- tip taken from airo.c
|
* Thanks for documenting it -- tip taken from airo.c
|
||||||
*/
|
*/
|
||||||
ax.flags = 0x01; /* as per WUSB 1.0 spec */
|
scratch->ax.flags = 0x01; /* as per WUSB 1.0 spec */
|
||||||
ax.ccm_nonce = *n;
|
scratch->ax.ccm_nonce = *n;
|
||||||
ax.counter = 0;
|
scratch->ax.counter = 0;
|
||||||
crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax);
|
crypto_cipher_encrypt_one(tfm_aes, (void *)&scratch->ax,
|
||||||
bytewise_xor(mic, &ax, iv, 8);
|
(void *)&scratch->ax);
|
||||||
|
bytewise_xor(mic, &scratch->ax, iv, 8);
|
||||||
result = 8;
|
result = 8;
|
||||||
error_cbc_crypt:
|
error_cbc_crypt:
|
||||||
kfree(dst_buf);
|
kfree(dst_buf);
|
||||||
|
@ -303,6 +311,7 @@ ssize_t wusb_prf(void *out, size_t out_size,
|
||||||
struct aes_ccm_nonce n = *_n;
|
struct aes_ccm_nonce n = *_n;
|
||||||
struct crypto_skcipher *tfm_cbc;
|
struct crypto_skcipher *tfm_cbc;
|
||||||
struct crypto_cipher *tfm_aes;
|
struct crypto_cipher *tfm_aes;
|
||||||
|
struct wusb_mac_scratch *scratch;
|
||||||
u64 sfn = 0;
|
u64 sfn = 0;
|
||||||
__le64 sfn_le;
|
__le64 sfn_le;
|
||||||
|
|
||||||
|
@ -329,17 +338,23 @@ ssize_t wusb_prf(void *out, size_t out_size,
|
||||||
printk(KERN_ERR "E: can't set AES key: %d\n", (int)result);
|
printk(KERN_ERR "E: can't set AES key: %d\n", (int)result);
|
||||||
goto error_setkey_aes;
|
goto error_setkey_aes;
|
||||||
}
|
}
|
||||||
|
scratch = kmalloc(sizeof(*scratch), GFP_KERNEL);
|
||||||
|
if (!scratch)
|
||||||
|
goto error_alloc_scratch;
|
||||||
|
|
||||||
for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
|
for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
|
||||||
sfn_le = cpu_to_le64(sfn++);
|
sfn_le = cpu_to_le64(sfn++);
|
||||||
memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */
|
memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */
|
||||||
result = wusb_ccm_mac(tfm_cbc, tfm_aes, out + bytes,
|
result = wusb_ccm_mac(tfm_cbc, tfm_aes, scratch, out + bytes,
|
||||||
&n, a, b, blen);
|
&n, a, b, blen);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
goto error_ccm_mac;
|
goto error_ccm_mac;
|
||||||
bytes += result;
|
bytes += result;
|
||||||
}
|
}
|
||||||
result = bytes;
|
result = bytes;
|
||||||
|
|
||||||
|
kfree(scratch);
|
||||||
|
error_alloc_scratch:
|
||||||
error_ccm_mac:
|
error_ccm_mac:
|
||||||
error_setkey_aes:
|
error_setkey_aes:
|
||||||
crypto_free_cipher(tfm_aes);
|
crypto_free_cipher(tfm_aes);
|
||||||
|
|
Loading…
Reference in New Issue