perform size checks on various operations

Signed-off-by: Tavi <tavi@divested.dev>
Co-authored-by: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
This commit is contained in:
Tavi 2025-03-22 02:54:10 -04:00
parent 7481c8857f
commit 2f06cddeb7
No known key found for this signature in database
GPG key ID: E599F62ECBAEAF2E
46 changed files with 1166 additions and 13 deletions

View file

@ -20,6 +20,10 @@
#include "random.h"
#include "util.h"
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
#include "musl.h"
#endif
#ifdef USE_PKEY
#include <sys/mman.h>
#endif
@ -528,7 +532,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_internal((char *)p + size - canary_size, &metadata->canary_value, canary_size);
#endif
}
@ -541,7 +545,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_internal(&canary_value, (const char *)p + size - canary_size, canary_size);
#ifdef HAS_ARM_MTE
if (unlikely(canary_value == 0)) {
@ -831,7 +835,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_internal(p, 0, size - canary_size);
}
}
@ -1502,7 +1506,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_internal(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 +1628,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_internal(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 +1650,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_internal(new, old_orig, copy_size);
if (old_size <= max_slab_size_class) {
deallocate_small(old, NULL);
} else {
@ -1874,6 +1878,133 @@ EXPORT size_t h_malloc_object_size_fast(const void *p) {
return SIZE_MAX;
}
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
EXPORT void *memcpy(void *restrict dst, const void *restrict src, size_t len) {
if (unlikely(dst == src || len == 0)) {
return dst;
}
if (unlikely(dst < (src + len) && (dst + len) > src)) {
fatal_error("memcpy overlap");
}
if (unlikely(len > malloc_object_size(src))) {
fatal_error("memcpy read overflow");
}
if (unlikely(len > malloc_object_size(dst))) {
fatal_error("memcpy buffer overflow");
}
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) && value != 0)) {
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) {
if (unlikely(dst == src || len == 0)) {
return dst;
}
if (unlikely(len > malloc_object_size(src))) {
fatal_error("memmove read overflow");
}
if (unlikely(len > malloc_object_size(dst))) {
fatal_error("memmove buffer overflow");
}
return musl_memmove(dst, src, len);
}
EXPORT void *mempcpy(void *restrict dst, const void *restrict src, size_t len) {
return memcpy(dst, src, len) + len;
}
EXPORT void *memset(void *dst, int value, size_t len) {
if (unlikely(len == 0)) {
return dst;
}
if (unlikely(len > malloc_object_size(dst))) {
fatal_error("memset buffer overflow");
}
return musl_memset(dst, value, len);
}
EXPORT void bcopy(const void *src, void *dst, size_t len) {
memmove(dst, src, len);
}
EXPORT void swab(const void *restrict src, void *restrict dst, ssize_t len) {
if (unlikely(len <= 0)) {
return;
}
size_t length = len;
if (unlikely(dst < (src + length) && (dst + length) > src)) {
fatal_error("swab overlap");
}
if (unlikely(length > malloc_object_size(src))) {
fatal_error("swab read overflow");
}
if (unlikely(length > malloc_object_size(dst))) {
fatal_error("swab buffer overflow");
}
return musl_swab(src, dst, len);
}
EXPORT wchar_t *wmemcpy(wchar_t *restrict dst, const wchar_t *restrict src, size_t len) {
if (unlikely(dst == src || len == 0)) {
return dst;
}
if (unlikely(dst < (src + len) && (dst + len) > src)) {
fatal_error("wmemcpy overlap");
}
size_t lenAdj = len * sizeof(wchar_t);
if (unlikely(lenAdj > malloc_object_size(src))) {
fatal_error("wmemcpy read overflow");
}
if (unlikely(lenAdj > malloc_object_size(dst))) {
fatal_error("wmemcpy buffer overflow");
}
return (wchar_t *)musl_memcpy((char *)dst, (const char *)src, lenAdj);
}
EXPORT wchar_t *wmemmove(wchar_t *dst, const wchar_t *src, size_t len) {
if (unlikely(dst == src || len == 0)) {
return dst;
}
size_t lenAdj = len * sizeof(wchar_t);
if (unlikely(lenAdj > malloc_object_size(src))) {
fatal_error("wmemmove read overflow");
}
if (unlikely(lenAdj > malloc_object_size(dst))) {
fatal_error("wmemmove buffer overflow");
}
return (wchar_t *)musl_memmove((char *)dst, (const char *)src, lenAdj);
}
EXPORT wchar_t *wmempcpy(wchar_t *restrict dst, const wchar_t *restrict src, size_t len) {
return wmemcpy(dst, src, len) + len;
}
EXPORT wchar_t *wmemset(wchar_t *dst, wchar_t value, size_t len) {
if (unlikely(len == 0)) {
return dst;
}
if (unlikely((len * sizeof(wchar_t)) > malloc_object_size(dst))) {
fatal_error("wmemset buffer overflow");
}
return musl_wmemset(dst, value, len);
}
#endif /* CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE) */
EXPORT int h_mallopt(UNUSED int param, UNUSED int value) {
#ifdef __ANDROID__
if (param == M_PURGE) {