summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm <>2012-11-02 18:18:15 +0000
committerdjm <>2012-11-02 18:18:15 +0000
commitcc27290cd0ac9c8a750e38719b5dff3cb0219726 (patch)
tree5ac95b51be61afab38ef830fc97336aacc9973c7
parente05982c56ef9dbde368df8fe35a8458f34b76f76 (diff)
downloadopenbsd-cc27290cd0ac9c8a750e38719b5dff3cb0219726.tar.gz
openbsd-cc27290cd0ac9c8a750e38719b5dff3cb0219726.tar.bz2
openbsd-cc27290cd0ac9c8a750e38719b5dff3cb0219726.zip
Add a new malloc option 'U' => "Free unmap" that does the guarding/
unmapping of freed allocations without disabling chunk randomisation like the "Freeguard" ('F') option does. Make security 'S' option use 'U' and not 'F'. Rationale: guarding with no chunk randomisation is great for debugging use-after-free, but chunk randomisation offers better defence against "heap feng shui" style attacks that depend on carefully constructing a particular heap layout so we should leave this enabled when requesting security options.
-rw-r--r--src/lib/libc/stdlib/malloc.315
-rw-r--r--src/lib/libc/stdlib/malloc.c39
2 files changed, 36 insertions, 18 deletions
diff --git a/src/lib/libc/stdlib/malloc.3 b/src/lib/libc/stdlib/malloc.3
index 6a012fd23d..74df922f4b 100644
--- a/src/lib/libc/stdlib/malloc.3
+++ b/src/lib/libc/stdlib/malloc.3
@@ -30,9 +30,9 @@
30.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31.\" SUCH DAMAGE. 31.\" SUCH DAMAGE.
32.\" 32.\"
33.\" $OpenBSD: malloc.3,v 1.70 2011/07/22 07:00:44 otto Exp $ 33.\" $OpenBSD: malloc.3,v 1.71 2012/11/02 18:18:15 djm Exp $
34.\" 34.\"
35.Dd $Mdocdate: July 22 2011 $ 35.Dd $Mdocdate: November 2 2012 $
36.Dt MALLOC 3 36.Dt MALLOC 3
37.Os 37.Os
38.Sh NAME 38.Sh NAME
@@ -231,13 +231,17 @@ This option requires the library to have been compiled with -DMALLOC_STATS in
231order to have any effect. 231order to have any effect.
232.It Cm F 232.It Cm F
233.Dq Freeguard . 233.Dq Freeguard .
234Enable use after free protection. 234Enable use after free detection.
235Unused pages on the freelist are read and write protected to 235Unused pages on the freelist are read and write protected to
236cause a segmentation fault upon access. 236cause a segmentation fault upon access.
237This will also switch off the delayed freeing of chunks, 237This will also switch off the delayed freeing of chunks,
238reducing random behaviour but detecting double 238reducing random behaviour but detecting double
239.Fn free 239.Fn free
240calls as early as possible. 240calls as early as possible.
241This option is intended for debugging rather than improved security
242(use the
243.Cm U
244option for security).
241.It Cm G 245.It Cm G
242.Dq Guard . 246.Dq Guard .
243Enable guard pages. 247Enable guard pages.
@@ -275,6 +279,11 @@ This can substantially aid in compacting memory.
275.\"Consult the source for this one. 279.\"Consult the source for this one.
276.It Cm S 280.It Cm S
277Enable all options suitable for security auditing. 281Enable all options suitable for security auditing.
282.It Cm U
283.Dq Free unmap .
284Enable use after free protection for larger allocations.
285Unused pages on the freelist are read and write protected to
286cause a segmentation fault upon access.
278.It Cm X 287.It Cm X
279.Dq xmalloc . 288.Dq xmalloc .
280Rather than return failure, 289Rather than return failure,
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c
index c69ec8316a..b14c747652 100644
--- a/src/lib/libc/stdlib/malloc.c
+++ b/src/lib/libc/stdlib/malloc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: malloc.c,v 1.147 2012/09/13 10:45:41 pirofti Exp $ */ 1/* $OpenBSD: malloc.c,v 1.148 2012/11/02 18:18:15 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> 3 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
4 * 4 *
@@ -165,7 +165,8 @@ struct chunk_info {
165struct malloc_readonly { 165struct malloc_readonly {
166 struct dir_info *g_pool; /* Main bookkeeping information */ 166 struct dir_info *g_pool; /* Main bookkeeping information */
167 int malloc_abort; /* abort() on error */ 167 int malloc_abort; /* abort() on error */
168 int malloc_freeprot; /* mprotect free pages PROT_NONE? */ 168 int malloc_freenow; /* Free quickly - disable chunk rnd */
169 int malloc_freeunmap; /* mprotect free pages PROT_NONE? */
169 int malloc_hint; /* call madvice on free pages? */ 170 int malloc_hint; /* call madvice on free pages? */
170 int malloc_junk; /* junk fill? */ 171 int malloc_junk; /* junk fill? */
171 int malloc_move; /* move allocations to end of page? */ 172 int malloc_move; /* move allocations to end of page? */
@@ -344,7 +345,7 @@ unmap(struct dir_info *d, void *p, size_t sz)
344 if (r->p == NULL) { 345 if (r->p == NULL) {
345 if (mopts.malloc_hint) 346 if (mopts.malloc_hint)
346 madvise(p, sz, MADV_FREE); 347 madvise(p, sz, MADV_FREE);
347 if (mopts.malloc_freeprot) 348 if (mopts.malloc_freeunmap)
348 mprotect(p, sz, PROT_NONE); 349 mprotect(p, sz, PROT_NONE);
349 r->p = p; 350 r->p = p;
350 r->size = psz; 351 r->size = psz;
@@ -407,7 +408,7 @@ map(struct dir_info *d, size_t sz, int zero_fill)
407 if (r->p != NULL) { 408 if (r->p != NULL) {
408 if (r->size == psz) { 409 if (r->size == psz) {
409 p = r->p; 410 p = r->p;
410 if (mopts.malloc_freeprot) 411 if (mopts.malloc_freeunmap)
411 mprotect(p, sz, PROT_READ | PROT_WRITE); 412 mprotect(p, sz, PROT_READ | PROT_WRITE);
412 if (mopts.malloc_hint) 413 if (mopts.malloc_hint)
413 madvise(p, sz, MADV_NORMAL); 414 madvise(p, sz, MADV_NORMAL);
@@ -417,7 +418,7 @@ map(struct dir_info *d, size_t sz, int zero_fill)
417 if (zero_fill) 418 if (zero_fill)
418 memset(p, 0, sz); 419 memset(p, 0, sz);
419 else if (mopts.malloc_junk && 420 else if (mopts.malloc_junk &&
420 mopts.malloc_freeprot) 421 mopts.malloc_freeunmap)
421 memset(p, SOME_FREEJUNK, sz); 422 memset(p, SOME_FREEJUNK, sz);
422 return p; 423 return p;
423 } else if (r->size > psz) 424 } else if (r->size > psz)
@@ -427,7 +428,7 @@ map(struct dir_info *d, size_t sz, int zero_fill)
427 if (big != NULL) { 428 if (big != NULL) {
428 r = big; 429 r = big;
429 p = (char *)r->p + ((r->size - psz) << MALLOC_PAGESHIFT); 430 p = (char *)r->p + ((r->size - psz) << MALLOC_PAGESHIFT);
430 if (mopts.malloc_freeprot) 431 if (mopts.malloc_freeunmap)
431 mprotect(p, sz, PROT_READ | PROT_WRITE); 432 mprotect(p, sz, PROT_READ | PROT_WRITE);
432 if (mopts.malloc_hint) 433 if (mopts.malloc_hint)
433 madvise(p, sz, MADV_NORMAL); 434 madvise(p, sz, MADV_NORMAL);
@@ -435,7 +436,7 @@ map(struct dir_info *d, size_t sz, int zero_fill)
435 d->free_regions_size -= psz; 436 d->free_regions_size -= psz;
436 if (zero_fill) 437 if (zero_fill)
437 memset(p, 0, sz); 438 memset(p, 0, sz);
438 else if (mopts.malloc_junk && mopts.malloc_freeprot) 439 else if (mopts.malloc_junk && mopts.malloc_freeunmap)
439 memset(p, SOME_FREEJUNK, sz); 440 memset(p, SOME_FREEJUNK, sz);
440 return p; 441 return p;
441 } 442 }
@@ -515,10 +516,12 @@ omalloc_init(struct dir_info **dp)
515 break; 516 break;
516#endif /* MALLOC_STATS */ 517#endif /* MALLOC_STATS */
517 case 'f': 518 case 'f':
518 mopts.malloc_freeprot = 0; 519 mopts.malloc_freenow = 0;
520 mopts.malloc_freeunmap = 0;
519 break; 521 break;
520 case 'F': 522 case 'F':
521 mopts.malloc_freeprot = 1; 523 mopts.malloc_freenow = 1;
524 mopts.malloc_freeunmap = 1;
522 break; 525 break;
523 case 'g': 526 case 'g':
524 mopts.malloc_guard = 0; 527 mopts.malloc_guard = 0;
@@ -554,15 +557,21 @@ omalloc_init(struct dir_info **dp)
554 mopts.malloc_realloc = 1; 557 mopts.malloc_realloc = 1;
555 break; 558 break;
556 case 's': 559 case 's':
557 mopts.malloc_freeprot = mopts.malloc_junk = 0; 560 mopts.malloc_freeunmap = mopts.malloc_junk = 0;
558 mopts.malloc_guard = 0; 561 mopts.malloc_guard = 0;
559 mopts.malloc_cache = MALLOC_DEFAULT_CACHE; 562 mopts.malloc_cache = MALLOC_DEFAULT_CACHE;
560 break; 563 break;
561 case 'S': 564 case 'S':
562 mopts.malloc_freeprot = mopts.malloc_junk = 1; 565 mopts.malloc_freeunmap = mopts.malloc_junk = 1;
563 mopts.malloc_guard = MALLOC_PAGESIZE; 566 mopts.malloc_guard = MALLOC_PAGESIZE;
564 mopts.malloc_cache = 0; 567 mopts.malloc_cache = 0;
565 break; 568 break;
569 case 'u':
570 mopts.malloc_freeunmap = 0;
571 break;
572 case 'U':
573 mopts.malloc_freeunmap = 1;
574 break;
566 case 'x': 575 case 'x':
567 mopts.malloc_xmalloc = 0; 576 mopts.malloc_xmalloc = 0;
568 break; 577 break;
@@ -1015,7 +1024,7 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
1015 1024
1016 LIST_REMOVE(info, entries); 1025 LIST_REMOVE(info, entries);
1017 1026
1018 if (info->size == 0 && !mopts.malloc_freeprot) 1027 if (info->size == 0 && !mopts.malloc_freeunmap)
1019 mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE); 1028 mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE);
1020 unmap(d, info->page, MALLOC_PAGESIZE); 1029 unmap(d, info->page, MALLOC_PAGESIZE);
1021 1030
@@ -1184,7 +1193,7 @@ ofree(void *p)
1184 if (mopts.malloc_guard) { 1193 if (mopts.malloc_guard) {
1185 if (sz < mopts.malloc_guard) 1194 if (sz < mopts.malloc_guard)
1186 wrterror("guard size", NULL); 1195 wrterror("guard size", NULL);
1187 if (!mopts.malloc_freeprot) { 1196 if (!mopts.malloc_freeunmap) {
1188 if (mprotect((char *)p + PAGEROUND(sz) - 1197 if (mprotect((char *)p + PAGEROUND(sz) -
1189 mopts.malloc_guard, mopts.malloc_guard, 1198 mopts.malloc_guard, mopts.malloc_guard,
1190 PROT_READ | PROT_WRITE)) 1199 PROT_READ | PROT_WRITE))
@@ -1192,7 +1201,7 @@ ofree(void *p)
1192 } 1201 }
1193 malloc_guarded -= mopts.malloc_guard; 1202 malloc_guarded -= mopts.malloc_guard;
1194 } 1203 }
1195 if (mopts.malloc_junk && !mopts.malloc_freeprot) 1204 if (mopts.malloc_junk && !mopts.malloc_freeunmap)
1196 memset(p, SOME_FREEJUNK, 1205 memset(p, SOME_FREEJUNK,
1197 PAGEROUND(sz) - mopts.malloc_guard); 1206 PAGEROUND(sz) - mopts.malloc_guard);
1198 unmap(g_pool, p, PAGEROUND(sz)); 1207 unmap(g_pool, p, PAGEROUND(sz));
@@ -1203,7 +1212,7 @@ ofree(void *p)
1203 1212
1204 if (mopts.malloc_junk && sz > 0) 1213 if (mopts.malloc_junk && sz > 0)
1205 memset(p, SOME_FREEJUNK, sz); 1214 memset(p, SOME_FREEJUNK, sz);
1206 if (!mopts.malloc_freeprot) { 1215 if (!mopts.malloc_freenow) {
1207 i = getrnibble(); 1216 i = getrnibble();
1208 tmp = p; 1217 tmp = p;
1209 p = g_pool->delayed_chunks[i]; 1218 p = g_pool->delayed_chunks[i];