summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_malloc.c
diff options
context:
space:
mode:
authorbluhm <bluhm@openbsd.org>2018-07-09 08:46:30 +0000
committerbluhm <bluhm@openbsd.org>2018-07-09 08:46:30 +0000
commit21c85adc82cf6f023de093b050b8ab587ea321a9 (patch)
treee8a9d0acccdd3d0a35f4fb716e104b8405228319 /sys/kern/kern_malloc.c
parentvmd(8): stash device IRQ in the device struct (diff)
downloadwireguard-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.c13
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