summaryrefslogtreecommitdiff
path: root/libc/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'libc/stdlib')
-rw-r--r--libc/stdlib/getenv.c2
-rw-r--r--libc/stdlib/malloc-simple/alloc.c20
-rw-r--r--libc/stdlib/malloc-standard/free.c5
-rw-r--r--libc/stdlib/malloc-standard/mallinfo.c3
-rw-r--r--libc/stdlib/malloc-standard/malloc.c7
-rw-r--r--libc/stdlib/malloc-standard/malloc.h16
-rw-r--r--libc/stdlib/malloc-standard/reallocarray.c36
-rw-r--r--libc/stdlib/malloc/memalign.c14
-rw-r--r--libc/stdlib/random.c14
9 files changed, 102 insertions, 15 deletions
diff --git a/libc/stdlib/getenv.c b/libc/stdlib/getenv.c
index 9b04d0fab..a1a65e6c7 100644
--- a/libc/stdlib/getenv.c
+++ b/libc/stdlib/getenv.c
@@ -20,7 +20,7 @@ char *getenv(const char *var)
return NULL;
len = strlen(var);
while(*ep) {
- if (memcmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
+ if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
return *ep + len + 1;
}
ep++;
diff --git a/libc/stdlib/malloc-simple/alloc.c b/libc/stdlib/malloc-simple/alloc.c
index 3baf75fdd..757a05ecf 100644
--- a/libc/stdlib/malloc-simple/alloc.c
+++ b/libc/stdlib/malloc-simple/alloc.c
@@ -13,6 +13,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdint.h>
#include <errno.h>
#include <sys/mman.h>
#include <malloc.h>
@@ -28,6 +29,15 @@ void *malloc(size_t size)
size++;
}
+ /* prevent Undefined Behaviour for pointer arithmetic (substract) of too big pointers
+ * see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63303
+ * No need to check for size + sizeof(size_t) integer overflow since we already check for PTRDIFF_MAX
+ */
+ if (unlikely(size > PTRDIFF_MAX)) {
+ __set_errno(ENOMEM);
+ return 0;
+ }
+
#ifdef __ARCH_USE_MMU__
# define MMAP_FLAGS MAP_PRIVATE | MAP_ANONYMOUS
#else
@@ -148,6 +158,16 @@ void * memalign (size_t alignment, size_t size)
void * result;
unsigned long int adj;
+ if (unlikely(size > PTRDIFF_MAX)) {
+ __set_errno(ENOMEM);
+ return NULL;
+ }
+
+ if (unlikely((size + alignment - 1 < size) && (alignment != 0))) {
+ __set_errno(ENOMEM);
+ return NULL;
+ }
+
result = malloc (size + alignment - 1);
if (result == NULL)
return NULL;
diff --git a/libc/stdlib/malloc-standard/free.c b/libc/stdlib/malloc-standard/free.c
index a2d765d41..f3602cf48 100644
--- a/libc/stdlib/malloc-standard/free.c
+++ b/libc/stdlib/malloc-standard/free.c
@@ -214,8 +214,9 @@ void attribute_hidden __malloc_consolidate(mstate av)
*fb = 0;
do {
+ CHECK_PTR(p);
check_inuse_chunk(p);
- nextp = p->fd;
+ nextp = REVEAL_PTR(&p->fd, p->fd);
/* Slightly streamlined version of consolidation code in free() */
size = p->size & ~PREV_INUSE;
@@ -308,7 +309,7 @@ void free(void* mem)
set_fastchunks(av);
fb = &(av->fastbins[fastbin_index(size)]);
- p->fd = *fb;
+ p->fd = PROTECT_PTR(&p->fd, *fb);
*fb = p;
}
diff --git a/libc/stdlib/malloc-standard/mallinfo.c b/libc/stdlib/malloc-standard/mallinfo.c
index dbe4d49b8..992322341 100644
--- a/libc/stdlib/malloc-standard/mallinfo.c
+++ b/libc/stdlib/malloc-standard/mallinfo.c
@@ -49,7 +49,8 @@ struct mallinfo mallinfo(void)
fastavail = 0;
for (i = 0; i < NFASTBINS; ++i) {
- for (p = av->fastbins[i]; p != 0; p = p->fd) {
+ for (p = av->fastbins[i]; p != 0; p = REVEAL_PTR(&p->fd, p->fd)) {
+ CHECK_PTR(p);
++nfastblocks;
fastavail += chunksize(p);
}
diff --git a/libc/stdlib/malloc-standard/malloc.c b/libc/stdlib/malloc-standard/malloc.c
index 1a6d4dc1c..cecea87ec 100644
--- a/libc/stdlib/malloc-standard/malloc.c
+++ b/libc/stdlib/malloc-standard/malloc.c
@@ -176,6 +176,7 @@ void __do_check_remalloced_chunk(mchunkptr p, size_t s)
size_t sz = p->size & ~PREV_INUSE;
#endif
+ (void)s;
__do_check_inuse_chunk(p);
/* Legal size ... */
@@ -260,12 +261,13 @@ void __do_check_malloc_state(void)
assert(p == 0);
while (p != 0) {
+ CHECK_PTR(p);
/* each chunk claims to be inuse */
__do_check_inuse_chunk(p);
total += chunksize(p);
/* chunk belongs in this bin */
assert(fastbin_index(chunksize(p)) == i);
- p = p->fd;
+ p = REVEAL_PTR(&p->fd, p->fd);
}
}
@@ -855,7 +857,8 @@ void* malloc(size_t bytes)
if ((unsigned long)(nb) <= (unsigned long)(av->max_fast)) {
fb = &(av->fastbins[(fastbin_index(nb))]);
if ( (victim = *fb) != 0) {
- *fb = victim->fd;
+ CHECK_PTR(victim);
+ *fb = REVEAL_PTR(&victim->fd, victim->fd);
check_remalloced_chunk(victim, nb);
retval = chunk2mem(victim);
goto DONE;
diff --git a/libc/stdlib/malloc-standard/malloc.h b/libc/stdlib/malloc-standard/malloc.h
index 44120d388..f196a560f 100644
--- a/libc/stdlib/malloc-standard/malloc.h
+++ b/libc/stdlib/malloc-standard/malloc.h
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <sys/mman.h>
#include <bits/uClibc_mutex.h>
+#include <bits/uClibc_page.h>
@@ -839,6 +840,21 @@ typedef struct malloc_chunk* mfastbinptr;
#define get_max_fast(M) \
((M)->max_fast & ~(FASTCHUNKS_BIT | ANYCHUNKS_BIT))
+/*
+ Safe-Linking:
+ Use randomness from ASLR (mmap_base) to protect single-linked lists
+ of fastbins. Together with allocation alignment checks, this mechanism
+ reduces the risk of pointer hijacking, as was done with Safe-Unlinking
+ in the double-linked lists of smallbins.
+*/
+#define PROTECT_PTR(pos, ptr) ((mchunkptr)((((size_t)pos) >> PAGE_SHIFT) ^ ((size_t)ptr)))
+#define REVEAL_PTR(pos, ptr) PROTECT_PTR(pos, ptr)
+#define PTR_FOR_ALIGNMENT_CHECK(P) \
+ (MALLOC_ALIGNMENT == 2*(sizeof(size_t)) ? (P) : chunk2mem(P))
+
+#define CHECK_PTR(P) \
+ if (!aligned_OK(PTR_FOR_ALIGNMENT_CHECK(P))) \
+ abort();
/*
morecore_properties is a status word holding dynamically discovered
diff --git a/libc/stdlib/malloc-standard/reallocarray.c b/libc/stdlib/malloc-standard/reallocarray.c
new file mode 100644
index 000000000..e4044c3f5
--- /dev/null
+++ b/libc/stdlib/malloc-standard/reallocarray.c
@@ -0,0 +1,36 @@
+/*
+Copyright © 2005-2020 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#define _BSD_SOURCE
+#include <errno.h>
+#include <stdlib.h>
+
+void *reallocarray(void *ptr, size_t m, size_t n)
+{
+ if (n && m > -1 / n) {
+ errno = ENOMEM;
+ return 0;
+ }
+
+ return realloc(ptr, m * n);
+}
diff --git a/libc/stdlib/malloc/memalign.c b/libc/stdlib/malloc/memalign.c
index 6943279ac..54f6dbc6c 100644
--- a/libc/stdlib/malloc/memalign.c
+++ b/libc/stdlib/malloc/memalign.c
@@ -11,6 +11,7 @@
* Written by Miles Bader <miles@gnu.org>
*/
+#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
@@ -38,6 +39,11 @@ memalign (size_t alignment, size_t size)
unsigned long tot_addr, tot_end_addr, addr, end_addr;
struct heap_free_area **heap = &__malloc_heap;
+ if (unlikely(size > PTRDIFF_MAX)) {
+ __set_errno(ENOMEM);
+ return NULL;
+ }
+
/* Make SIZE something we like. */
size = HEAP_ADJUST_SIZE (size);
@@ -77,7 +83,9 @@ memalign (size_t alignment, size_t size)
init_size = addr - tot_addr;
}
+ __heap_lock (&__malloc_heap_lock);
__heap_free (heap, base, init_size);
+ __heap_unlock (&__malloc_heap_lock);
/* Remember that we've freed the initial part of MEM. */
base += init_size;
@@ -85,9 +93,11 @@ memalign (size_t alignment, size_t size)
/* Return the end part of MEM to the heap, unless it's too small. */
end_addr = addr + size;
- if (end_addr + MALLOC_REALLOC_MIN_FREE_SIZE < tot_end_addr)
+ if (end_addr + MALLOC_REALLOC_MIN_FREE_SIZE < tot_end_addr) {
+ __heap_lock (&__malloc_heap_lock);
__heap_free (heap, (void *)end_addr, tot_end_addr - end_addr);
- else
+ __heap_unlock (&__malloc_heap_lock);
+ } else
/* We didn't free the end, so include it in the size. */
end_addr = tot_end_addr;
diff --git a/libc/stdlib/random.c b/libc/stdlib/random.c
index b009c4310..05ce3fe84 100644
--- a/libc/stdlib/random.c
+++ b/libc/stdlib/random.c
@@ -139,8 +139,8 @@ static struct random_data unsafe_state =
in the initialization of randtbl) because the state table pointer is set
to point to randtbl[1] (as explained below).) */
- fptr : &randtbl[SEP_3 + 1],
- rptr : &randtbl[1],
+ .fptr = &randtbl[SEP_3 + 1],
+ .rptr = &randtbl[1],
/* The following things are the pointer to the state information table,
the type of the current generator, the degree of the current polynomial
@@ -152,13 +152,13 @@ static struct random_data unsafe_state =
indexing every time to find the address of the last element to see if
the front and rear pointers have wrapped. */
- state : &randtbl[1],
+ .state = &randtbl[1],
- rand_type : TYPE_3,
- rand_deg : DEG_3,
- rand_sep : SEP_3,
+ .rand_type = TYPE_3,
+ .rand_deg = DEG_3,
+ .rand_sep = SEP_3,
- end_ptr : &randtbl[sizeof (randtbl) / sizeof (randtbl[0])]
+ .end_ptr = &randtbl[sizeof (randtbl) / sizeof (randtbl[0])]
};