mirror of
https://github.com/GrapheneOS/hardened_malloc.git
synced 2025-04-19 22:10:19 +02:00
Compare commits
2 commits
a73585cc39
...
fc042d5daa
Author | SHA1 | Date | |
---|---|---|---|
|
fc042d5daa | ||
|
0cada13b78 |
16 changed files with 169 additions and 8 deletions
2
CREDITS
2
CREDITS
|
@ -23,7 +23,7 @@ h_malloc.c open-addressed hash table (regions_grow, regions_insert, regions_find
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
memcpy.c, memmove.c, memset.c, wmemset.c:
|
memcpy.c, memccpy.c, memmove.c, memset.c, wmemset.c:
|
||||||
Copyright © 2005-2020 Rich Felker, et al.
|
Copyright © 2005-2020 Rich Felker, et al.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -41,7 +41,7 @@ LDFLAGS := $(LDFLAGS) -Wl,-O1,--as-needed,-z,defs,-z,relro,-z,now,-z,nodlopen,-z
|
||||||
|
|
||||||
SOURCES := chacha.c h_malloc.c memory.c pages.c random.c util.c
|
SOURCES := chacha.c h_malloc.c memory.c pages.c random.c util.c
|
||||||
ifeq ($(CONFIG_BLOCK_OPS_CHECK_SIZE),true)
|
ifeq ($(CONFIG_BLOCK_OPS_CHECK_SIZE),true)
|
||||||
SOURCES += memcpy.c memmove.c memset.c wmemset.c
|
SOURCES += memcpy.c memccpy.c memmove.c memset.c wmemset.c
|
||||||
BOSC_EXTRAS := musl.h
|
BOSC_EXTRAS := musl.h
|
||||||
endif
|
endif
|
||||||
OBJECTS := $(SOURCES:.c=.o)
|
OBJECTS := $(SOURCES:.c=.o)
|
||||||
|
@ -135,13 +135,15 @@ $(OUT)/new.o: new.cc include/h_malloc.h util.h $(CONFIG_FILE) | $(OUT)
|
||||||
$(COMPILE.cc) $(OUTPUT_OPTION) $<
|
$(COMPILE.cc) $(OUTPUT_OPTION) $<
|
||||||
$(OUT)/pages.o: pages.c pages.h memory.h util.h $(CONFIG_FILE) | $(OUT)
|
$(OUT)/pages.o: pages.c pages.h memory.h util.h $(CONFIG_FILE) | $(OUT)
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
$(OUT)/random.o: random.c random.h chacha.h util.h $(CONFIG_FILE) | $(OUT)
|
$(OUT)/random.o: random.c random.h chacha.h $(BOSC_EXTRAS) util.h $(CONFIG_FILE) | $(OUT)
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
$(OUT)/util.o: util.c util.h $(CONFIG_FILE) | $(OUT)
|
$(OUT)/util.o: util.c util.h $(CONFIG_FILE) | $(OUT)
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
$(OUT)/memcpy.o: memcpy.c musl.h $(CONFIG_FILE) | $(OUT)
|
$(OUT)/memcpy.o: memcpy.c musl.h $(CONFIG_FILE) | $(OUT)
|
||||||
$(COMPILE.c) -Wno-cast-align $(OUTPUT_OPTION) $<
|
$(COMPILE.c) -Wno-cast-align $(OUTPUT_OPTION) $<
|
||||||
|
$(OUT)/memccpy.o: memccpy.c musl.h $(CONFIG_FILE) | $(OUT)
|
||||||
|
$(COMPILE.c) -Wno-cast-align $(OUTPUT_OPTION) $<
|
||||||
$(OUT)/memmove.o: memmove.c musl.h $(CONFIG_FILE) | $(OUT)
|
$(OUT)/memmove.o: memmove.c musl.h $(CONFIG_FILE) | $(OUT)
|
||||||
$(COMPILE.c) -Wno-cast-align $(OUTPUT_OPTION) $<
|
$(COMPILE.c) -Wno-cast-align $(OUTPUT_OPTION) $<
|
||||||
$(OUT)/memset.o: memset.c musl.h $(CONFIG_FILE) | $(OUT)
|
$(OUT)/memset.o: memset.c musl.h $(CONFIG_FILE) | $(OUT)
|
||||||
|
|
|
@ -277,8 +277,8 @@ The following boolean configuration options are available:
|
||||||
this feature is enabled, the metadata is all contained within an isolated
|
this feature is enabled, the metadata is all contained within an isolated
|
||||||
memory region with high entropy random guard regions around it.
|
memory region with high entropy random guard regions around it.
|
||||||
* `CONFIG_BLOCK_OPS_CHECK_SIZE`: `true` or `false` (default) to ensure length
|
* `CONFIG_BLOCK_OPS_CHECK_SIZE`: `true` or `false` (default) to ensure length
|
||||||
parameter of the memcpy/memmove/memset block operations and their wide
|
parameter of the memcpy/memccpy/memmove/memset block operations and their
|
||||||
variants are within approximate bounds to minimize buffer overflows.
|
wide variants are within approximate bounds to minimize buffer overflows.
|
||||||
|
|
||||||
The following integer configuration options are available:
|
The following integer configuration options are available:
|
||||||
|
|
||||||
|
|
16
h_malloc.c
16
h_malloc.c
|
@ -1895,6 +1895,22 @@ EXPORT void *memcpy(void *restrict dst, const void *restrict src, size_t len) {
|
||||||
return musl_memcpy(dst, src, len);
|
return musl_memcpy(dst, src, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT void *memccpy(void *restrict dst, const void *restrict src, int value, size_t len) {
|
||||||
|
if (unlikely(dst == src || len == 0)) {
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
if (unlikely(dst < (src + len) && (dst + len) > src)) {
|
||||||
|
fatal_error("memccpy overlap");
|
||||||
|
}
|
||||||
|
if (unlikely(len > malloc_object_size(src))) {
|
||||||
|
fatal_error("memccpy read overflow");
|
||||||
|
}
|
||||||
|
if (unlikely(len > malloc_object_size(dst))) {
|
||||||
|
fatal_error("memccpy buffer overflow");
|
||||||
|
}
|
||||||
|
return musl_memccpy(dst, src, value, len);
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT void *memmove(void *dst, const void *src, size_t len) {
|
EXPORT void *memmove(void *dst, const void *src, size_t len) {
|
||||||
if (unlikely(dst == src || len == 0)) {
|
if (unlikely(dst == src || len == 0)) {
|
||||||
return dst;
|
return dst;
|
||||||
|
|
|
@ -57,6 +57,7 @@ void h_free(void *ptr);
|
||||||
|
|
||||||
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
|
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
|
||||||
void *memcpy(void *dst, const void *src, size_t len);
|
void *memcpy(void *dst, const void *src, size_t len);
|
||||||
|
void *memccpy(void *dst, const void *src, int value, size_t len);
|
||||||
void *memmove(void *dst, const void *src, size_t len);
|
void *memmove(void *dst, const void *src, size_t len);
|
||||||
void *memset(void *dst, int value, size_t len);
|
void *memset(void *dst, int value, size_t len);
|
||||||
wchar_t *wmemcpy(wchar_t *dst, const wchar_t *src, size_t len);
|
wchar_t *wmemcpy(wchar_t *dst, const wchar_t *src, size_t len);
|
||||||
|
|
38
memccpy.c
Normal file
38
memccpy.c
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include "musl.h"
|
||||||
|
|
||||||
|
/* Copied from musl libc version 1.2.5 licensed under the MIT license */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#define ALIGN (sizeof(size_t)-1)
|
||||||
|
#define ONES ((size_t)-1/UCHAR_MAX)
|
||||||
|
#define HIGHS (ONES * (UCHAR_MAX/2+1))
|
||||||
|
#define HASZERO(x) (((x)-ONES) & ~(x) & HIGHS)
|
||||||
|
|
||||||
|
void *musl_memccpy(void *restrict dest, const void *restrict src, int c, size_t n)
|
||||||
|
{
|
||||||
|
unsigned char *d = dest;
|
||||||
|
const unsigned char *s = src;
|
||||||
|
|
||||||
|
c = (unsigned char)c;
|
||||||
|
#ifdef __GNUC__
|
||||||
|
typedef size_t __attribute__((__may_alias__)) word;
|
||||||
|
word *wd;
|
||||||
|
const word *ws;
|
||||||
|
if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
|
||||||
|
for (; ((uintptr_t)s & ALIGN) && n && (*d=*s)!=c; n--, s++, d++);
|
||||||
|
if ((uintptr_t)s & ALIGN) goto tail;
|
||||||
|
size_t k = ONES * c;
|
||||||
|
wd=(void *)d; ws=(const void *)s;
|
||||||
|
for (; n>=sizeof(size_t) && !HASZERO(*ws^k);
|
||||||
|
n-=sizeof(size_t), ws++, wd++) *wd = *ws;
|
||||||
|
d=(void *)wd; s=(const void *)ws;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (; n && (*d=*s)!=c; n--, s++, d++);
|
||||||
|
tail:
|
||||||
|
if (n) return d+1;
|
||||||
|
return 0;
|
||||||
|
}
|
1
musl.h
1
musl.h
|
@ -3,6 +3,7 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
void *musl_memcpy(void *dst, const void *src, size_t len);
|
void *musl_memcpy(void *dst, const void *src, size_t len);
|
||||||
|
void *musl_memccpy(void *restrict dest, const void *restrict src, int c, size_t n);
|
||||||
void *musl_memmove(void *dst, const void *src, size_t len);
|
void *musl_memmove(void *dst, const void *src, size_t len);
|
||||||
void *musl_memset(void *dst, int value, size_t len);
|
void *musl_memset(void *dst, int value, size_t len);
|
||||||
wchar_t *musl_wmemset(wchar_t *dst, wchar_t value, size_t len);
|
wchar_t *musl_wmemset(wchar_t *dst, wchar_t value, size_t len);
|
||||||
|
|
10
random.c
10
random.c
|
@ -5,6 +5,10 @@
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
|
||||||
|
#include "musl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sys/random.h>
|
#include <sys/random.h>
|
||||||
|
|
||||||
static void get_random_seed(void *buf, size_t size) {
|
static void get_random_seed(void *buf, size_t size) {
|
||||||
|
@ -65,7 +69,7 @@ void get_random_bytes(struct random_state *state, void *buf, size_t size) {
|
||||||
|
|
||||||
size_t remaining = RANDOM_CACHE_SIZE - state->index;
|
size_t remaining = RANDOM_CACHE_SIZE - state->index;
|
||||||
size_t copy_size = min(size, remaining);
|
size_t copy_size = min(size, remaining);
|
||||||
memcpy(buf, state->cache + state->index, copy_size);
|
h_memcpy_internal(buf, state->cache + state->index, copy_size);
|
||||||
state->index += copy_size;
|
state->index += copy_size;
|
||||||
|
|
||||||
buf = (char *)buf + copy_size;
|
buf = (char *)buf + copy_size;
|
||||||
|
@ -79,7 +83,7 @@ u16 get_random_u16(struct random_state *state) {
|
||||||
if (remaining < sizeof(value)) {
|
if (remaining < sizeof(value)) {
|
||||||
refill(state);
|
refill(state);
|
||||||
}
|
}
|
||||||
memcpy(&value, state->cache + state->index, sizeof(value));
|
h_memcpy_internal(&value, state->cache + state->index, sizeof(value));
|
||||||
state->index += sizeof(value);
|
state->index += sizeof(value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +110,7 @@ u64 get_random_u64(struct random_state *state) {
|
||||||
if (remaining < sizeof(value)) {
|
if (remaining < sizeof(value)) {
|
||||||
refill(state);
|
refill(state);
|
||||||
}
|
}
|
||||||
memcpy(&value, state->cache + state->index, sizeof(value));
|
h_memcpy_internal(&value, state->cache + state->index, sizeof(value));
|
||||||
state->index += sizeof(value);
|
state->index += sizeof(value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
6
random.h
6
random.h
|
@ -22,4 +22,10 @@ u16 get_random_u16_uniform(struct random_state *state, u16 bound);
|
||||||
u64 get_random_u64(struct random_state *state);
|
u64 get_random_u64(struct random_state *state);
|
||||||
u64 get_random_u64_uniform(struct random_state *state, u64 bound);
|
u64 get_random_u64_uniform(struct random_state *state, u64 bound);
|
||||||
|
|
||||||
|
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
|
||||||
|
#define h_memcpy_internal musl_memcpy
|
||||||
|
#else
|
||||||
|
#define h_memcpy_internal memcpy
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
4
test/.gitignore
vendored
4
test/.gitignore
vendored
|
@ -45,6 +45,10 @@ memcpy_buffer_overflow
|
||||||
memcpy_read_overflow
|
memcpy_read_overflow
|
||||||
memcpy_valid_same
|
memcpy_valid_same
|
||||||
memcpy_valid_mismatched
|
memcpy_valid_mismatched
|
||||||
|
memccpy_buffer_overflow
|
||||||
|
memccpy_read_overflow
|
||||||
|
memccpy_valid_same
|
||||||
|
memccpy_valid_mismatched
|
||||||
memmove_buffer_overflow
|
memmove_buffer_overflow
|
||||||
memmove_read_overflow
|
memmove_read_overflow
|
||||||
memmove_valid_same
|
memmove_valid_same
|
||||||
|
|
|
@ -72,6 +72,10 @@ EXECUTABLES := \
|
||||||
memcpy_read_overflow \
|
memcpy_read_overflow \
|
||||||
memcpy_valid_same \
|
memcpy_valid_same \
|
||||||
memcpy_valid_mismatched \
|
memcpy_valid_mismatched \
|
||||||
|
memccpy_buffer_overflow \
|
||||||
|
memccpy_read_overflow \
|
||||||
|
memccpy_valid_same \
|
||||||
|
memccpy_valid_mismatched \
|
||||||
memmove_buffer_overflow \
|
memmove_buffer_overflow \
|
||||||
memmove_read_overflow \
|
memmove_read_overflow \
|
||||||
memmove_valid_same \
|
memmove_valid_same \
|
||||||
|
|
15
test/memccpy_buffer_overflow.c
Normal file
15
test/memccpy_buffer_overflow.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "test_util.h"
|
||||||
|
|
||||||
|
OPTNONE int main(void) {
|
||||||
|
char *firstbuffer = malloc(16);
|
||||||
|
char *secondbuffer = malloc(32);
|
||||||
|
if (!firstbuffer && !secondbuffer) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memset(secondbuffer, 'a', 32);
|
||||||
|
memccpy(firstbuffer, secondbuffer, 'b', 32);
|
||||||
|
return 1;
|
||||||
|
}
|
15
test/memccpy_read_overflow.c
Normal file
15
test/memccpy_read_overflow.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "test_util.h"
|
||||||
|
|
||||||
|
OPTNONE int main(void) {
|
||||||
|
char *firstbuffer = malloc(32);
|
||||||
|
char *secondbuffer = malloc(16);
|
||||||
|
if (!firstbuffer && !secondbuffer) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memset(secondbuffer, 'a', 16);
|
||||||
|
memccpy(firstbuffer, secondbuffer, 'b', 32);
|
||||||
|
return 1;
|
||||||
|
}
|
15
test/memccpy_valid_mismatched.c
Normal file
15
test/memccpy_valid_mismatched.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "test_util.h"
|
||||||
|
|
||||||
|
OPTNONE int main(void) {
|
||||||
|
char *firstbuffer = malloc(32);
|
||||||
|
char *secondbuffer = malloc(16);
|
||||||
|
if (!firstbuffer && !secondbuffer) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memset(secondbuffer, 'a', 16);
|
||||||
|
memccpy(firstbuffer, secondbuffer, 'b', 16);
|
||||||
|
return 0;
|
||||||
|
}
|
15
test/memccpy_valid_same.c
Normal file
15
test/memccpy_valid_same.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "test_util.h"
|
||||||
|
|
||||||
|
OPTNONE int main(void) {
|
||||||
|
char *firstbuffer = malloc(16);
|
||||||
|
char *secondbuffer = malloc(16);
|
||||||
|
if (!firstbuffer && !secondbuffer) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memset(secondbuffer, 'a', 16);
|
||||||
|
memccpy(firstbuffer, secondbuffer, 'b', 16);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -262,6 +262,31 @@ class TestSimpleMemoryCorruption(unittest.TestCase):
|
||||||
"memcpy_valid_mismatched")
|
"memcpy_valid_mismatched")
|
||||||
self.assertEqual(returncode, 0)
|
self.assertEqual(returncode, 0)
|
||||||
|
|
||||||
|
#def test_memccpy_buffer_overflow(self):
|
||||||
|
# _stdout, stderr, returncode = self.run_test(
|
||||||
|
# "memccpy_buffer_overflow")
|
||||||
|
# self.assertEqual(returncode, -6)
|
||||||
|
# self.assertEqual(stderr.decode(
|
||||||
|
# "utf-8"), "fatal allocator error: memccpy buffer overflow\n")
|
||||||
|
|
||||||
|
#def test_memccpy_read_overflow(self):
|
||||||
|
# _stdout, stderr, returncode = self.run_test(
|
||||||
|
# "memccpy_read_overflow")
|
||||||
|
# self.assertEqual(returncode, -6)
|
||||||
|
# self.assertEqual(stderr.decode(
|
||||||
|
# "utf-8"), "fatal allocator error: memccpy read overflow\n")
|
||||||
|
|
||||||
|
def test_memccpy_valid_same(self):
|
||||||
|
_stdout, _stderr, returncode = self.run_test(
|
||||||
|
"memccpy_valid_same")
|
||||||
|
self.assertEqual(returncode, 0)
|
||||||
|
|
||||||
|
def test_memccpy_valid_mismatched(self):
|
||||||
|
_stdout, _stderr, returncode = self.run_test(
|
||||||
|
"memccpy_valid_mismatched")
|
||||||
|
self.assertEqual(returncode, 0)
|
||||||
|
|
||||||
|
|
||||||
#def test_memmove_buffer_overflow(self):
|
#def test_memmove_buffer_overflow(self):
|
||||||
# _stdout, stderr, returncode = self.run_test(
|
# _stdout, stderr, returncode = self.run_test(
|
||||||
# "memmove_buffer_overflow")
|
# "memmove_buffer_overflow")
|
||||||
|
|
Loading…
Add table
Reference in a new issue