| 
									
										
										
										
											2019-05-27 08:55:01 +02:00
										 |  |  | // SPDX-License-Identifier: GPL-2.0-or-later
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Cryptographic API. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * HMAC: Keyed-Hashing for Message Authentication (RFC2104). | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  |  * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * The HMAC implementation is derived from USAGI. | 
					
						
							|  |  |  |  * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 08:53:23 +02:00
										 |  |  | #include <crypto/hmac.h>
 | 
					
						
							| 
									
										
										
										
											2008-08-31 22:21:09 +10:00
										 |  |  | #include <crypto/internal/hash.h>
 | 
					
						
							| 
									
										
										
										
											2007-12-05 20:59:25 +11:00
										 |  |  | #include <crypto/scatterwalk.h>
 | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | #include <linux/err.h>
 | 
					
						
							| 
									
										
										
										
											2022-02-01 09:41:32 +01:00
										 |  |  | #include <linux/fips.h>
 | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							| 
									
										
										
										
											2005-09-17 17:55:31 +10:00
										 |  |  | #include <linux/scatterlist.h>
 | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | #include <linux/string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct hmac_ctx { | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	struct crypto_shash *hash; | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	/* Contains 'u8 ipad[statesize];', then 'u8 opad[statesize];' */ | 
					
						
							|  |  |  | 	u8 pads[]; | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | static int hmac_setkey(struct crypto_shash *parent, | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 		       const u8 *inkey, unsigned int keylen) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	int bs = crypto_shash_blocksize(parent); | 
					
						
							|  |  |  | 	int ds = crypto_shash_digestsize(parent); | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	int ss = crypto_shash_statesize(parent); | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	struct hmac_ctx *tctx = crypto_shash_ctx(parent); | 
					
						
							|  |  |  | 	struct crypto_shash *hash = tctx->hash; | 
					
						
							|  |  |  | 	u8 *ipad = &tctx->pads[0]; | 
					
						
							|  |  |  | 	u8 *opad = &tctx->pads[ss]; | 
					
						
							| 
									
										
										
										
											2012-07-02 13:47:40 +02:00
										 |  |  | 	SHASH_DESC_ON_STACK(shash, hash); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-01 09:41:32 +01:00
										 |  |  | 	if (fips_enabled && (keylen < 112 / 8)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-02 13:47:40 +02:00
										 |  |  | 	shash->tfm = hash; | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 	if (keylen > bs) { | 
					
						
							|  |  |  | 		int err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-02 13:47:40 +02:00
										 |  |  | 		err = crypto_shash_digest(shash, inkey, keylen, ipad); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 		if (err) | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		keylen = ds; | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	} else | 
					
						
							|  |  |  | 		memcpy(ipad, inkey, keylen); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	memset(ipad + keylen, 0, bs - keylen); | 
					
						
							|  |  |  | 	memcpy(opad, ipad, bs); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < bs; i++) { | 
					
						
							| 
									
										
										
										
											2017-05-19 08:53:23 +02:00
										 |  |  | 		ipad[i] ^= HMAC_IPAD_VALUE; | 
					
						
							|  |  |  | 		opad[i] ^= HMAC_OPAD_VALUE; | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-02 13:47:40 +02:00
										 |  |  | 	return crypto_shash_init(shash) ?: | 
					
						
							|  |  |  | 	       crypto_shash_update(shash, ipad, bs) ?: | 
					
						
							|  |  |  | 	       crypto_shash_export(shash, ipad) ?: | 
					
						
							|  |  |  | 	       crypto_shash_init(shash) ?: | 
					
						
							|  |  |  | 	       crypto_shash_update(shash, opad, bs) ?: | 
					
						
							|  |  |  | 	       crypto_shash_export(shash, opad); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | static int hmac_export(struct shash_desc *pdesc, void *out) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct shash_desc *desc = shash_desc_ctx(pdesc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return crypto_shash_export(desc, out); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int hmac_import(struct shash_desc *pdesc, const void *in) | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	struct shash_desc *desc = shash_desc_ctx(pdesc); | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	const struct hmac_ctx *tctx = crypto_shash_ctx(pdesc->tfm); | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	desc->tfm = tctx->hash; | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	return crypto_shash_import(desc, in); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int hmac_init(struct shash_desc *pdesc) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	const struct hmac_ctx *tctx = crypto_shash_ctx(pdesc->tfm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return hmac_import(pdesc, &tctx->pads[0]); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | static int hmac_update(struct shash_desc *pdesc, | 
					
						
							|  |  |  | 		       const u8 *data, unsigned int nbytes) | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	struct shash_desc *desc = shash_desc_ctx(pdesc); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	return crypto_shash_update(desc, data, nbytes); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | static int hmac_final(struct shash_desc *pdesc, u8 *out) | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	struct crypto_shash *parent = pdesc->tfm; | 
					
						
							|  |  |  | 	int ds = crypto_shash_digestsize(parent); | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	int ss = crypto_shash_statesize(parent); | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	const struct hmac_ctx *tctx = crypto_shash_ctx(parent); | 
					
						
							|  |  |  | 	const u8 *opad = &tctx->pads[ss]; | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	struct shash_desc *desc = shash_desc_ctx(pdesc); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	return crypto_shash_final(desc, out) ?: | 
					
						
							|  |  |  | 	       crypto_shash_import(desc, opad) ?: | 
					
						
							|  |  |  | 	       crypto_shash_finup(desc, out, ds, out); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | static int hmac_finup(struct shash_desc *pdesc, const u8 *data, | 
					
						
							|  |  |  | 		      unsigned int nbytes, u8 *out) | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	struct crypto_shash *parent = pdesc->tfm; | 
					
						
							|  |  |  | 	int ds = crypto_shash_digestsize(parent); | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	int ss = crypto_shash_statesize(parent); | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	const struct hmac_ctx *tctx = crypto_shash_ctx(parent); | 
					
						
							|  |  |  | 	const u8 *opad = &tctx->pads[ss]; | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	struct shash_desc *desc = shash_desc_ctx(pdesc); | 
					
						
							| 
									
										
										
										
											2007-10-22 19:40:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	return crypto_shash_finup(desc, data, nbytes, out) ?: | 
					
						
							|  |  |  | 	       crypto_shash_import(desc, opad) ?: | 
					
						
							|  |  |  | 	       crypto_shash_finup(desc, out, ds, out); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-08 13:42:53 +08:00
										 |  |  | static int hmac_init_tfm(struct crypto_shash *parent) | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	struct crypto_shash *hash; | 
					
						
							| 
									
										
										
										
											2019-12-08 13:42:53 +08:00
										 |  |  | 	struct shash_instance *inst = shash_alg_instance(parent); | 
					
						
							|  |  |  | 	struct crypto_shash_spawn *spawn = shash_instance_ctx(inst); | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	struct hmac_ctx *tctx = crypto_shash_ctx(parent); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	hash = crypto_spawn_shash(spawn); | 
					
						
							| 
									
										
										
										
											2006-12-17 10:05:58 +11:00
										 |  |  | 	if (IS_ERR(hash)) | 
					
						
							|  |  |  | 		return PTR_ERR(hash); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	parent->descsize = sizeof(struct shash_desc) + | 
					
						
							|  |  |  | 			   crypto_shash_descsize(hash); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	tctx->hash = hash; | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-13 14:24:21 +08:00
										 |  |  | static int hmac_clone_tfm(struct crypto_shash *dst, struct crypto_shash *src) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	struct hmac_ctx *sctx = crypto_shash_ctx(src); | 
					
						
							|  |  |  | 	struct hmac_ctx *dctx = crypto_shash_ctx(dst); | 
					
						
							| 
									
										
										
										
											2023-04-13 14:24:21 +08:00
										 |  |  | 	struct crypto_shash *hash; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hash = crypto_clone_shash(sctx->hash); | 
					
						
							|  |  |  | 	if (IS_ERR(hash)) | 
					
						
							|  |  |  | 		return PTR_ERR(hash); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dctx->hash = hash; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-08 13:42:53 +08:00
										 |  |  | static void hmac_exit_tfm(struct crypto_shash *parent) | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	struct hmac_ctx *tctx = crypto_shash_ctx(parent); | 
					
						
							| 
									
										
										
										
											2023-06-06 13:17:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	crypto_free_shash(tctx->hash); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	struct shash_instance *inst; | 
					
						
							| 
									
										
										
										
											2020-01-02 19:58:54 -08:00
										 |  |  | 	struct crypto_shash_spawn *spawn; | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 	struct crypto_alg *alg; | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	struct shash_alg *salg; | 
					
						
							| 
									
										
										
										
											2020-07-09 23:20:38 -07:00
										 |  |  | 	u32 mask; | 
					
						
							| 
									
										
										
										
											2007-01-01 18:37:02 +11:00
										 |  |  | 	int err; | 
					
						
							| 
									
										
										
										
											2008-07-07 20:23:56 +08:00
										 |  |  | 	int ds; | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	int ss; | 
					
						
							| 
									
										
										
										
											2007-01-01 18:37:02 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-09 23:20:38 -07:00
										 |  |  | 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH, &mask); | 
					
						
							| 
									
										
										
										
											2007-01-01 18:37:02 +11:00
										 |  |  | 	if (err) | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 		return err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-02 19:58:54 -08:00
										 |  |  | 	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!inst) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	spawn = shash_instance_ctx(inst); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = crypto_grab_shash(spawn, shash_crypto_instance(inst), | 
					
						
							| 
									
										
										
										
											2020-07-09 23:20:38 -07:00
										 |  |  | 				crypto_attr_alg_name(tb[1]), 0, mask); | 
					
						
							| 
									
										
										
										
											2020-01-02 19:58:54 -08:00
										 |  |  | 	if (err) | 
					
						
							|  |  |  | 		goto err_free_inst; | 
					
						
							|  |  |  | 	salg = crypto_spawn_shash_alg(spawn); | 
					
						
							| 
									
										
											  
											
												crypto: hmac - require that the underlying hash algorithm is unkeyed
Because the HMAC template didn't check that its underlying hash
algorithm is unkeyed, trying to use "hmac(hmac(sha3-512-generic))"
through AF_ALG or through KEYCTL_DH_COMPUTE resulted in the inner HMAC
being used without having been keyed, resulting in sha3_update() being
called without sha3_init(), causing a stack buffer overflow.
This is a very old bug, but it seems to have only started causing real
problems when SHA-3 support was added (requires CONFIG_CRYPTO_SHA3)
because the innermost hash's state is ->import()ed from a zeroed buffer,
and it just so happens that other hash algorithms are fine with that,
but SHA-3 is not.  However, there could be arch or hardware-dependent
hash algorithms also affected; I couldn't test everything.
Fix the bug by introducing a function crypto_shash_alg_has_setkey()
which tests whether a shash algorithm is keyed.  Then update the HMAC
template to require that its underlying hash algorithm is unkeyed.
Here is a reproducer:
    #include <linux/if_alg.h>
    #include <sys/socket.h>
    int main()
    {
        int algfd;
        struct sockaddr_alg addr = {
            .salg_type = "hash",
            .salg_name = "hmac(hmac(sha3-512-generic))",
        };
        char key[4096] = { 0 };
        algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
        bind(algfd, (const struct sockaddr *)&addr, sizeof(addr));
        setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, sizeof(key));
    }
Here was the KASAN report from syzbot:
    BUG: KASAN: stack-out-of-bounds in memcpy include/linux/string.h:341  [inline]
    BUG: KASAN: stack-out-of-bounds in sha3_update+0xdf/0x2e0  crypto/sha3_generic.c:161
    Write of size 4096 at addr ffff8801cca07c40 by task syzkaller076574/3044
    CPU: 1 PID: 3044 Comm: syzkaller076574 Not tainted 4.14.0-mm1+ #25
    Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS  Google 01/01/2011
    Call Trace:
      __dump_stack lib/dump_stack.c:17 [inline]
      dump_stack+0x194/0x257 lib/dump_stack.c:53
      print_address_description+0x73/0x250 mm/kasan/report.c:252
      kasan_report_error mm/kasan/report.c:351 [inline]
      kasan_report+0x25b/0x340 mm/kasan/report.c:409
      check_memory_region_inline mm/kasan/kasan.c:260 [inline]
      check_memory_region+0x137/0x190 mm/kasan/kasan.c:267
      memcpy+0x37/0x50 mm/kasan/kasan.c:303
      memcpy include/linux/string.h:341 [inline]
      sha3_update+0xdf/0x2e0 crypto/sha3_generic.c:161
      crypto_shash_update+0xcb/0x220 crypto/shash.c:109
      shash_finup_unaligned+0x2a/0x60 crypto/shash.c:151
      crypto_shash_finup+0xc4/0x120 crypto/shash.c:165
      hmac_finup+0x182/0x330 crypto/hmac.c:152
      crypto_shash_finup+0xc4/0x120 crypto/shash.c:165
      shash_digest_unaligned+0x9e/0xd0 crypto/shash.c:172
      crypto_shash_digest+0xc4/0x120 crypto/shash.c:186
      hmac_setkey+0x36a/0x690 crypto/hmac.c:66
      crypto_shash_setkey+0xad/0x190 crypto/shash.c:64
      shash_async_setkey+0x47/0x60 crypto/shash.c:207
      crypto_ahash_setkey+0xaf/0x180 crypto/ahash.c:200
      hash_setkey+0x40/0x90 crypto/algif_hash.c:446
      alg_setkey crypto/af_alg.c:221 [inline]
      alg_setsockopt+0x2a1/0x350 crypto/af_alg.c:254
      SYSC_setsockopt net/socket.c:1851 [inline]
      SyS_setsockopt+0x189/0x360 net/socket.c:1830
      entry_SYSCALL_64_fastpath+0x1f/0x96
Reported-by: syzbot <syzkaller@googlegroups.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
											
										 
											2017-11-28 18:01:38 -08:00
										 |  |  | 	alg = &salg->base; | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-29 11:35:22 -08:00
										 |  |  | 	/* The underlying hash algorithm must not require a key */ | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	err = -EINVAL; | 
					
						
							| 
									
										
										
										
											2019-11-29 11:35:22 -08:00
										 |  |  | 	if (crypto_shash_alg_needs_key(salg)) | 
					
						
							| 
									
										
										
										
											2020-01-02 19:58:54 -08:00
										 |  |  | 		goto err_free_inst; | 
					
						
							| 
									
										
											  
											
												crypto: hmac - require that the underlying hash algorithm is unkeyed
Because the HMAC template didn't check that its underlying hash
algorithm is unkeyed, trying to use "hmac(hmac(sha3-512-generic))"
through AF_ALG or through KEYCTL_DH_COMPUTE resulted in the inner HMAC
being used without having been keyed, resulting in sha3_update() being
called without sha3_init(), causing a stack buffer overflow.
This is a very old bug, but it seems to have only started causing real
problems when SHA-3 support was added (requires CONFIG_CRYPTO_SHA3)
because the innermost hash's state is ->import()ed from a zeroed buffer,
and it just so happens that other hash algorithms are fine with that,
but SHA-3 is not.  However, there could be arch or hardware-dependent
hash algorithms also affected; I couldn't test everything.
Fix the bug by introducing a function crypto_shash_alg_has_setkey()
which tests whether a shash algorithm is keyed.  Then update the HMAC
template to require that its underlying hash algorithm is unkeyed.
Here is a reproducer:
    #include <linux/if_alg.h>
    #include <sys/socket.h>
    int main()
    {
        int algfd;
        struct sockaddr_alg addr = {
            .salg_type = "hash",
            .salg_name = "hmac(hmac(sha3-512-generic))",
        };
        char key[4096] = { 0 };
        algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
        bind(algfd, (const struct sockaddr *)&addr, sizeof(addr));
        setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, sizeof(key));
    }
Here was the KASAN report from syzbot:
    BUG: KASAN: stack-out-of-bounds in memcpy include/linux/string.h:341  [inline]
    BUG: KASAN: stack-out-of-bounds in sha3_update+0xdf/0x2e0  crypto/sha3_generic.c:161
    Write of size 4096 at addr ffff8801cca07c40 by task syzkaller076574/3044
    CPU: 1 PID: 3044 Comm: syzkaller076574 Not tainted 4.14.0-mm1+ #25
    Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS  Google 01/01/2011
    Call Trace:
      __dump_stack lib/dump_stack.c:17 [inline]
      dump_stack+0x194/0x257 lib/dump_stack.c:53
      print_address_description+0x73/0x250 mm/kasan/report.c:252
      kasan_report_error mm/kasan/report.c:351 [inline]
      kasan_report+0x25b/0x340 mm/kasan/report.c:409
      check_memory_region_inline mm/kasan/kasan.c:260 [inline]
      check_memory_region+0x137/0x190 mm/kasan/kasan.c:267
      memcpy+0x37/0x50 mm/kasan/kasan.c:303
      memcpy include/linux/string.h:341 [inline]
      sha3_update+0xdf/0x2e0 crypto/sha3_generic.c:161
      crypto_shash_update+0xcb/0x220 crypto/shash.c:109
      shash_finup_unaligned+0x2a/0x60 crypto/shash.c:151
      crypto_shash_finup+0xc4/0x120 crypto/shash.c:165
      hmac_finup+0x182/0x330 crypto/hmac.c:152
      crypto_shash_finup+0xc4/0x120 crypto/shash.c:165
      shash_digest_unaligned+0x9e/0xd0 crypto/shash.c:172
      crypto_shash_digest+0xc4/0x120 crypto/shash.c:186
      hmac_setkey+0x36a/0x690 crypto/hmac.c:66
      crypto_shash_setkey+0xad/0x190 crypto/shash.c:64
      shash_async_setkey+0x47/0x60 crypto/shash.c:207
      crypto_ahash_setkey+0xaf/0x180 crypto/ahash.c:200
      hash_setkey+0x40/0x90 crypto/algif_hash.c:446
      alg_setkey crypto/af_alg.c:221 [inline]
      alg_setsockopt+0x2a1/0x350 crypto/af_alg.c:254
      SYSC_setsockopt net/socket.c:1851 [inline]
      SyS_setsockopt+0x189/0x360 net/socket.c:1830
      entry_SYSCALL_64_fastpath+0x1f/0x96
Reported-by: syzbot <syzkaller@googlegroups.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
											
										 
											2017-11-28 18:01:38 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	ds = salg->digestsize; | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	ss = salg->statesize; | 
					
						
							|  |  |  | 	if (ds > alg->cra_blocksize || | 
					
						
							|  |  |  | 	    ss < alg->cra_blocksize) | 
					
						
							| 
									
										
										
										
											2020-01-02 19:58:54 -08:00
										 |  |  | 		goto err_free_inst; | 
					
						
							| 
									
										
										
										
											2008-07-07 20:23:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-02 19:58:54 -08:00
										 |  |  | 	err = crypto_inst_setname(shash_crypto_instance(inst), tmpl->name, alg); | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	if (err) | 
					
						
							| 
									
										
										
										
											2020-01-02 19:58:54 -08:00
										 |  |  | 		goto err_free_inst; | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	inst->alg.base.cra_priority = alg->cra_priority; | 
					
						
							|  |  |  | 	inst->alg.base.cra_blocksize = alg->cra_blocksize; | 
					
						
							| 
									
										
										
										
											2023-10-18 22:53:34 -07:00
										 |  |  | 	inst->alg.base.cra_ctxsize = sizeof(struct hmac_ctx) + (ss * 2); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	inst->alg.digestsize = ds; | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	inst->alg.statesize = ss; | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	inst->alg.init = hmac_init; | 
					
						
							|  |  |  | 	inst->alg.update = hmac_update; | 
					
						
							|  |  |  | 	inst->alg.final = hmac_final; | 
					
						
							|  |  |  | 	inst->alg.finup = hmac_finup; | 
					
						
							| 
									
										
										
										
											2009-07-24 15:18:41 +08:00
										 |  |  | 	inst->alg.export = hmac_export; | 
					
						
							|  |  |  | 	inst->alg.import = hmac_import; | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	inst->alg.setkey = hmac_setkey; | 
					
						
							| 
									
										
										
										
											2019-12-08 13:42:53 +08:00
										 |  |  | 	inst->alg.init_tfm = hmac_init_tfm; | 
					
						
							| 
									
										
										
										
											2023-04-13 14:24:21 +08:00
										 |  |  | 	inst->alg.clone_tfm = hmac_clone_tfm; | 
					
						
							| 
									
										
										
										
											2019-12-08 13:42:53 +08:00
										 |  |  | 	inst->alg.exit_tfm = hmac_exit_tfm; | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-02 20:04:38 -08:00
										 |  |  | 	inst->free = shash_free_singlespawn_instance; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	err = shash_register_instance(tmpl, inst); | 
					
						
							|  |  |  | 	if (err) { | 
					
						
							| 
									
										
										
										
											2020-01-02 19:58:54 -08:00
										 |  |  | err_free_inst: | 
					
						
							| 
									
										
										
										
											2020-01-02 20:04:38 -08:00
										 |  |  | 		shash_free_singlespawn_instance(inst); | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return err; | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct crypto_template hmac_tmpl = { | 
					
						
							|  |  |  | 	.name = "hmac", | 
					
						
							| 
									
										
										
										
											2009-07-09 12:43:37 +08:00
										 |  |  | 	.create = hmac_create, | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | 	.module = THIS_MODULE, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init hmac_module_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return crypto_register_template(&hmac_tmpl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __exit hmac_module_exit(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	crypto_unregister_template(&hmac_tmpl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-11 21:57:42 -07:00
										 |  |  | subsys_initcall(hmac_module_init); | 
					
						
							| 
									
										
										
										
											2006-08-21 20:50:52 +10:00
										 |  |  | module_exit(hmac_module_exit); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MODULE_LICENSE("GPL"); | 
					
						
							|  |  |  | MODULE_DESCRIPTION("HMAC hash algorithm"); | 
					
						
							| 
									
										
										
										
											2014-11-24 16:32:38 -08:00
										 |  |  | MODULE_ALIAS_CRYPTO("hmac"); |