Instead of always using a fixed byte pattern, I think malloc should use a
random pattern. Now, this sometimes means it's harder to identify exactly
what's used after free, so we should provide a means to get the old 0xdf
pattern back.

Since we already have two junk modes, I thought I'd carry on along those
lines. The default junk behavior, for free chunks only, is more of a security
measure. I think this means we want random junk. The second level 'J' junk is
more of a debugging tool, so that retains 0xdf.

There's some overlap here with canaries, but nothing wrong with that. :)

Index: malloc.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/malloc.c,v
retrieving revision 1.195
diff -u -p -r1.195 malloc.c
--- malloc.c    1 Sep 2016 10:41:02 -0000       1.195
+++ malloc.c    7 Sep 2016 22:21:37 -0000
@@ -186,6 +186,7 @@ struct malloc_readonly {
 #endif
        u_int32_t malloc_canary;        /* Matched against ones in malloc_pool 
*/
        uintptr_t malloc_chunk_canary;
+       u_char  malloc_junkbytes[256];
 };
 
 /* This object is mapped PROT_READ after initialisation to prevent tampering */
@@ -597,6 +598,8 @@ omalloc_init(void)
        mopts.malloc_move = 1;
        mopts.malloc_cache = MALLOC_DEFAULT_CACHE;
 
+       arc4random_buf(mopts.malloc_junkbytes, sizeof(mopts.malloc_junkbytes));
+
        for (i = 0; i < 3; i++) {
                switch (i) {
                case 0:
@@ -1260,7 +1263,29 @@ malloc(size_t size)
 /*DEF_STRONG(malloc);*/
 
 static void
-validate_junk(struct dir_info *pool, void *p) {
+random_junk(void *p, size_t amt)
+{
+       u_long offset = ((u_long)p) & (sizeof(mopts.malloc_junkbytes) - 1);
+
+       if (amt < sizeof(mopts.malloc_junkbytes) - offset) {
+               memcpy(p, mopts.malloc_junkbytes + offset, amt);
+       } else {
+               memcpy(p, mopts.malloc_junkbytes + offset,
+                   sizeof(mopts.malloc_junkbytes) - offset);
+               amt -= sizeof(mopts.malloc_junkbytes) - offset;
+               while (amt > 0) {
+                       size_t x = amt > sizeof(mopts.malloc_junkbytes) ?
+                               sizeof(mopts.malloc_junkbytes) : amt;
+                       memcpy(p, mopts.malloc_junkbytes, x);
+                       amt -= x;
+               }
+       }
+}
+
+
+static void
+validate_junk(struct dir_info *pool, void *p)
+{
        struct region_info *r;
        size_t byte, sz;
 
@@ -1274,9 +1299,15 @@ validate_junk(struct dir_info *pool, voi
                sz -= mopts.malloc_canaries;
        if (sz > 32)
                sz = 32;
-       for (byte = 0; byte < sz; byte++) {
-               if (((unsigned char *)p)[byte] != SOME_FREEJUNK)
+       if (mopts.malloc_junk == 1) {
+               u_long offset = ((u_long)p) & (sizeof(mopts.malloc_junkbytes) - 
1);
+               if (memcmp(p, mopts.malloc_junkbytes + offset, sz) != 0)
                        wrterror(pool, "use after free", p);
+       } else {
+               for (byte = 0; byte < sz; byte++) {
+                       if (((unsigned char *)p)[byte] != SOME_FREEJUNK)
+                               wrterror(pool, "use after free", p);
+               }
        }
 }
 
@@ -1336,10 +1367,11 @@ ofree(struct dir_info *argpool, void *p)
                        }
                        STATS_SUB(pool->malloc_guarded, mopts.malloc_guard);
                }
-               if (mopts.malloc_junk && !mopts.malloc_freeunmap) {
-                       size_t amt = mopts.malloc_junk == 1 ? MALLOC_MAXCHUNK :
-                           PAGEROUND(sz) - mopts.malloc_guard;
-                       memset(p, SOME_FREEJUNK, amt);
+               if (mopts.malloc_junk == 2 && !mopts.malloc_freeunmap) {
+                       memset(p, SOME_FREEJUNK,
+                           PAGEROUND(sz) - mopts.malloc_guard);
+               } else if (mopts.malloc_junk == 1 && !mopts.malloc_freeunmap) {
+                       random_junk(p, MALLOC_MAXCHUNK); 
                }
                unmap(pool, p, PAGEROUND(sz));
                delete(pool, r);
@@ -1347,8 +1379,10 @@ ofree(struct dir_info *argpool, void *p)
                void *tmp;
                int i;
 
-               if (mopts.malloc_junk && sz > 0)
+               if (mopts.malloc_junk == 2 && sz > 0)
                        memset(p, SOME_FREEJUNK, sz - mopts.malloc_canaries);
+               else if (mopts.malloc_junk == 1 && sz > 0)
+                       random_junk(p, sz);
                if (!mopts.malloc_freenow) {
                        if (find_chunknum(pool, r, p) == -1)
                                goto done;

Reply via email to