Skip to content

Commit 12d41a0

Browse files
ebiggersherbertx
authored andcommitted
crypto: dh - Fix double free of ctx->p
When setting the secret with the software Diffie-Hellman implementation, if allocating 'g' failed (e.g. if it was longer than MAX_EXTERN_MPI_BITS), then 'p' was freed twice: once immediately, and once later when the crypto_kpp tfm was destroyed. Fix it by using dh_free_ctx() (renamed to dh_clear_ctx()) in the error paths, as that correctly sets the pointers to NULL. KASAN report: MPI: mpi too large (32760 bits) ================================================================== BUG: KASAN: use-after-free in mpi_free+0x131/0x170 Read of size 4 at addr ffff88006c7cdf90 by task reproduce_doubl/367 CPU: 1 PID: 367 Comm: reproduce_doubl Not tainted 4.14.0-rc7-00040-g05298abde6fe #7 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 Call Trace: dump_stack+0xb3/0x10b ? mpi_free+0x131/0x170 print_address_description+0x79/0x2a0 ? mpi_free+0x131/0x170 kasan_report+0x236/0x340 ? akcipher_register_instance+0x90/0x90 __asan_report_load4_noabort+0x14/0x20 mpi_free+0x131/0x170 ? akcipher_register_instance+0x90/0x90 dh_exit_tfm+0x3d/0x140 crypto_kpp_exit_tfm+0x52/0x70 crypto_destroy_tfm+0xb3/0x250 __keyctl_dh_compute+0x640/0xe90 ? kasan_slab_free+0x12f/0x180 ? dh_data_from_key+0x240/0x240 ? key_create_or_update+0x1ee/0xb20 ? key_instantiate_and_link+0x440/0x440 ? lock_contended+0xee0/0xee0 ? kfree+0xcf/0x210 ? SyS_add_key+0x268/0x340 keyctl_dh_compute+0xb3/0xf1 ? __keyctl_dh_compute+0xe90/0xe90 ? SyS_add_key+0x26d/0x340 ? entry_SYSCALL_64_fastpath+0x5/0xbe ? trace_hardirqs_on_caller+0x3f4/0x560 SyS_keyctl+0x72/0x2c0 entry_SYSCALL_64_fastpath+0x1f/0xbe RIP: 0033:0x43ccf9 RSP: 002b:00007ffeeec96158 EFLAGS: 00000246 ORIG_RAX: 00000000000000fa RAX: ffffffffffffffda RBX: 000000000248b9b9 RCX: 000000000043ccf9 RDX: 00007ffeeec96170 RSI: 00007ffeeec96160 RDI: 0000000000000017 RBP: 0000000000000046 R08: 0000000000000000 R09: 0248b9b9143dc936 R10: 0000000000001000 R11: 0000000000000246 R12: 0000000000000000 R13: 0000000000409670 R14: 0000000000409700 R15: 0000000000000000 Allocated by task 367: save_stack_trace+0x16/0x20 kasan_kmalloc+0xeb/0x180 kmem_cache_alloc_trace+0x114/0x300 mpi_alloc+0x4b/0x230 mpi_read_raw_data+0xbe/0x360 dh_set_secret+0x1dc/0x460 __keyctl_dh_compute+0x623/0xe90 keyctl_dh_compute+0xb3/0xf1 SyS_keyctl+0x72/0x2c0 entry_SYSCALL_64_fastpath+0x1f/0xbe Freed by task 367: save_stack_trace+0x16/0x20 kasan_slab_free+0xab/0x180 kfree+0xb5/0x210 mpi_free+0xcb/0x170 dh_set_secret+0x2d7/0x460 __keyctl_dh_compute+0x623/0xe90 keyctl_dh_compute+0xb3/0xf1 SyS_keyctl+0x72/0x2c0 entry_SYSCALL_64_fastpath+0x1f/0xbe Fixes: 802c7f1 ("crypto: dh - Add DH software implementation") Cc: <[email protected]> # v4.8+ Signed-off-by: Eric Biggers <[email protected]> Reviewed-by: Tudor Ambarus <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent c3577f6 commit 12d41a0

File tree

1 file changed

+13
-20
lines changed

1 file changed

+13
-20
lines changed

crypto/dh.c

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,12 @@ struct dh_ctx {
2121
MPI xa;
2222
};
2323

24-
static inline void dh_clear_params(struct dh_ctx *ctx)
24+
static void dh_clear_ctx(struct dh_ctx *ctx)
2525
{
2626
mpi_free(ctx->p);
2727
mpi_free(ctx->g);
28-
ctx->p = NULL;
29-
ctx->g = NULL;
30-
}
31-
32-
static void dh_free_ctx(struct dh_ctx *ctx)
33-
{
34-
dh_clear_params(ctx);
3528
mpi_free(ctx->xa);
36-
ctx->xa = NULL;
29+
memset(ctx, 0, sizeof(*ctx));
3730
}
3831

3932
/*
@@ -71,10 +64,8 @@ static int dh_set_params(struct dh_ctx *ctx, struct dh *params)
7164
return -EINVAL;
7265

7366
ctx->g = mpi_read_raw_data(params->g, params->g_size);
74-
if (!ctx->g) {
75-
mpi_free(ctx->p);
67+
if (!ctx->g)
7668
return -EINVAL;
77-
}
7869

7970
return 0;
8071
}
@@ -86,21 +77,23 @@ static int dh_set_secret(struct crypto_kpp *tfm, const void *buf,
8677
struct dh params;
8778

8879
/* Free the old MPI key if any */
89-
dh_free_ctx(ctx);
80+
dh_clear_ctx(ctx);
9081

9182
if (crypto_dh_decode_key(buf, len, &params) < 0)
92-
return -EINVAL;
83+
goto err_clear_ctx;
9384

9485
if (dh_set_params(ctx, &params) < 0)
95-
return -EINVAL;
86+
goto err_clear_ctx;
9687

9788
ctx->xa = mpi_read_raw_data(params.key, params.key_size);
98-
if (!ctx->xa) {
99-
dh_clear_params(ctx);
100-
return -EINVAL;
101-
}
89+
if (!ctx->xa)
90+
goto err_clear_ctx;
10291

10392
return 0;
93+
94+
err_clear_ctx:
95+
dh_clear_ctx(ctx);
96+
return -EINVAL;
10497
}
10598

10699
static int dh_compute_value(struct kpp_request *req)
@@ -158,7 +151,7 @@ static void dh_exit_tfm(struct crypto_kpp *tfm)
158151
{
159152
struct dh_ctx *ctx = dh_get_ctx(tfm);
160153

161-
dh_free_ctx(ctx);
154+
dh_clear_ctx(ctx);
162155
}
163156

164157
static struct kpp_alg dh = {

0 commit comments

Comments
 (0)