Compare commits

..

2 commits

Author SHA1 Message Date
SkewedZeppelin
5d22d91964
Merge dd6eb962de into 4fe9018b6f 2025-03-23 08:51:54 +00:00
Tavi
dd6eb962de
perform size checks on memcpy/memmove/memset
- memset is disabled for now as it causes hangs
- underlying functions were copied from isoalloc, licensed Apache-2.0
	- credit Chris Rohlf for memcpy/memset
	- credit David Carlier for memmove

Signed-off-by: Tavi <tavi@divested.dev>
2025-03-23 04:51:44 -04:00
8 changed files with 67 additions and 53 deletions

View file

@ -279,7 +279,7 @@ The following boolean configuration options are available:
* `CONFIG_BLOCK_OPS_CHECK_SIZE`: `true` or `false` (default) to ensure length
parameter of the memcpy/memmove/memset block operations are within
approximate bounds to minimize buffer overflows. Note, memset override is
currently disabled due to improper behavior.
currently disabled due to being broken.
The following integer configuration options are available:

View file

@ -528,7 +528,7 @@ static void set_canary(UNUSED const struct slab_metadata *metadata, UNUSED void
}
#endif
memcpy((char *)p + size - canary_size, &metadata->canary_value, canary_size);
h_memcpy_real((char *)p + size - canary_size, &metadata->canary_value, canary_size);
#endif
}
@ -541,7 +541,7 @@ static void check_canary(UNUSED const struct slab_metadata *metadata, UNUSED con
#endif
u64 canary_value;
memcpy(&canary_value, (const char *)p + size - canary_size, canary_size);
h_memcpy_real(&canary_value, (const char *)p + size - canary_size, canary_size);
#ifdef HAS_ARM_MTE
if (unlikely(canary_value == 0)) {
@ -831,7 +831,7 @@ static inline void deallocate_small(void *p, const size_t *expected_size) {
#endif
if (ZERO_ON_FREE && !skip_zero) {
memset(p, 0, size - canary_size);
h_memset_real(p, 0, size - canary_size);
}
}
@ -1502,7 +1502,7 @@ EXPORT void *h_calloc(size_t nmemb, size_t size) {
total_size = adjust_size_for_canary(total_size);
void *p = alloc(total_size);
if (!ZERO_ON_FREE && likely(p != NULL) && total_size && total_size <= max_slab_size_class) {
memset(p, 0, total_size - canary_size);
h_memset_real(p, 0, total_size - canary_size);
}
#ifdef HAS_ARM_MTE
// use an assert instead of adding a conditional to memset() above (freed memory is always
@ -1624,7 +1624,7 @@ EXPORT void *h_realloc(void *old, size_t size) {
mutex_unlock(&ra->lock);
if (memory_remap_fixed(old, old_size, new, size)) {
memcpy(new, old, copy_size);
h_memcpy_real(new, old, copy_size);
deallocate_pages(old, old_size, old_guard_size);
} else {
memory_unmap((char *)old - old_guard_size, old_guard_size);
@ -1646,7 +1646,7 @@ EXPORT void *h_realloc(void *old, size_t size) {
if (copy_size > 0 && copy_size <= max_slab_size_class) {
copy_size -= canary_size;
}
memcpy(new, old_orig, copy_size);
h_memcpy_real(new, old_orig, copy_size);
if (old_size <= max_slab_size_class) {
deallocate_small(old, NULL);
} else {
@ -1874,8 +1874,8 @@ EXPORT size_t h_malloc_object_size_fast(const void *p) {
return SIZE_MAX;
}
#if CONFIG_BLOCK_OPS_CHECK_SIZE
inline void *h_memcpy_real(void *dst, const void *src, size_t len) {
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
char *p_dst = (char *)dst;
char const *p_src = (char const *)src;
@ -1884,27 +1884,16 @@ inline void *h_memcpy_real(void *dst, const void *src, size_t len) {
}
return dst;
}
EXPORT void *h_memcpy(void *dst, const void *src, size_t len) {
if (len > malloc_object_size_fast(src)) {
fatal_error("memcpy read overflow");
}
if (len > malloc_object_size_fast(dst)) {
fatal_error("memcpy buffer overflow");
}
return h_memcpy_real(dst, src, len);
#else
return memcpy(dst, src, len);
#endif
}
inline void *h_memmove_real(void *dst, const void *src, size_t len) {
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
char *p_dst = (char *)dst;
char const *p_src = (char const *)src;
if(dst == src) {
return dst;
}
if(p_src < p_dst) {
p_dst += len;
p_src += len;
@ -1912,24 +1901,17 @@ inline void *h_memmove_real(void *dst, const void *src, size_t len) {
*--p_dst = *--p_src;
}
} else {
dst = h_memcpy(dst, src, len);
dst = h_memcpy_real(dst, src, len);
}
return dst;
}
EXPORT void *h_memmove(void *dst, const void *src, size_t len) {
if (len > malloc_object_size_fast(src)) {
fatal_error("memmove read overflow");
}
if (len > malloc_object_size_fast(dst)) {
fatal_error("memmove buffer overflow");
}
return h_memmove_real(dst, src, len);
#else
return memmove(dst, src, len);
#endif
}
inline void *h_memset_real(void *dst, int value, size_t len) {
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
char *p_dst = (char *)dst;
while(len--) {
@ -1937,13 +1919,45 @@ inline void *h_memset_real(void *dst, int value, size_t len) {
}
return dst;
#else
return memset(dst, value, len);
#endif
}
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
EXPORT void *h_memcpy(void *dst, const void *src, size_t len) {
if(dst == src || len == 0) {
return dst;
}
if (len > malloc_object_size(src)) {
fatal_error("memcpy read overflow");
}
if (len > malloc_object_size(dst)) {
fatal_error("memcpy buffer overflow");
}
return h_memcpy_real(dst, src, len);
}
EXPORT void *h_memmove(void *dst, const void *src, size_t len) {
if(dst == src || len == 0) {
return dst;
}
if (len > malloc_object_size(src)) {
fatal_error("memmove read overflow");
}
if (len > malloc_object_size(dst)) {
fatal_error("memmove buffer overflow");
}
return h_memmove_real(dst, src, len);
}
EXPORT void *h_memset(void *dst, int value, size_t len) {
if (len > malloc_object_size_fast(dst)) {
if(len == 0) {
return dst;
}
if (len > malloc_object_size(dst)) {
fatal_error("memset buffer overflow");
}
return h_memset_real(dst, value, len);
}
#endif

View file

@ -15,7 +15,7 @@ extern "C" {
#define h_realloc realloc
#define h_aligned_alloc aligned_alloc
#define h_free free
#if CONFIG_BLOCK_OPS_CHECK_SIZE
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
#define h_memcpy memcpy
#define h_memmove memmove
//#define h_memset memset
@ -59,12 +59,12 @@ __attribute__((alloc_size(2))) void *h_realloc(void *ptr, size_t size);
__attribute__((malloc)) __attribute__((alloc_size(2))) __attribute__((alloc_align(1)))
void *h_aligned_alloc(size_t alignment, size_t size);
void h_free(void *ptr);
#if CONFIG_BLOCK_OPS_CHECK_SIZE
void *h_memcpy_real(void *dst, const void *src, size_t len);
void *h_memcpy(void *dst, const void *src, size_t len);
void *h_memmove_real(void *dst, const void *src, size_t len);
void *h_memmove(void *dst, const void *src, size_t len);
void *h_memset_real(void *dst, int value, size_t len);
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
void *h_memcpy(void *dst, const void *src, size_t len);
void *h_memmove(void *dst, const void *src, size_t len);
void *h_memset(void *dst, int value, size_t len);
#endif

View file

@ -9,7 +9,7 @@ OPTNONE int main(void) {
if (!firstbuffer && !secondbuffer) {
return 1;
}
memset(secondbuffer, 'a', 16);
memset(secondbuffer, 'a', 32);
memcpy(firstbuffer, secondbuffer, 32);
return 1;
}

View file

@ -4,12 +4,12 @@
#include "test_util.h"
OPTNONE int main(void) {
char *firstbuffer = malloc(16);
char *secondbuffer = malloc(8);
char *firstbuffer = malloc(32);
char *secondbuffer = malloc(16);
if (!firstbuffer && !secondbuffer) {
return 1;
}
memset(secondbuffer, 'a', 8);
memcpy(firstbuffer, secondbuffer, 8);
memset(secondbuffer, 'a', 16);
memcpy(firstbuffer, secondbuffer, 16);
return 0;
}

View file

@ -9,7 +9,7 @@ OPTNONE int main(void) {
if (!firstbuffer && !secondbuffer) {
return 1;
}
memset(secondbuffer, 'a', 16);
memset(secondbuffer, 'a', 32);
memmove(firstbuffer, secondbuffer, 32);
return 1;
}

View file

@ -4,12 +4,12 @@
#include "test_util.h"
OPTNONE int main(void) {
char *firstbuffer = malloc(16);
char *secondbuffer = malloc(8);
char *firstbuffer = malloc(32);
char *secondbuffer = malloc(16);
if (!firstbuffer && !secondbuffer) {
return 1;
}
memset(secondbuffer, 'a', 8);
memmove(firstbuffer, secondbuffer, 8);
memset(secondbuffer, 'a', 16);
memmove(firstbuffer, secondbuffer, 16);
return 0;
}

View file

@ -4,10 +4,10 @@
#include "test_util.h"
OPTNONE int main(void) {
char *buffer = malloc(16);
char *buffer = malloc(32);
if (!buffer) {
return 1;
}
memset(buffer, 'a', 8);
memset(buffer, 'a', 16);
return 0;
}