harden realloc/free to detect simple overflows
[musl] / src / malloc / malloc.c
index abf3e8f..4044eb2 100644 (file)
@@ -9,6 +9,10 @@
 #include "atomic.h"
 #include "pthread_impl.h"
 
+#if defined(__GNUC__) && defined(__PIC__)
+#define inline inline __attribute__((always_inline))
+#endif
+
 uintptr_t __brk(uintptr_t);
 void *__mmap(void *, size_t, int, int, int, off_t);
 int __munmap(void *, size_t);
@@ -43,8 +47,8 @@ static struct {
 #define DONTCARE 16
 #define RECLAIM 163840
 
-#define CHUNK_SIZE(c) ((c)->csize & SIZE_MASK)
-#define CHUNK_PSIZE(c) ((c)->psize & SIZE_MASK)
+#define CHUNK_SIZE(c) ((c)->csize & -2)
+#define CHUNK_PSIZE(c) ((c)->psize & -2)
 #define PREV_CHUNK(c) ((struct chunk *)((char *)(c) - CHUNK_PSIZE(c)))
 #define NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CHUNK_SIZE(c)))
 #define MEM_TO_CHUNK(p) (struct chunk *)((char *)(p) - OVERHEAD)
@@ -52,28 +56,26 @@ static struct {
 #define BIN_TO_CHUNK(i) (MEM_TO_CHUNK(&mal.bins[i].head))
 
 #define C_INUSE  ((size_t)1)
-#define C_FLAGS  ((size_t)3)
-#define C_SIZE   SIZE_MASK
 
 #define IS_MMAPPED(c) !((c)->csize & (C_INUSE))
 
 
 /* Synchronization tools */
 
-static void lock(volatile int *lk)
+static inline void lock(volatile int *lk)
 {
        if (!libc.threads_minus_1) return;
        while(a_swap(lk, 1)) __wait(lk, lk+1, 1, 1);
 }
 
-static void unlock(volatile int *lk)
+static inline void unlock(volatile int *lk)
 {
        if (!libc.threads_minus_1) return;
        a_store(lk, 0);
        if (lk[1]) __wake(lk, 1, 1);
 }
 
-static void lock_bin(int i)
+static inline void lock_bin(int i)
 {
        if (libc.threads_minus_1)
                lock(mal.bins[i].lock);
@@ -81,7 +83,7 @@ static void lock_bin(int i)
                mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i);
 }
 
-static void unlock_bin(int i)
+static inline void unlock_bin(int i)
 {
        if (!libc.threads_minus_1) return;
        unlock(mal.bins[i].lock);
@@ -194,7 +196,11 @@ static int init_malloc(size_t n)
                return 0;
        }
 
-       mal.brk = __brk(0) + 2*SIZE_ALIGN-1 & -SIZE_ALIGN;
+       mal.brk = __brk(0);
+#ifdef SHARED
+       mal.brk = mal.brk + PAGE_SIZE-1 & -PAGE_SIZE;
+#endif
+       mal.brk = mal.brk + 2*SIZE_ALIGN-1 & -SIZE_ALIGN;
 
        c = expand_heap(n);
 
@@ -412,6 +418,9 @@ void *realloc(void *p, size_t n)
 
        next = NEXT_CHUNK(self);
 
+       /* Crash on corrupted footer (likely from buffer overflow) */
+       if (next->psize != self->csize) a_crash();
+
        /* Merge adjacent chunks if we need more space. This is not
         * a waste of time even if we fail to get enough space, because our
         * subsequent call to free would otherwise have to do the merge. */
@@ -465,6 +474,9 @@ void free(void *p)
        final_size = new_size = CHUNK_SIZE(self);
        next = NEXT_CHUNK(self);
 
+       /* Crash on corrupted footer (likely from buffer overflow) */
+       if (next->psize != self->csize) a_crash();
+
        for (;;) {
                /* Replace middle of large chunks with fresh zero pages */
                if (reclaim && (self->psize & next->csize & C_INUSE)) {