Compare commits

..

2 commits

Author SHA1 Message Date
SkewedZeppelin
a73585cc39
Merge b5a8849fc8 into 4fe9018b6f 2025-03-27 20:55:25 +00:00
Tavi
b5a8849fc8
perform size checks on memcpy/memmove/memset
Signed-off-by: Tavi <tavi@divested.dev>
Co-authored-by: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
2025-03-27 16:54:51 -04:00
21 changed files with 268 additions and 55 deletions

View file

@ -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
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
memcpy.c, memmove.c, memset.c and their wide variants:
memcpy.c, memmove.c, memset.c, wmemset.c:
Copyright © 2005-2020 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining

View file

@ -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
ifeq ($(CONFIG_BLOCK_OPS_CHECK_SIZE),true)
SOURCES += memcpy.c memmove.c memset.c wmemcpy.c wmemmove.c wmemset.c
SOURCES += memcpy.c memmove.c memset.c wmemset.c
BOSC_EXTRAS := musl.h
endif
OBJECTS := $(SOURCES:.c=.o)
@ -146,10 +146,6 @@ $(OUT)/memmove.o: memmove.c musl.h $(CONFIG_FILE) | $(OUT)
$(COMPILE.c) -Wno-cast-align $(OUTPUT_OPTION) $<
$(OUT)/memset.o: memset.c musl.h $(CONFIG_FILE) | $(OUT)
$(COMPILE.c) -Wno-cast-align $(OUTPUT_OPTION) $<
$(OUT)/wmemcpy.o: wmemcpy.c musl.h $(CONFIG_FILE) | $(OUT)
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(OUT)/wmemmove.o: wmemmove.c musl.h $(CONFIG_FILE) | $(OUT)
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(OUT)/wmemset.o: wmemset.c musl.h $(CONFIG_FILE) | $(OUT)
$(COMPILE.c) $(OUTPUT_OPTION) $<

View file

@ -1880,10 +1880,10 @@ EXPORT size_t h_malloc_object_size_fast(const void *p) {
#if CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE)
EXPORT void *memcpy(void *restrict dst, const void *restrict src, size_t len) {
if(dst == src || len == 0) {
if (unlikely(dst == src || len == 0)) {
return dst;
}
if (unlikely(dst < src + len && dst + len > src)) {
if (unlikely(dst < (src + len) && (dst + len) > src)) {
fatal_error("memcpy overlap");
}
if (unlikely(len > malloc_object_size(src))) {
@ -1896,7 +1896,7 @@ EXPORT void *memcpy(void *restrict dst, const void *restrict src, size_t len) {
}
EXPORT void *memmove(void *dst, const void *src, size_t len) {
if(dst == src || len == 0) {
if (unlikely(dst == src || len == 0)) {
return dst;
}
if (unlikely(len > malloc_object_size(src))) {
@ -1909,7 +1909,7 @@ EXPORT void *memmove(void *dst, const void *src, size_t len) {
}
EXPORT void *memset(void *dst, int value, size_t len) {
if(len == 0) {
if (unlikely(len == 0)) {
return dst;
}
if (unlikely(len > malloc_object_size(dst))) {
@ -1919,44 +1919,46 @@ EXPORT void *memset(void *dst, int value, size_t len) {
}
EXPORT wchar_t *wmemcpy(wchar_t *restrict dst, const wchar_t *restrict src, size_t len) {
if(dst == src || len == 0) {
if (unlikely(dst == src || len == 0)) {
return dst;
}
if (dst < src + len && dst + len > src) {
if (unlikely(dst < (src + len) && (dst + len) > src)) {
fatal_error("wmemcpy overlap");
}
if (len > malloc_object_size(src)) {
size_t lenAdj = len * sizeof(wchar_t);
if (unlikely(lenAdj > malloc_object_size(src))) {
fatal_error("wmemcpy read overflow");
}
if (len > malloc_object_size(dst)) {
if (unlikely(lenAdj > malloc_object_size(dst))) {
fatal_error("wmemcpy buffer overflow");
}
return musl_wmemcpy(dst, src, len);
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(dst == src || len == 0) {
if (unlikely(dst == src || len == 0)) {
return dst;
}
if (len > malloc_object_size(src)) {
size_t lenAdj = len * sizeof(wchar_t);
if (unlikely(lenAdj > malloc_object_size(src))) {
fatal_error("wmemmove read overflow");
}
if (len > malloc_object_size(dst)) {
if (unlikely(lenAdj > malloc_object_size(dst))) {
fatal_error("wmemmove buffer overflow");
}
return musl_wmemmove(dst, src, len);
return (wchar_t *)musl_memmove((char *)dst, (const char *)src, lenAdj);
}
EXPORT wchar_t *wmemset(wchar_t *dst, wchar_t value, size_t len) {
if(len == 0) {
if (unlikely(len == 0)) {
return dst;
}
if (len > malloc_object_size(dst)) {
if (unlikely((len * sizeof(wchar_t)) > malloc_object_size(dst))) {
fatal_error("wmemset buffer overflow");
}
return musl_wmemset(dst, value, len);
}
#endif
#endif /* CONFIG_BLOCK_OPS_CHECK_SIZE && !defined(HAS_ARM_MTE) */
EXPORT int h_mallopt(UNUSED int param, UNUSED int value) {
#ifdef __ANDROID__

View file

@ -20,7 +20,7 @@ void *musl_memmove(void *dest, const void *src, size_t n)
const char *s = src;
if (d==s) return d;
if ((uintptr_t)s-(uintptr_t)d-n <= -2*n) return memcpy(d, s, n);
if ((uintptr_t)s-(uintptr_t)d-n <= -2*n) return musl_memcpy(d, s, n);
if (d<s) {
#ifdef __GNUC__

2
musl.h
View file

@ -5,6 +5,4 @@
void *musl_memcpy(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);
wchar_t *musl_wmemcpy(wchar_t *dst, const wchar_t *src, size_t len);
wchar_t *musl_wmemmove(wchar_t *dst, const wchar_t *src, size_t len);
wchar_t *musl_wmemset(wchar_t *dst, wchar_t value, size_t len);

11
test/.gitignore vendored
View file

@ -52,4 +52,15 @@ memmove_valid_mismatched
memset_buffer_overflow
memset_valid_same
memset_valid_mismatched
wmemcpy_buffer_overflow
wmemcpy_read_overflow
wmemcpy_valid_same
wmemcpy_valid_mismatched
wmemmove_buffer_overflow
wmemmove_read_overflow
wmemmove_valid_same
wmemmove_valid_mismatched
wmemset_buffer_overflow
wmemset_valid_same
wmemset_valid_mismatched
__pycache__/

View file

@ -78,7 +78,18 @@ EXECUTABLES := \
memmove_valid_mismatched \
memset_buffer_overflow \
memset_valid_same \
memset_valid_mismatched
memset_valid_mismatched \
wmemcpy_buffer_overflow \
wmemcpy_read_overflow \
wmemcpy_valid_same \
wmemcpy_valid_mismatched \
wmemmove_buffer_overflow \
wmemmove_read_overflow \
wmemmove_valid_same \
wmemmove_valid_mismatched \
wmemset_buffer_overflow \
wmemset_valid_same \
wmemset_valid_mismatched
all: $(EXECUTABLES)

View file

@ -293,6 +293,71 @@ class TestSimpleMemoryCorruption(unittest.TestCase):
# self.assertEqual(stderr.decode(
# "utf-8"), "fatal allocator error: memset buffer overflow\n")
#def test_wmemcpy_buffer_overflow(self):
# _stdout, stderr, returncode = self.run_test(
# "wmemcpy_buffer_overflow")
# self.assertEqual(returncode, -6)
# self.assertEqual(stderr.decode(
# "utf-8"), "fatal allocator error: wmemcpy buffer overflow\n")
#def test_wmemcpy_read_overflow(self):
# _stdout, stderr, returncode = self.run_test(
# "wmemcpy_read_overflow")
# self.assertEqual(returncode, -6)
# self.assertEqual(stderr.decode(
# "utf-8"), "fatal allocator error: wmemcpy read overflow\n")
def test_wmemcpy_valid_same(self):
_stdout, _stderr, returncode = self.run_test(
"wmemcpy_valid_same")
self.assertEqual(returncode, 0)
def test_wmemcpy_valid_mismatched(self):
_stdout, _stderr, returncode = self.run_test(
"wmemcpy_valid_mismatched")
self.assertEqual(returncode, 0)
#def test_wmemmove_buffer_overflow(self):
# _stdout, stderr, returncode = self.run_test(
# "wmemmove_buffer_overflow")
# self.assertEqual(returncode, -6)
# self.assertEqual(stderr.decode(
# "utf-8"), "fatal allocator error: wmemmove buffer overflow\n")
#def test_wmemmove_read_overflow(self):
# _stdout, stderr, returncode = self.run_test(
# "wmemmove_read_overflow")
# self.assertEqual(returncode, -6)
# self.assertEqual(stderr.decode(
# "utf-8"), "fatal allocator error: wmemmove read overflow\n")
def test_wmemmove_valid_same(self):
_stdout, _stderr, returncode = self.run_test(
"wmemmove_valid_same")
self.assertEqual(returncode, 0)
def test_wmemmove_valid_mismatched(self):
_stdout, _stderr, returncode = self.run_test(
"wmemmove_valid_mismatched")
self.assertEqual(returncode, 0)
#def test_wmemset_buffer_overflow(self):
# _stdout, stderr, returncode = self.run_test(
# "wmemset_buffer_overflow")
# self.assertEqual(returncode, -6)
# self.assertEqual(stderr.decode(
# "utf-8"), "fatal allocator error: wmemset buffer overflow\n")
def test_wmemset_valid_same(self):
_stdout, _stderr, returncode = self.run_test(
"wmemset_valid_same")
self.assertEqual(returncode, 0)
def test_wmemset_valid_mismatched(self):
_stdout, _stderr, returncode = self.run_test(
"wmemset_valid_mismatched")
self.assertEqual(returncode, 0)
def test_memset_valid_same(self):
_stdout, _stderr, returncode = self.run_test(
"memset_valid_same")

View file

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *firstbuffer = malloc(16 * sizeof(wchar_t));
wchar_t *secondbuffer = malloc(32 * sizeof(wchar_t));
if (!firstbuffer && !secondbuffer) {
return 1;
}
wmemset(secondbuffer, L'\U0001F642', 32);
wmemcpy(firstbuffer, secondbuffer, 32);
return 1;
}

View file

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *firstbuffer = malloc(32 * sizeof(wchar_t));
wchar_t *secondbuffer = malloc(16 * sizeof(wchar_t));
if (!firstbuffer && !secondbuffer) {
return 1;
}
wmemset(secondbuffer, L'\U0001F642', 16);
wmemcpy(firstbuffer, secondbuffer, 32);
return 1;
}

View file

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *firstbuffer = malloc(32 * sizeof(wchar_t));
wchar_t *secondbuffer = malloc(16 * sizeof(wchar_t));
if (!firstbuffer && !secondbuffer) {
return 1;
}
wmemset(secondbuffer, L'\U0001F642', 16);
wmemcpy(firstbuffer, secondbuffer, 16);
return 0;
}

15
test/wmemcpy_valid_same.c Normal file
View file

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *firstbuffer = malloc(16 * sizeof(wchar_t));
wchar_t *secondbuffer = malloc(16 * sizeof(wchar_t));
if (!firstbuffer && !secondbuffer) {
return 1;
}
wmemset(secondbuffer, L'\U0001F642', 16);
wmemcpy(firstbuffer, secondbuffer, 16);
return 0;
}

View file

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *firstbuffer = malloc(16 * sizeof(wchar_t));
wchar_t *secondbuffer = malloc(32 * sizeof(wchar_t));
if (!firstbuffer && !secondbuffer) {
return 1;
}
wmemset(secondbuffer, L'\U0001F642', 32);
wmemmove(firstbuffer, secondbuffer, 32);
return 1;
}

View file

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *firstbuffer = malloc(32 * sizeof(wchar_t));
wchar_t *secondbuffer = malloc(16 * sizeof(wchar_t));
if (!firstbuffer && !secondbuffer) {
return 1;
}
wmemset(secondbuffer, L'\U0001F642', 16);
wmemmove(firstbuffer, secondbuffer, 32);
return 1;
}

View file

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *firstbuffer = malloc(32 * sizeof(wchar_t));
wchar_t *secondbuffer = malloc(16 * sizeof(wchar_t));
if (!firstbuffer && !secondbuffer) {
return 1;
}
wmemset(secondbuffer, L'\U0001F642', 16);
wmemmove(firstbuffer, secondbuffer, 16);
return 0;
}

View file

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *firstbuffer = malloc(16 * sizeof(wchar_t));
wchar_t *secondbuffer = malloc(16 * sizeof(wchar_t));
if (!firstbuffer && !secondbuffer) {
return 1;
}
wmemset(secondbuffer, L'\U0001F642', 16);
wmemmove(firstbuffer, secondbuffer, 16);
return 0;
}

View file

@ -0,0 +1,13 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *buffer = malloc(16 * sizeof(wchar_t));
if (!buffer) {
return 1;
}
wmemset(buffer, L'\U0001F642', 32);
return 1;
}

View file

@ -0,0 +1,13 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *buffer = malloc(32 * sizeof(wchar_t));
if (!buffer) {
return 1;
}
wmemset(buffer, L'\U0001F642', 16);
return 0;
}

13
test/wmemset_valid_same.c Normal file
View file

@ -0,0 +1,13 @@
#include <stdlib.h>
#include <wchar.h>
#include "test_util.h"
OPTNONE int main(void) {
wchar_t *buffer = malloc(16 * sizeof(wchar_t));
if (!buffer) {
return 1;
}
wmemset(buffer, L'\U0001F642', 16);
return 0;
}

View file

@ -1,12 +0,0 @@
#include "musl.h"
/* Copied from musl libc version 1.2.5 licensed under the MIT license */
#include <wchar.h>
wchar_t *musl_wmemcpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n)
{
wchar_t *a = d;
while (n--) *d++ = *s++;
return a;
}

View file

@ -1,17 +0,0 @@
#include "musl.h"
/* Copied from musl libc version 1.2.5 licensed under the MIT license */
#include <wchar.h>
#include <stdint.h>
wchar_t *musl_wmemmove(wchar_t *d, const wchar_t *s, size_t n)
{
wchar_t *d0 = d;
if (d == s) return d;
if ((uintptr_t)d-(uintptr_t)s < n * sizeof *d)
while (n--) d[n] = s[n];
else
while (n--) *d++ = *s++;
return d0;
}