CVE-2017-18075: Release of Invalid Pointer or Reference (CWE-763)
value: crypto/pcrypt.c in the Linux kernel before 4.14.13 mishandles freeing instances, allowing a local user able to access the AF_ALG-based AEAD interface (CONFIG_CRYPTO_USER_API_AEAD) and pcrypt (CONFIG_CRYPTO_PCRYPT) to cause a denial of service (kfree of an incorrect pointer) or possibly have unspecified other impact by executing a crafted sequence of system calls.
CWE description: The product attempts to return a memory resource to the system, but it calls the wrong release function or calls the appropriate release function incorrectly.
CVSS v3 base score: 7.8
Published: 2018-01-24T10:29Z
Repository: https://github.com/torvalds/linux
Language: C
Files changed: crypto/pcrypt.c
Commit date: 2017-12-22 19:02:47 +1100
Commit message: crypto: pcrypt - fix freeing pcrypt instances

pcrypt is using the old way of freeing instances, where the ->free()
method specified in the 'struct crypto_template' is passed a pointer to
the 'struct crypto_instance'.  But the crypto_instance is being
kfree()'d directly, which is incorrect because the memory was actually
allocated as an aead_instance, which contains the crypto_instance at a
nonzero offset.  Thus, the wrong pointer was being kfree()'d.

Fix it by switching to the new way to free aead_instance's where the
->free() method is specified in the aead_instance itself.

Reported-by: syzbot <syzkaller@googlegroups.com>
Fixes: 0496f56065e0 ("crypto: pcrypt - Add support for new AEAD interface")
Cc: <stable@vger.kernel.org> # v4.2+
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Diff: diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c
index ee9cfb99fe256a..f8ec3d4ba4a80f 100644
--- a/crypto/pcrypt.c
+++ b/crypto/pcrypt.c
@@ -252,10 +252,18 @@ static void pcrypt_aead_exit_tfm(struct crypto_aead *tfm)
 	struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(tfm);
 
 	crypto_free_aead(ctx->child);
 }
 
+static void pcrypt_free(struct aead_instance *inst)
+{
+	struct pcrypt_instance_ctx *ctx = aead_instance_ctx(inst);
+
+	crypto_drop_aead(&ctx->spawn);
+	kfree(inst);
+}
+
 static int pcrypt_init_instance(struct crypto_instance *inst,
 				struct crypto_alg *alg)
 {
 	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
 		     "pcrypt(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
@@ -317,10 +325,12 @@ static int pcrypt_create_aead(struct crypto_template *tmpl, struct rtattr **tb,
 	inst->alg.setkey = pcrypt_aead_setkey;
 	inst->alg.setauthsize = pcrypt_aead_setauthsize;
 	inst->alg.encrypt = pcrypt_aead_encrypt;
 	inst->alg.decrypt = pcrypt_aead_decrypt;
 
+	inst->free = pcrypt_free;
+
 	err = aead_register_instance(tmpl, inst);
 	if (err)
 		goto out_drop_aead;
 
 out:
@@ -347,18 +357,10 @@ static int pcrypt_create(struct crypto_template *tmpl, struct rtattr **tb)
 	}
 
 	return -EINVAL;
 }
 
-static void pcrypt_free(struct crypto_instance *inst)
-{
-	struct pcrypt_instance_ctx *ctx = crypto_instance_ctx(inst);
-
-	crypto_drop_aead(&ctx->spawn);
-	kfree(inst);
-}
-
 static int pcrypt_cpumask_change_notify(struct notifier_block *self,
 					unsigned long val, void *data)
 {
 	struct padata_pcrypt *pcrypt;
 	struct pcrypt_cpumask *new_mask, *old_mask;
@@ -467,11 +469,10 @@ static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt)
 }
 
 static struct crypto_template pcrypt_tmpl = {
 	.name = "pcrypt",
 	.create = pcrypt_create,
-	.free = pcrypt_free,
 	.module = THIS_MODULE,
 };
 
 static int __init pcrypt_init(void)
 {

Vulnerable code: static void pcrypt_free(struct crypto_instance *inst)
{
	struct pcrypt_instance_ctx *ctx = crypto_instance_ctx(inst);

	crypto_drop_aead(&ctx->spawn);
	kfree(inst);
}

	.free = pcrypt_free,
Fixed code: static void pcrypt_free(struct aead_instance *inst)
{
	struct pcrypt_instance_ctx *ctx = aead_instance_ctx(inst);

	crypto_drop_aead(&ctx->spawn);
	kfree(inst);
}

	inst->free = pcrypt_free;