diff --git a/debian/changelog b/debian/changelog index 7aea59ce7..c6d6afc86 100644 --- a/debian/changelog +++ b/debian/changelog @@ -507,6 +507,8 @@ linux (4.14.7-1) UNRELEASED; urgency=medium * xen/time: do not decrease steal time after live migration on xen (Closes: #871608) * crypto: salsa20 - fix blkcipher_walk API usage (CVE-2017-17805) + * crypto: hmac - require that the underlying hash algorithm is unkeyed + (CVE-2017-17806) [ Vagrant Cascadian ] * [armhf, arm64] Backport patches from 4.15.x to support dwmac-sun8i. diff --git a/debian/patches/bugfix/all/crypto-hmac-require-that-the-underlying-hash-algorit.patch b/debian/patches/bugfix/all/crypto-hmac-require-that-the-underlying-hash-algorit.patch new file mode 100644 index 000000000..44c4b4f43 --- /dev/null +++ b/debian/patches/bugfix/all/crypto-hmac-require-that-the-underlying-hash-algorit.patch @@ -0,0 +1,151 @@ +From: Eric Biggers +Date: Tue, 28 Nov 2017 18:01:38 -0800 +Subject: crypto: hmac - require that the underlying hash algorithm is unkeyed +Origin: https://git.kernel.org/linus/af3ff8045bbf3e32f1a448542e73abb4c8ceb6f1 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-17806 + +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 + #include + + 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 +Cc: +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +--- + crypto/hmac.c | 6 +++++- + crypto/shash.c | 5 +++-- + include/crypto/internal/hash.h | 8 ++++++++ + 3 files changed, 16 insertions(+), 3 deletions(-) + +diff --git a/crypto/hmac.c b/crypto/hmac.c +index 92871dc2a63e..e74730224f0a 100644 +--- a/crypto/hmac.c ++++ b/crypto/hmac.c +@@ -195,11 +195,15 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) + salg = shash_attr_alg(tb[1], 0, 0); + if (IS_ERR(salg)) + return PTR_ERR(salg); ++ alg = &salg->base; + ++ /* The underlying hash algorithm must be unkeyed */ + err = -EINVAL; ++ if (crypto_shash_alg_has_setkey(salg)) ++ goto out_put_alg; ++ + ds = salg->digestsize; + ss = salg->statesize; +- alg = &salg->base; + if (ds > alg->cra_blocksize || + ss < alg->cra_blocksize) + goto out_put_alg; +diff --git a/crypto/shash.c b/crypto/shash.c +index 325a14da5827..e849d3ee2e27 100644 +--- a/crypto/shash.c ++++ b/crypto/shash.c +@@ -25,11 +25,12 @@ + + static const struct crypto_type crypto_shash_type; + +-static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, +- unsigned int keylen) ++int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, ++ unsigned int keylen) + { + return -ENOSYS; + } ++EXPORT_SYMBOL_GPL(shash_no_setkey); + + static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) +diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h +index f0b44c16e88f..c2bae8da642c 100644 +--- a/include/crypto/internal/hash.h ++++ b/include/crypto/internal/hash.h +@@ -82,6 +82,14 @@ int ahash_register_instance(struct crypto_template *tmpl, + struct ahash_instance *inst); + void ahash_free_instance(struct crypto_instance *inst); + ++int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, ++ unsigned int keylen); ++ ++static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg) ++{ ++ return alg->setkey != shash_no_setkey; ++} ++ + int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, + struct hash_alg_common *alg, + struct crypto_instance *inst); +-- +2.11.0 + diff --git a/debian/patches/series b/debian/patches/series index de71383b3..f38ac7f9c 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -128,6 +128,7 @@ bugfix/all/media-hdpvr-fix-an-error-handling-path-in-hdpvr_prob.patch bugfix/all/kvm-fix-stack-out-of-bounds-read-in-write_mmio.patch bugfix/all/bluetooth-prevent-stack-info-leak-from-the-efs-element.patch bugfix/all/crypto-salsa20-fix-blkcipher_walk-API-usage.patch +bugfix/all/crypto-hmac-require-that-the-underlying-hash-algorit.patch # Fix exported symbol versions bugfix/all/module-disable-matching-missing-version-crc.patch