From 3b6bc929b83c5c765266bbcec2b681d2f254c881 Mon Sep 17 00:00:00 2001 From: otto <> Date: Sat, 23 Sep 2017 15:13:12 +0000 Subject: [PATCH] Make delayed free non-optional and make F do an extensive double free check. ok tb@ tedu@ --- src/lib/libc/stdlib/malloc.c | 47 ++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index e522e0ae..221a876f 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: malloc.c,v 1.231 2017/09/12 18:36:30 otto Exp $ */ +/* $OpenBSD: malloc.c,v 1.232 2017/09/23 15:13:12 otto Exp $ */ /* * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek * Copyright (c) 2012 Matthew Dempsky @@ -179,7 +179,7 @@ struct chunk_info { struct malloc_readonly { struct dir_info *malloc_pool[_MALLOC_MUTEXES]; /* Main bookkeeping information */ int malloc_mt; /* multi-threaded mode? */ - int malloc_freenow; /* Free quickly - disable chunk rnd */ + int malloc_freecheck; /* Extensive double free check */ int malloc_freeunmap; /* mprotect free pages PROT_NONE? */ int malloc_junk; /* junk fill? */ int malloc_realloc; /* always realloc? */ @@ -520,11 +520,11 @@ omalloc_parseopt(char opt) break; #endif /* MALLOC_STATS */ case 'f': - mopts.malloc_freenow = 0; + mopts.malloc_freecheck = 0; mopts.malloc_freeunmap = 0; break; case 'F': - mopts.malloc_freenow = 1; + mopts.malloc_freecheck = 1; mopts.malloc_freeunmap = 1; break; case 'g': @@ -605,7 +605,7 @@ omalloc_init(void) for (; p != NULL && *p != '\0'; p++) { switch (*p) { case 'S': - for (q = "CGJ"; *q != '\0'; q++) + for (q = "CFGJ"; *q != '\0'; q++) omalloc_parseopt(*q); mopts.malloc_cache = 0; break; @@ -1046,10 +1046,12 @@ validate_canary(struct dir_info *d, u_char *ptr, size_t sz, size_t allocated) q = p + check_sz; while (p < q) { - if (*p++ != SOME_JUNK) { - wrterror(d, "chunk canary corrupted %p %#tx@%#zx", - ptr, p - ptr - 1, sz); + if (*p != SOME_JUNK) { + wrterror(d, "chunk canary corrupted %p %#tx@%#zx%s", + ptr, p - ptr, sz, *p == SOME_FREEJUNK ? + " (double free?)" : ""); } + p++; } } @@ -1381,13 +1383,18 @@ ofree(struct dir_info *argpool, void *p, int clear, int check, size_t argsz) unmap(pool, p, PAGEROUND(sz), clear); delete(pool, r); } else { - void *tmp; - int i; - - /* Delayed free or canaries? Extra check */ - if (!mopts.malloc_freenow || mopts.chunk_canaries) - find_chunknum(pool, r, p, mopts.chunk_canaries); - if (!clear && !mopts.malloc_freenow) { + /* Validate and optionally canary check */ + find_chunknum(pool, r, p, mopts.chunk_canaries); + if (!clear) { + void *tmp; + int i; + + if (mopts.malloc_freecheck) { + for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++) + if (p == pool->delayed_chunks[i]) + wrterror(pool, + "double free %p", p); + } if (mopts.malloc_junk && sz > 0) memset(p, SOME_FREEJUNK, sz); i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK; @@ -1395,13 +1402,11 @@ ofree(struct dir_info *argpool, void *p, int clear, int check, size_t argsz) p = pool->delayed_chunks[i]; if (tmp == p) wrterror(pool, "double free %p", tmp); + pool->delayed_chunks[i] = tmp; if (mopts.malloc_junk) validate_junk(pool, p); - pool->delayed_chunks[i] = tmp; - } else { - if ((clear || mopts.malloc_junk) && sz > 0) - memset(p, clear ? 0 : SOME_FREEJUNK, sz); - } + } else if (sz > 0) + memset(p, 0, sz); if (p != NULL) { r = find(pool, p); if (r == NULL) @@ -2348,7 +2353,7 @@ malloc_exit(void) snprintf(buf, sizeof(buf), "MT=%d I=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u G=%zu\n", mopts.malloc_mt, mopts.internal_funcs, - mopts.malloc_freenow, + mopts.malloc_freecheck, mopts.malloc_freeunmap, mopts.malloc_junk, mopts.malloc_realloc, mopts.malloc_xmalloc, mopts.chunk_canaries, mopts.malloc_cache,