Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a19b882c authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Greg Kroah-Hartman
Browse files

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: default avatarAndy Lutomirski <luto@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1001354c
Loading
Loading
Loading
Loading
+37 −22
Original line number Diff line number Diff line
@@ -133,6 +133,13 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
		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]
 *
@@ -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.
 */
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_label *a, const void *b,
			size_t blen)
{
	int result = 0;
	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;
	void *dst_buf;
	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
	 * ensure @a fills b1's mac_header and following fields
	 */
	WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la));
	WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block));
	WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block));
	WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block));
	WARN_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
	WARN_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
	WARN_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
	WARN_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));

	result = -ENOMEM;
	zero_padding = blen % sizeof(struct aes_ccm_block);
	if (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);
	if (!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));

	/* Setup B0 */
	b0.flags = 0x59;	/* Format B0 */
	b0.ccm_nonce = *n;
	b0.lm = cpu_to_be16(0);	/* WUSB1.0[6.5] sez l(m) is 0 */
	scratch->b0.flags = 0x59;	/* Format B0 */
	scratch->b0.ccm_nonce = *n;
	scratch->b0.lm = cpu_to_be16(0);	/* WUSB1.0[6.5] sez l(m) is 0 */

	/* 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
	 * for MAC Header, EO, sec reserved and padding.
	 */
	b1.la = cpu_to_be16(blen + 14);
	memcpy(&b1.mac_header, a, sizeof(*a));
	scratch->b1.la = cpu_to_be16(blen + 14);
	memcpy(&scratch->b1.mac_header, a, sizeof(*a));

	sg_init_table(sg, ARRAY_SIZE(sg));
	sg_set_buf(&sg[0], &b0, sizeof(b0));
	sg_set_buf(&sg[1], &b1, sizeof(b1));
	sg_set_buf(&sg[0], &scratch->b0, sizeof(scratch->b0));
	sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1));
	sg_set_buf(&sg[2], b, blen);
	/* 0 if well behaved :) */
	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.
	 * Thanks for documenting it -- tip taken from airo.c
	 */
	ax.flags = 0x01;		/* as per WUSB 1.0 spec */
	ax.ccm_nonce = *n;
	ax.counter = 0;
	crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax);
	bytewise_xor(mic, &ax, iv, 8);
	scratch->ax.flags = 0x01;		/* as per WUSB 1.0 spec */
	scratch->ax.ccm_nonce = *n;
	scratch->ax.counter = 0;
	crypto_cipher_encrypt_one(tfm_aes, (void *)&scratch->ax,
				  (void *)&scratch->ax);
	bytewise_xor(mic, &scratch->ax, iv, 8);
	result = 8;
error_cbc_crypt:
	kfree(dst_buf);
@@ -303,6 +311,7 @@ ssize_t wusb_prf(void *out, size_t out_size,
	struct aes_ccm_nonce n = *_n;
	struct crypto_skcipher *tfm_cbc;
	struct crypto_cipher *tfm_aes;
	struct wusb_mac_scratch *scratch;
	u64 sfn = 0;
	__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);
		goto error_setkey_aes;
	}
	scratch = kmalloc(sizeof(*scratch), GFP_KERNEL);
	if (!scratch)
		goto error_alloc_scratch;

	for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
		sfn_le = cpu_to_le64(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);
		if (result < 0)
			goto error_ccm_mac;
		bytes += result;
	}
	result = bytes;

	kfree(scratch);
error_alloc_scratch:
error_ccm_mac:
error_setkey_aes:
	crypto_free_cipher(tfm_aes);