reintroduce hardening against partially-replaced allocator
authorRich Felker <dalias@aerifal.cx>
Fri, 20 Apr 2018 02:19:29 +0000 (22:19 -0400)
committerRich Felker <dalias@aerifal.cx>
Fri, 20 Apr 2018 02:22:11 +0000 (22:22 -0400)
commit 618b18c78e33acfe54a4434e91aa57b8e171df89 removed the previous
detection and hardening since it was incorrect. commit
72141795d4edd17f88da192447395a48444afa10 already handled all that
remained for hardening the static-linked case. in the dynamic-linked
case, have the dynamic linker check whether malloc was replaced and
make that information available.

with these changes, the properties documented in commit
c9f415d7ea2dace5bf77f6518b6afc36bb7a5732 are restored: if calloc is
not provided, it will behave as malloc+memset, and any of the
memalign-family functions not provided will fail with ENOMEM.

ldso/dynlink.c
src/internal/malloc_impl.h
src/malloc/malloc.c
src/malloc/memalign.c

index 63e7b81fedf294c3d5ecef2a4ad4abb9891684ba..cea5f4521ec9255d257b0a346191c2095038d15a 100644 (file)
@@ -133,6 +133,9 @@ static struct dso *const nodeps_dummy;
 
 struct debug *_dl_debug_addr = &debug;
 
+__attribute__((__visibility__("hidden")))
+extern int __malloc_replaced;
+
 __attribute__((__visibility__("hidden")))
 void (*const __init_array_start)(void)=0, (*const __fini_array_start)(void)=0;
 
@@ -1691,6 +1694,12 @@ _Noreturn void __dls3(size_t *sp)
        if (ldso_fail) _exit(127);
        if (ldd_mode) _exit(0);
 
+       /* Determine if malloc was interposed by a replacement implementation
+        * so that calloc and the memalign family can harden against the
+        * possibility of incomplete replacement. */
+       if (find_sym(head, "malloc", 1).dso != &ldso)
+               __malloc_replaced = 1;
+
        /* Switch to runtime mode: any further failures in the dynamic
         * linker are a reportable failure rather than a fatal startup
         * error. */
index 4c4a4b461519863c59f6be01740e9585da214881..5d025b0640d776f2d2540adbc0de2936ebd9eb2f 100644 (file)
@@ -39,4 +39,7 @@ struct bin {
 __attribute__((__visibility__("hidden")))
 void __bin_chunk(struct chunk *);
 
+__attribute__((__visibility__("hidden")))
+extern int __malloc_replaced;
+
 #endif
index 239ab9c6ba2cdf159ef041c41b3eba7d01b87d93..d72883e1371687b0916c5270fd7d944335b6d0c5 100644 (file)
@@ -20,6 +20,8 @@ static struct {
        volatile int free_lock[2];
 } mal;
 
+int __malloc_replaced;
+
 /* Synchronization tools */
 
 static inline void lock(volatile int *lk)
@@ -356,10 +358,13 @@ void *calloc(size_t m, size_t n)
        }
        n *= m;
        void *p = malloc(n);
-       if (!p || IS_MMAPPED(MEM_TO_CHUNK(p)))
-               return p;
-       if (n >= PAGE_SIZE)
-               n = mal0_clear(p, PAGE_SIZE, n);
+       if (!p) return p;
+       if (!__malloc_replaced) {
+               if (IS_MMAPPED(MEM_TO_CHUNK(p)))
+                       return p;
+               if (n >= PAGE_SIZE)
+                       n = mal0_clear(p, PAGE_SIZE, n);
+       }
        return memset(p, 0, n);
 }
 
index 7246a99b808a27cea8d758ec35df83392e09009a..8a6152f466edd4860abbd319170bb9bff9b47d43 100644 (file)
@@ -13,7 +13,7 @@ void *__memalign(size_t align, size_t len)
                return 0;
        }
 
-       if (len > SIZE_MAX - align) {
+       if (len > SIZE_MAX - align || __malloc_replaced) {
                errno = ENOMEM;
                return 0;
        }