summaryrefslogtreecommitdiff
path: root/src/lib/libc/stdlib/malloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/stdlib/malloc.c')
-rw-r--r--src/lib/libc/stdlib/malloc.c126
1 files changed, 80 insertions, 46 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c
index 7004a0aa36..46b07ff77d 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.267 2020/11/23 15:42:11 otto Exp $ */ 1/* $OpenBSD: malloc.c,v 1.268 2021/02/25 15:20:18 otto Exp $ */
2/* 2/*
3 * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <otto@drijf.net> 3 * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <otto@drijf.net>
4 * Copyright (c) 2012 Matthew Dempsky <matthew@openbsd.org> 4 * Copyright (c) 2012 Matthew Dempsky <matthew@openbsd.org>
@@ -89,6 +89,7 @@
89 */ 89 */
90#define SOME_JUNK 0xdb /* deadbeef */ 90#define SOME_JUNK 0xdb /* deadbeef */
91#define SOME_FREEJUNK 0xdf /* dead, free */ 91#define SOME_FREEJUNK 0xdf /* dead, free */
92#define SOME_FREEJUNK_ULL 0xdfdfdfdfdfdfdfdfULL
92 93
93#define MMAP(sz,f) mmap(NULL, (sz), PROT_READ | PROT_WRITE, \ 94#define MMAP(sz,f) mmap(NULL, (sz), PROT_READ | PROT_WRITE, \
94 MAP_ANON | MAP_PRIVATE | (f), -1, 0) 95 MAP_ANON | MAP_PRIVATE | (f), -1, 0)
@@ -655,6 +656,49 @@ delete(struct dir_info *d, struct region_info *ri)
655 } 656 }
656} 657}
657 658
659static inline void
660junk_free(int junk, void *p, size_t sz)
661{
662 size_t i, step = 1;
663 uint64_t *lp = p;
664
665 if (junk == 0 || sz == 0)
666 return;
667 sz /= sizeof(uint64_t);
668 if (junk == 1) {
669 if (sz > MALLOC_PAGESIZE / sizeof(uint64_t))
670 sz = MALLOC_PAGESIZE / sizeof(uint64_t);
671 step = sz / 4;
672 if (step == 0)
673 step = 1;
674 }
675 for (i = 0; i < sz; i += step)
676 lp[i] = SOME_FREEJUNK_ULL;
677}
678
679static inline void
680validate_junk(struct dir_info *pool, void *p, size_t sz)
681{
682 size_t i, step = 1;
683 uint64_t *lp = p;
684
685 if (pool->malloc_junk == 0 || sz == 0)
686 return;
687 sz /= sizeof(uint64_t);
688 if (pool->malloc_junk == 1) {
689 if (sz > MALLOC_PAGESIZE / sizeof(uint64_t))
690 sz = MALLOC_PAGESIZE / sizeof(uint64_t);
691 step = sz / 4;
692 if (step == 0)
693 step = 1;
694 }
695 for (i = 0; i < sz; i += step) {
696 if (lp[i] != SOME_FREEJUNK_ULL)
697 wrterror(pool, "write after free %p", p);
698 }
699}
700
701
658/* 702/*
659 * Cache maintenance. We keep at most malloc_cache pages cached. 703 * Cache maintenance. We keep at most malloc_cache pages cached.
660 * If the cache is becoming full, unmap pages in the cache for real, 704 * If the cache is becoming full, unmap pages in the cache for real,
@@ -663,7 +707,7 @@ delete(struct dir_info *d, struct region_info *ri)
663 * cache are in MALLOC_PAGESIZE units. 707 * cache are in MALLOC_PAGESIZE units.
664 */ 708 */
665static void 709static void
666unmap(struct dir_info *d, void *p, size_t sz, size_t clear, int junk) 710unmap(struct dir_info *d, void *p, size_t sz, size_t clear)
667{ 711{
668 size_t psz = sz >> MALLOC_PAGESHIFT; 712 size_t psz = sz >> MALLOC_PAGESHIFT;
669 size_t rsz; 713 size_t rsz;
@@ -695,6 +739,8 @@ unmap(struct dir_info *d, void *p, size_t sz, size_t clear, int junk)
695 r = &d->free_regions[(i + offset) & mask]; 739 r = &d->free_regions[(i + offset) & mask];
696 if (r->p != NULL) { 740 if (r->p != NULL) {
697 rsz = r->size << MALLOC_PAGESHIFT; 741 rsz = r->size << MALLOC_PAGESHIFT;
742 if (!mopts.malloc_freeunmap)
743 validate_junk(d, r->p, rsz);
698 if (munmap(r->p, rsz)) 744 if (munmap(r->p, rsz))
699 wrterror(d, "munmap %p", r->p); 745 wrterror(d, "munmap %p", r->p);
700 r->p = NULL; 746 r->p = NULL;
@@ -716,12 +762,11 @@ unmap(struct dir_info *d, void *p, size_t sz, size_t clear, int junk)
716 if (r->p == NULL) { 762 if (r->p == NULL) {
717 if (clear > 0) 763 if (clear > 0)
718 memset(p, 0, clear); 764 memset(p, 0, clear);
719 if (junk && !mopts.malloc_freeunmap) {
720 size_t amt = junk == 1 ? MALLOC_MAXCHUNK : sz;
721 memset(p, SOME_FREEJUNK, amt);
722 }
723 if (mopts.malloc_freeunmap) 765 if (mopts.malloc_freeunmap)
724 mprotect(p, sz, PROT_NONE); 766 mprotect(p, sz, PROT_NONE);
767 else
768 junk_free(d->malloc_junk, p,
769 psz << MALLOC_PAGESHIFT);
725 r->p = p; 770 r->p = p;
726 r->size = psz; 771 r->size = psz;
727 d->free_regions_size += psz; 772 d->free_regions_size += psz;
@@ -760,15 +805,17 @@ map(struct dir_info *d, size_t sz, int zero_fill)
760 if (r->p != NULL) { 805 if (r->p != NULL) {
761 if (r->size == psz) { 806 if (r->size == psz) {
762 p = r->p; 807 p = r->p;
808 if (!mopts.malloc_freeunmap)
809 validate_junk(d, p,
810 psz << MALLOC_PAGESHIFT);
763 r->p = NULL; 811 r->p = NULL;
764 d->free_regions_size -= psz; 812 d->free_regions_size -= psz;
765 if (mopts.malloc_freeunmap) 813 if (mopts.malloc_freeunmap)
766 mprotect(p, sz, PROT_READ | PROT_WRITE); 814 mprotect(p, sz, PROT_READ | PROT_WRITE);
767 if (zero_fill) 815 if (zero_fill)
768 memset(p, 0, sz); 816 memset(p, 0, sz);
769 else if (d->malloc_junk == 2 && 817 else if (mopts.malloc_freeunmap)
770 mopts.malloc_freeunmap) 818 junk_free(d->malloc_junk, p, sz);
771 memset(p, SOME_FREEJUNK, sz);
772 d->rotor += i + 1; 819 d->rotor += i + 1;
773 return p; 820 return p;
774 } else if (r->size > psz) 821 } else if (r->size > psz)
@@ -778,15 +825,20 @@ map(struct dir_info *d, size_t sz, int zero_fill)
778 if (big != NULL) { 825 if (big != NULL) {
779 r = big; 826 r = big;
780 p = r->p; 827 p = r->p;
828 if (!mopts.malloc_freeunmap)
829 validate_junk(d, p, r->size << MALLOC_PAGESHIFT);
781 r->p = (char *)r->p + (psz << MALLOC_PAGESHIFT); 830 r->p = (char *)r->p + (psz << MALLOC_PAGESHIFT);
782 if (mopts.malloc_freeunmap)
783 mprotect(p, sz, PROT_READ | PROT_WRITE);
784 r->size -= psz; 831 r->size -= psz;
785 d->free_regions_size -= psz; 832 d->free_regions_size -= psz;
833 if (mopts.malloc_freeunmap)
834 mprotect(p, sz, PROT_READ | PROT_WRITE);
835 else
836 junk_free(d->malloc_junk, r->p,
837 r->size << MALLOC_PAGESHIFT);
786 if (zero_fill) 838 if (zero_fill)
787 memset(p, 0, sz); 839 memset(p, 0, sz);
788 else if (d->malloc_junk == 2 && mopts.malloc_freeunmap) 840 else if (mopts.malloc_freeunmap)
789 memset(p, SOME_FREEJUNK, sz); 841 junk_free(d->malloc_junk, p, sz);
790 return p; 842 return p;
791 } 843 }
792 if (d->free_regions_size > d->malloc_cache) 844 if (d->free_regions_size > d->malloc_cache)
@@ -892,7 +944,7 @@ omalloc_make_chunks(struct dir_info *d, int bits, int listnum)
892 return bp; 944 return bp;
893 945
894err: 946err:
895 unmap(d, pp, MALLOC_PAGESIZE, 0, d->malloc_junk); 947 unmap(d, pp, MALLOC_PAGESIZE, 0);
896 return NULL; 948 return NULL;
897} 949}
898 950
@@ -1091,7 +1143,7 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
1091 1143
1092 if (info->size == 0 && !mopts.malloc_freeunmap) 1144 if (info->size == 0 && !mopts.malloc_freeunmap)
1093 mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE); 1145 mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE);
1094 unmap(d, info->page, MALLOC_PAGESIZE, 0, 0); 1146 unmap(d, info->page, MALLOC_PAGESIZE, 0);
1095 1147
1096 delete(d, r); 1148 delete(d, r);
1097 if (info->size != 0) 1149 if (info->size != 0)
@@ -1122,7 +1174,7 @@ omalloc(struct dir_info *pool, size_t sz, int zero_fill, void *f)
1122 return NULL; 1174 return NULL;
1123 } 1175 }
1124 if (insert(pool, p, sz, f)) { 1176 if (insert(pool, p, sz, f)) {
1125 unmap(pool, p, psz, 0, 0); 1177 unmap(pool, p, psz, 0);
1126 errno = ENOMEM; 1178 errno = ENOMEM;
1127 return NULL; 1179 return NULL;
1128 } 1180 }
@@ -1282,27 +1334,6 @@ malloc_conceal(size_t size)
1282} 1334}
1283DEF_WEAK(malloc_conceal); 1335DEF_WEAK(malloc_conceal);
1284 1336
1285static void
1286validate_junk(struct dir_info *pool, void *p)
1287{
1288 struct region_info *r;
1289 size_t byte, sz;
1290
1291 if (p == NULL)
1292 return;
1293 r = find(pool, p);
1294 if (r == NULL)
1295 wrterror(pool, "bogus pointer in validate_junk %p", p);
1296 REALSIZE(sz, r);
1297 if (sz > CHUNK_CHECK_LENGTH)
1298 sz = CHUNK_CHECK_LENGTH;
1299 for (byte = 0; byte < sz; byte++) {
1300 if (((unsigned char *)p)[byte] != SOME_FREEJUNK)
1301 wrterror(pool, "use after free %p", p);
1302 }
1303}
1304
1305
1306static struct region_info * 1337static struct region_info *
1307findpool(void *p, struct dir_info *argpool, struct dir_info **foundpool, 1338findpool(void *p, struct dir_info *argpool, struct dir_info **foundpool,
1308 char **saved_function) 1339 char **saved_function)
@@ -1402,8 +1433,7 @@ ofree(struct dir_info **argpool, void *p, int clear, int check, size_t argsz)
1402 } 1433 }
1403 STATS_SUB(pool->malloc_guarded, mopts.malloc_guard); 1434 STATS_SUB(pool->malloc_guarded, mopts.malloc_guard);
1404 } 1435 }
1405 unmap(pool, p, PAGEROUND(sz), clear ? argsz : 0, 1436 unmap(pool, p, PAGEROUND(sz), clear ? argsz : 0);
1406 pool->malloc_junk);
1407 delete(pool, r); 1437 delete(pool, r);
1408 } else { 1438 } else {
1409 /* Validate and optionally canary check */ 1439 /* Validate and optionally canary check */
@@ -1419,20 +1449,24 @@ ofree(struct dir_info **argpool, void *p, int clear, int check, size_t argsz)
1419 wrterror(pool, 1449 wrterror(pool,
1420 "double free %p", p); 1450 "double free %p", p);
1421 } 1451 }
1422 if (pool->malloc_junk && sz > 0) 1452 junk_free(pool->malloc_junk, p, sz);
1423 memset(p, SOME_FREEJUNK, sz);
1424 i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK; 1453 i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK;
1425 tmp = p; 1454 tmp = p;
1426 p = pool->delayed_chunks[i]; 1455 p = pool->delayed_chunks[i];
1427 if (tmp == p) 1456 if (tmp == p)
1428 wrterror(pool, "double free %p", tmp); 1457 wrterror(pool, "double free %p", tmp);
1429 pool->delayed_chunks[i] = tmp; 1458 pool->delayed_chunks[i] = tmp;
1430 if (pool->malloc_junk) 1459 if (p != NULL) {
1431 validate_junk(pool, p); 1460 r = find(pool, p);
1432 } else if (argsz > 0) 1461 REALSIZE(sz, r);
1462 if (r != NULL)
1463 validate_junk(pool, p, sz);
1464 }
1465 } else if (argsz > 0) {
1466 r = find(pool, p);
1433 memset(p, 0, argsz); 1467 memset(p, 0, argsz);
1468 }
1434 if (p != NULL) { 1469 if (p != NULL) {
1435 r = find(pool, p);
1436 if (r == NULL) 1470 if (r == NULL)
1437 wrterror(pool, 1471 wrterror(pool,
1438 "bogus pointer (double free?) %p", p); 1472 "bogus pointer (double free?) %p", p);
@@ -1969,7 +2003,7 @@ omemalign(struct dir_info *pool, size_t alignment, size_t sz, int zero_fill,
1969 } 2003 }
1970 2004
1971 if (insert(pool, p, sz, f)) { 2005 if (insert(pool, p, sz, f)) {
1972 unmap(pool, p, psz, 0, 0); 2006 unmap(pool, p, psz, 0);
1973 errno = ENOMEM; 2007 errno = ENOMEM;
1974 return NULL; 2008 return NULL;
1975 } 2009 }