diff options
| author | 2018-07-09 08:46:30 +0000 | |
|---|---|---|
| committer | 2018-07-09 08:46:30 +0000 | |
| commit | 21c85adc82cf6f023de093b050b8ab587ea321a9 (patch) | |
| tree | e8a9d0acccdd3d0a35f4fb716e104b8405228319 /sys/kern/kern_malloc.c | |
| parent | vmd(8): stash device IRQ in the device struct (diff) | |
| download | wireguard-openbsd-21c85adc82cf6f023de093b050b8ab587ea321a9.tar.xz wireguard-openbsd-21c85adc82cf6f023de093b050b8ab587ea321a9.zip | |
Make free(9) MP safe. It was wrong to set ku_indx to 0 after freeing
the memory in uvm. Another process could use the false 0 then. To
be on the safe side, protect all access to ku_indx and ku_pagecnt
with a mutex. Update ku_indx and ku_pagecnt before calling
uvm_km_free(). Update ksp after uvm_km_free() to keep accounting
correct.
tested by sthen@; OK mpi@ visa@ deraadt@
Diffstat (limited to 'sys/kern/kern_malloc.c')
| -rw-r--r-- | sys/kern/kern_malloc.c | 13 |
1 files changed, 8 insertions, 5 deletions
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c index 5ea2bc176ae..4432d7c3e52 100644 --- a/sys/kern/kern_malloc.c +++ b/sys/kern/kern_malloc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_malloc.c,v 1.133 2018/01/18 18:08:51 bluhm Exp $ */ +/* $OpenBSD: kern_malloc.c,v 1.134 2018/07/09 08:46:30 bluhm Exp $ */ /* $NetBSD: kern_malloc.c,v 1.15.4.2 1996/06/13 17:10:56 cgd Exp $ */ /* @@ -384,6 +384,7 @@ free(void *addr, int type, size_t freedsize) memname[type]); #endif + mtx_enter(&malloc_mtx); kup = btokup(addr); size = 1 << kup->ku_indx; kbp = &bucket[kup->ku_indx]; @@ -409,14 +410,17 @@ free(void *addr, int type, size_t freedsize) addr, size, memname[type], alloc); #endif /* DIAGNOSTIC */ if (size > MAXALLOCSAVE) { + u_short pagecnt = kup->ku_pagecnt; + + kup->ku_indx = 0; + kup->ku_pagecnt = 0; + mtx_leave(&malloc_mtx); s = splvm(); - uvm_km_free(kmem_map, (vaddr_t)addr, ptoa(kup->ku_pagecnt)); + uvm_km_free(kmem_map, (vaddr_t)addr, ptoa(pagecnt)); splx(s); #ifdef KMEMSTATS mtx_enter(&malloc_mtx); ksp->ks_memuse -= size; - kup->ku_indx = 0; - kup->ku_pagecnt = 0; if (ksp->ks_memuse + size >= ksp->ks_limit && ksp->ks_memuse < ksp->ks_limit) wakeup(ksp); @@ -427,7 +431,6 @@ free(void *addr, int type, size_t freedsize) return; } freep = (struct kmem_freelist *)addr; - mtx_enter(&malloc_mtx); #ifdef DIAGNOSTIC /* * Check for multiple frees. Use a quick check to see if |
