Takashi Iwai 5cd14d
From e57121d08c38dabec15cf3e1e2ad46721af30cae Mon Sep 17 00:00:00 2001
Takashi Iwai 5cd14d
From: Eric Biggers <ebiggers@google.com>
Takashi Iwai 5cd14d
Date: Mon, 11 Dec 2017 12:15:17 -0800
Takashi Iwai 5cd14d
Subject: [PATCH] crypto: chacha20poly1305 - validate the digest size
Takashi Iwai 5cd14d
Git-commit: e57121d08c38dabec15cf3e1e2ad46721af30cae
Takashi Iwai 5cd14d
Patch-mainline: v4.15-rc7
Takashi Iwai 5cd14d
References: bsc#1051510
Takashi Iwai 5cd14d
Takashi Iwai 5cd14d
If the rfc7539 template was instantiated with a hash algorithm with
Takashi Iwai 5cd14d
digest size larger than 16 bytes (POLY1305_DIGEST_SIZE), then the digest
Takashi Iwai 5cd14d
overran the 'tag' buffer in 'struct chachapoly_req_ctx', corrupting the
Takashi Iwai 5cd14d
subsequent memory, including 'cryptlen'.  This caused a crash during
Takashi Iwai 5cd14d
crypto_skcipher_decrypt().
Takashi Iwai 5cd14d
Takashi Iwai 5cd14d
Fix it by, when instantiating the template, requiring that the
Takashi Iwai 5cd14d
underlying hash algorithm has the digest size expected for Poly1305.
Takashi Iwai 5cd14d
Takashi Iwai 5cd14d
Reproducer: 
Takashi Iwai 5cd14d
Takashi Iwai 5cd14d
    #include <linux/if_alg.h>
Takashi Iwai 5cd14d
    #include <sys/socket.h>
Takashi Iwai 5cd14d
    #include <unistd.h>
Takashi Iwai 5cd14d
Takashi Iwai 5cd14d
    int main()
Takashi Iwai 5cd14d
    {
Takashi Iwai 5cd14d
            int algfd, reqfd;
Takashi Iwai 5cd14d
            struct sockaddr_alg addr = {
Takashi Iwai 5cd14d
                    .salg_type = "aead",
Takashi Iwai 5cd14d
                    .salg_name = "rfc7539(chacha20,sha256)",
Takashi Iwai 5cd14d
            };
Takashi Iwai 5cd14d
            unsigned char buf[32] = { 0 };
Takashi Iwai 5cd14d
Takashi Iwai 5cd14d
            algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
Takashi Iwai 5cd14d
            bind(algfd, (void *)&addr, sizeof(addr));
Takashi Iwai 5cd14d
            setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, sizeof(buf));
Takashi Iwai 5cd14d
            reqfd = accept(algfd, 0, 0);
Takashi Iwai 5cd14d
            write(reqfd, buf, 16);
Takashi Iwai 5cd14d
            read(reqfd, buf, 16);
Takashi Iwai 5cd14d
    }
Takashi Iwai 5cd14d
Takashi Iwai 5cd14d
Reported-by: syzbot <syzkaller@googlegroups.com>
Takashi Iwai 5cd14d
Fixes: 71ebc4d1b27d ("crypto: chacha20poly1305 - Add a ChaCha20-Poly1305 AEAD construction, RFC7539")
Takashi Iwai 5cd14d
Cc: <stable@vger.kernel.org> # v4.2+
Takashi Iwai 5cd14d
Signed-off-by: Eric Biggers <ebiggers@google.com>
Takashi Iwai 5cd14d
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Takashi Iwai 5cd14d
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 5cd14d
Takashi Iwai 5cd14d
---
Takashi Iwai 5cd14d
 crypto/chacha20poly1305.c |    6 +++++-
Takashi Iwai 5cd14d
 1 file changed, 5 insertions(+), 1 deletion(-)
Takashi Iwai 5cd14d
Takashi Iwai 5cd14d
--- a/crypto/chacha20poly1305.c
Takashi Iwai 5cd14d
+++ b/crypto/chacha20poly1305.c
Takashi Iwai 5cd14d
@@ -610,6 +610,11 @@ static int chachapoly_create(struct cryp
Takashi Iwai 5cd14d
 						    algt->mask));
Takashi Iwai 5cd14d
 	if (IS_ERR(poly))
Takashi Iwai 5cd14d
 		return PTR_ERR(poly);
Takashi Iwai 5cd14d
+	poly_hash = __crypto_hash_alg_common(poly);
Takashi Iwai 5cd14d
+
Takashi Iwai 5cd14d
+	err = -EINVAL;
Takashi Iwai 5cd14d
+	if (poly_hash->digestsize != POLY1305_DIGEST_SIZE)
Takashi Iwai 5cd14d
+		goto out_put_poly;
Takashi Iwai 5cd14d
 
Takashi Iwai 5cd14d
 	err = -ENOMEM;
Takashi Iwai 5cd14d
 	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
Takashi Iwai 5cd14d
@@ -618,7 +623,6 @@ static int chachapoly_create(struct cryp
Takashi Iwai 5cd14d
 
Takashi Iwai 5cd14d
 	ctx = aead_instance_ctx(inst);
Takashi Iwai 5cd14d
 	ctx->saltlen = CHACHAPOLY_IV_SIZE - ivsize;
Takashi Iwai 5cd14d
-	poly_hash = __crypto_hash_alg_common(poly);
Takashi Iwai 5cd14d
 	err = crypto_init_ahash_spawn(&ctx->poly, poly_hash,
Takashi Iwai 5cd14d
 				      aead_crypto_instance(inst));
Takashi Iwai 5cd14d
 	if (err)