diff options
Diffstat (limited to '')
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | common.h | 6 | ||||
| -rw-r--r-- | config-coverage-gcc.mk | 6 | ||||
| -rw-r--r-- | librecrypt_check_settings_.c | 23 | ||||
| -rw-r--r-- | librecrypt_hash_.c | 4 | ||||
| -rw-r--r-- | librecrypt_rng_.c | 312 | ||||
| -rw-r--r-- | librecrypt_test_supported.c | 2 | ||||
| -rw-r--r-- | libtest/alloc.c | 124 | ||||
| -rw-r--r-- | libtest/alloc_have_custom.c | 14 | ||||
| -rw-r--r-- | libtest/common.h | 4 | ||||
| -rw-r--r-- | libtest/config.mk | 2 | ||||
| -rw-r--r-- | libtest/globals.c | 3 | ||||
| -rw-r--r-- | libtest/libtest.h | 19 | ||||
| -rw-r--r-- | libtest/mmap.c | 12 |
14 files changed, 454 insertions, 82 deletions
@@ -42,8 +42,8 @@ OBJ_PUBLIC =\ OBJ_PRIVATE =\ librecrypt_algorithms_.o\ - librecrypt_hash_.o\ librecrypt_rng_.o\ + librecrypt_hash_.o\ librecrypt_fill_with_random_.o\ librecrypt_find_first_algorithm_.o\ librecrypt_check_settings_.o\ @@ -91,7 +91,7 @@ $(TEST): $(HDR) librecrypt.a libtest/libtest.a libtest/libtest.h $(CC) -fPIC -c -o $@ $< $(ALL_CFLAGS) $(COV_CFLAGS) $(ALL_CPPFLAGS) $(COV_CPPFLAGS) .c.to: - $(CC) -DTEST -c -o $@ $< $(ALL_CFLAGS) $(ALL_CPPFLAGS) + $(CC) -DTEST -c -o $@ $< $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(COV_CPPFLAGS) .to.t: $(CC) -o $@ $< librecrypt.a libtest/libtest.a $(G) $(ALL_LDFLAGS) $(TEST_LDFLAGS) $(COV_LDFLAGS) @@ -141,6 +141,7 @@ uninstall: -cd -- "$(DESTDIR)$(MANPREFIX)/man7/" && rm -f -- $(MAN7) clean: + +cd libtest && $(MAKE) clean -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.dll *.dylib -rm -f -- *.gch *.gcov *.gcno *.gcda *.$(LIBEXT) -rm -f -- *.to *.t @@ -45,6 +45,11 @@ #endif +#if defined(POSIX_CLOSE_RESTART) && !defined(__linux__) +# define close(fd) posix_close(fd, 0) +#endif + + /** * Used for literal commas in macro calls */ @@ -447,6 +452,7 @@ int librecrypt_check_settings_(const char *settings, size_t len, const char *fmt # endif # include <sys/resource.h> # include <sys/types.h> +# include <sys/uio.h> # include <sys/wait.h> # include <setjmp.h> # include <signal.h> diff --git a/config-coverage-gcc.mk b/config-coverage-gcc.mk index c487b3a..6578f68 100644 --- a/config-coverage-gcc.mk +++ b/config-coverage-gcc.mk @@ -4,9 +4,9 @@ include $(CONFIGFILE_PROPER) CC = $(CC_PREFIX)gcc -std=c99 GCOV = gcov -CFLAGS = -g -O0 -COV_CFLAGS = --coverage -COV_LDFLAGS = --coverage +COV_CPPFLAGS = -DCOVERAGE_TEST +COV_CFLAGS = --coverage -g -O0 +COV_LDFLAGS = --coverage -g -O0 G = diff --git a/librecrypt_check_settings_.c b/librecrypt_check_settings_.c index 16fbe7f..2c544b2 100644 --- a/librecrypt_check_settings_.c +++ b/librecrypt_check_settings_.c @@ -178,12 +178,16 @@ librecrypt_check_settings_(const char *settings, size_t len, const char *fmt, .. while (*fmt) { if (*fmt != '%') { /* Normal literal character */ - if (i == len || settings[i++] != *fmt++) + if (i == len) + return 0; + if (settings[i++] != *fmt++) return 0; } else if (fmt[1u] == '%') { /* '%'-escaped literal '%' ("%%") */ - if (i == len || settings[i++] != '%') + if (i == len) + return 0; + if (settings[i++] != '%') return 0; fmt = &fmt[2u]; @@ -238,12 +242,14 @@ librecrypt_check_settings_(const char *settings, size_t len, const char *fmt, .. if (!str) return 0; n = strlen(str); - if (n <= len - i && !strncmp(&settings[i], str, n)) { - if (strout) - *strout = str; - i += n; - break; - } + if (n > len - i) + continue; + if (strncmp(&settings[i], str, n)) + continue; + if (strout) + *strout = str; + i += n; + break; } while ((str = va_arg(args, const char *))); goto outable_done; @@ -647,6 +653,7 @@ main(void) EXPECT(librecrypt_check_settings_("%", 1u, "%%") == 1); EXPECT(librecrypt_check_settings_("%", 0u, "%%") == 0); + EXPECT(librecrypt_check_settings_("x", 1u, "%%") == 0); EXPECT(librecrypt_check_settings_("hello", 5u, "%*") == 1); EXPECT(librecrypt_check_settings_("hello$world", 11u, "%*$world") == 1); diff --git a/librecrypt_hash_.c b/librecrypt_hash_.c index c66d4be..dc32df1 100644 --- a/librecrypt_hash_.c +++ b/librecrypt_hash_.c @@ -68,8 +68,10 @@ librecrypt_hash_(char *restrict out_buffer, size_t size, const char *phrase, siz /* Generate the salts */ r_len = librecrypt_realise_salts(out_buffer, size, settings, rng, NULL); if (r_len < 0) { - if (errno == ERANGE) + if (errno == ERANGE) { errno = ENOMEM; + return -1; + } return -1; } else if ((size_t)r_len >= size) { settings_scratch = malloc((size_t)r_len + 1u); diff --git a/librecrypt_rng_.c b/librecrypt_rng_.c index 3f9b9eb..f9a6cc7 100644 --- a/librecrypt_rng_.c +++ b/librecrypt_rng_.c @@ -96,7 +96,7 @@ librecrypt_rng_(void *out, size_t n, void *user) /* /dev/urandom cannot be exhausted, your system * has been compromised if this happens */ /* TODO we should probably warn the user */ - abort(); + abort(); /* $covered$ */ } } @@ -128,16 +128,16 @@ no_urandom: * allocation. A few bit's are always 0, but that's not * a big deal. */ random_ptr = mmap(NULL, 1u, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED, -1, 0); - if (random_ptr != MAP_FAILED) { + if (random_ptr == MAP_FAILED) { + random_ptr = malloc(1u); /* NULL is OK (MAP_FAILED was actually also OK) */ + random_addr = (uintptr_t)random_ptr; + state ^= (unsigned int)random_addr; + free(random_ptr); + } else { random_addr = (uintptr_t)random_ptr; state ^= (unsigned int)random_addr; munmap(random_ptr, 1u); - goto have_initial_seed; /* just using goto to simplify the #if'ing */ } - random_ptr = malloc(1u); /* NULL is OK (MAP_FAILED was actually also OK) */ - random_addr = (uintptr_t)random_ptr; - state ^= (unsigned int)random_addr; - free(random_ptr); have_initial_seed: /* and always do a time-based reseed in case of multithreading, @@ -175,6 +175,7 @@ int (open)(const char *path, int flags, ...) { mode_t mode = 0; + va_list args; open_calls += 1u; @@ -186,7 +187,6 @@ int } if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { - va_list args; va_start(args, flags); mode = va_arg(args, mode_t); va_end(args); @@ -196,6 +196,143 @@ int } +static int read_error = 0; +static size_t read_max_return = SIZE_MAX; + +ssize_t +(read)(int fd, void *buf, size_t n) +{ + struct iovec iov; + + if (n > read_max_return) + n = read_max_return; + + if (read_error) { + errno = read_error; + if (read_error == EINTR) + read_error = 0; + return -1; + } + + iov.iov_base = buf; + iov.iov_len = n; + return readv(fd, &iov, 1); +} + + +static int clock_gettime_error = 0; + +int +(clock_gettime)(clockid_t clockid, struct timespec *tp) +{ + (void) clockid; + + if (clock_gettime_error) { + errno = clock_gettime_error; + return -1; + } + + memset(tp, 0, sizeof(*tp)); + return 0; +} + + +#if defined(__linux__) && defined(AT_RANDOM) +static int getauxval_error = 0; + +unsigned long +(getauxval)(unsigned long type) +{ + /* We don't want to read from after the first NULL + * in the environment variable list provided by the + * kernel, because (1) this function may be executed + * before `main` so we cannot copy the auxiliary + * vector in `main` and use that, (2) if this function + * is executed before `main`, we don't know if + * environ(3) has been set up by libc, and (3) we + * cannot know if environ(3) is it's original pointer + * without addition elements when this function is + * executed. Therefore we use /proc/self/auxv instead. */ + + size_t saved_open_calls = open_calls; + int saved_open_error = open_error; + int saved_read_error = read_error; + size_t saved_read_max_return = read_max_return; + size_t *aux; + unsigned char buf[2u * sizeof(*aux)]; + size_t off; + ssize_t r; + int fd; + unsigned long ret = 0u; + + if (getauxval_error) { + errno = getauxval_error; + return 0; + } + + open_error = 0; + read_error = 0; + read_max_return = SIZE_MAX; + + fd = open("/proc/self/auxv", O_RDONLY); + + if (fd < 0) { + errno = ENOENT; + goto out; + } + + aux = (unsigned long *)buf; + for (off = 0u;;) { + r = read(fd, &buf[off], sizeof(buf) - off); + if (r <= 0) { + if (r && errno == EINTR) + continue; + errno = ENOENT; + goto out_close; + } + off += (size_t)r; + if (off < sizeof(buf)) + continue; + off = 0u; + if (aux[0] == type) + break; + } + + ret = aux[1]; +out_close: + close(fd); +out: + open_calls = saved_open_calls; + open_error = saved_open_error; + read_error = saved_read_error; + read_max_return = saved_read_max_return; + return ret; +} +#endif + + +static size_t rand_r_calls = 0u; +static int rand_r_clean_seed = 0; + +int +(rand_r)(unsigned int *seedp) +{ + int ret; + + rand_r_calls += 1u; + + if (*seedp) + srand(*seedp); + ret = rand(); + + *seedp = (unsigned int)ret; + if (rand_r_clean_seed) + *seedp = 0u; + + return ret; +} + + static volatile size_t beyond_ssize_max = (size_t)SSIZE_MAX + 1u; static void @@ -225,8 +362,6 @@ test_oversized(void) int main(void) { - /* TODO test failure cases */ - unsigned char buf1[1024u]; unsigned char buf2[sizeof(buf1)]; ssize_t n1, n2; @@ -237,14 +372,26 @@ main(void) open_calls = 0u; +#define CHECK1()\ + do {\ + n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);\ + EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));\ + EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));\ + } while (0) + +#define CHECK2()\ + do {\ + n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);\ + n2 = librecrypt_rng_(buf2, sizeof(buf2), &user);\ + EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));\ + EXPECT(n2 >= 128 && (size_t)n2 <= sizeof(buf2));\ + EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));\ + } while (0) + /* TODO Test with output pattern (useful for other tests) */ /* Check that output is random */ - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - n2 = librecrypt_rng_(buf2, sizeof(buf2), &user); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(n2 >= 128 && (size_t)n2 <= sizeof(buf2)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK2(); #if defined(__linux__) libtest_getentropy_calls = 0u; @@ -252,9 +399,7 @@ main(void) /* Check with short getrandom(3) */ errno = 0; libtest_getrandom_max_return = 1u; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK1(); libtest_getrandom_max_return = SIZE_MAX; EXPECT(libtest_getentropy_calls == 0u); EXPECT(errno == 0); @@ -262,9 +407,7 @@ main(void) /* Check with getrandom(3) with EINTR */ errno = 0; libtest_getrandom_error = EINTR; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK1(); assert(!libtest_getrandom_error); EXPECT(libtest_getentropy_calls == 0u); EXPECT(errno == EINTR); @@ -272,9 +415,7 @@ main(void) /* Check with getrandom(3) with ENOSYS */ errno = 0; libtest_getrandom_error = ENOSYS; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK1(); assert(libtest_getrandom_error == ENOSYS); EXPECT(libtest_getentropy_calls > 0u); libtest_getentropy_calls = 0u; @@ -283,9 +424,7 @@ main(void) /* Check with getrandom(3) other error */ errno = 0; libtest_getrandom_error = EDOM; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK1(); assert(libtest_getrandom_error == EDOM); EXPECT(libtest_getentropy_calls > 0u); libtest_getentropy_calls = 0u; @@ -295,9 +434,7 @@ main(void) /* Check with getrandom(3) zero return */ errno = 0; libtest_getrandom_max_return = 0u; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK1(); libtest_getrandom_max_return = SIZE_MAX; EXPECT(libtest_getentropy_calls > 0u); libtest_getentropy_calls = 0u; @@ -310,9 +447,7 @@ main(void) /* Check with getentropy(3) with EINTR */ errno = 0; libtest_getentropy_error = EINTR; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK1(); assert(!libtest_getentropy_error); EXPECT(libtest_getentropy_calls > 0u); libtest_getentropy_calls = 0u; @@ -321,9 +456,7 @@ main(void) /* Check with getentropy(3) with ENOSYS */ errno = 0; libtest_getentropy_error = ENOSYS; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK1(); assert(libtest_getentropy_error == ENOSYS); EXPECT(libtest_getentropy_calls > 0u); libtest_getentropy_calls = 0u; @@ -332,9 +465,7 @@ main(void) /* Check with getentropy(3) other error */ errno = 0; libtest_getentropy_error = EDOM; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK1(); assert(libtest_getentropy_error == EDOM); EXPECT(libtest_getentropy_calls > 0u); libtest_getentropy_calls = 0u; @@ -345,54 +476,108 @@ main(void) assert(open_calls > 0u); open_calls = 0u; errno = 0; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - n2 = librecrypt_rng_(buf2, sizeof(buf2), &user); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(n2 >= 128 && (size_t)n2 <= sizeof(buf2)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK2(); EXPECT(libtest_getentropy_calls > 0u); libtest_getentropy_calls = 0u; EXPECT(errno == 0); libtest_getentropy_real = 1; EXPECT(open_calls == 0u); - /* TODO Check with getentropy(3) with small buffer */ + /* Check with getentropy(3) with small buffer */ + n1 = librecrypt_rng_(buf1, 64u, NULL); + EXPECT(n1 == 64u); + EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); /* Don't use getentropy(3) for reminder of the test */ libtest_getentropy_error = ENOSYS; /* Check with urandom(4) */ + rand_r_calls = 0; errno = 0; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - n2 = librecrypt_rng_(buf2, sizeof(buf2), &user); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(n2 >= 128 && (size_t)n2 <= sizeof(buf2)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK2(); EXPECT(errno == 0); - /* TODO check that rand(3) was not called */ + EXPECT(rand_r_calls == 0u); /* Check with urandom(4) not available */ open_calls = 0; open_error = ENOENT; - n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL); - n2 = librecrypt_rng_(buf2, sizeof(buf2), &user); - EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1)); - EXPECT(n2 >= 128 && (size_t)n2 <= sizeof(buf2)); - EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2))); + CHECK2(); assert(open_error == ENOENT); open_error = 0; EXPECT(open_calls > 0u); - /* TODO Check with urandom(4) read(3) EINTR */ - /* TODO Check with urandom(4) read(3) EIO */ - /* TODO Check with urandom(4) read(3) exhaustion */ + /* Check with urandom(4) read(3) failure */ + read_error = EBADF; + errno = 0; + CHECK1(); + EXPECT(errno == 0); + assert(read_error == EBADF); + read_error = 0; + + /* Check with urandom(4) read(3) EINTR */ + read_error = EINTR; + errno = 0; + CHECK1(); + EXPECT(errno == EINTR); + assert(read_error == 0); + + /* Check with urandom(4) short read(3) */ + read_max_return = 1u; + CHECK1(); + assert(read_max_return == 1u); + read_max_return = SIZE_MAX; + + /* Check with urandom(4) read(3) exhaustion */ + read_max_return = 0u; + EXPECT_ABORT(n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL)); + read_max_return = SIZE_MAX; /* Don't use urandom(4) for reminder of the test */ open_error = ENOENT; - /* TODO Check with rand(3) */ - /* TODO Check with mmap(3) failure */ - /* TODO Check with clock_gettime(3) failure */ + rand_r_clean_seed = 1; + + /* Check with rand(3) */ + rand_r_calls = 0u; + errno = 0; + CHECK2(); + EXPECT(errno == 0); + assert(rand_r_calls > 0u); + +#if defined(__linux__) && defined(AT_RANDOM) + getauxval_error = ENOENT; + + /* Check with getauxval(3) failure */ + assert(getauxval(AT_RANDOM) == 0u); + assert(getauxval_error == ENOENT); + errno = 0; + CHECK1(); + EXPECT(errno == 0); +#endif + + /* Check with mmap(3) failure */ + if (libtest_have_custom_mmap()) { + libtest_set_alloc_failure_in(1u); + errno = 0; + CHECK1(); + EXPECT(errno == 0); + assert(libtest_get_alloc_failure_in() == 0u); + } + +#if defined(__linux__) && defined(AT_RANDOM) + getauxval_error = 0; +#endif + + /* Check with clock_gettime(3) failure */ + clock_gettime_error = EDOM; + errno = 0; + CHECK1(); + EXPECT(errno == 0); + EXPECT(clock_gettime_error == EDOM); + clock_gettime_error = 0; + + assert(rand_r_clean_seed == 1); + rand_r_clean_seed = 0; /* Check zero-request */ errno = 0; @@ -401,6 +586,9 @@ main(void) test_oversized(); + /* So that gcov can report coverage */ + open_error = 0; + STOP_RESOURCE_TEST(); return 0; } diff --git a/librecrypt_test_supported.c b/librecrypt_test_supported.c index 520ab68..db9f302 100644 --- a/librecrypt_test_supported.c +++ b/librecrypt_test_supported.c @@ -9,7 +9,7 @@ librecrypt_test_supported(const char *phrase, size_t len, int text, const char * const struct algorithm *algo; size_t n; - /* For each chained algorithm*/ + /* For each chained algorithm */ for (;;) { /* Measure until next '>' */ for (n = 0u; settings[n]; n++) diff --git a/libtest/alloc.c b/libtest/alloc.c index 7752091..f89ba94 100644 --- a/libtest/alloc.c +++ b/libtest/alloc.c @@ -427,6 +427,121 @@ void * } +int +libtest_check_custom_mmap(void) +{ + static _Thread_local int in_check_custom_mmap = 0; + char *volatile test_dummy = NULL; + + if (in_check_custom_mmap) + return libtest_mmap_is_custom; + in_check_custom_mmap = 1; + + if (libtest_mmap_is_custom >= 0 && + libtest_mremap_is_custom >= 0 && + libtest_munmap_is_custom >= 0) { + if (libtest_mmap_is_custom & libtest_mremap_is_custom & libtest_munmap_is_custom) + goto custom; + goto real_deallocated; + } + + test_dummy = mmap(NULL, 1u, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(test_dummy != MAP_FAILED); + assert(test_dummy != NULL); + *test_dummy = 0; + + if (libtest_mmap_is_custom == 0) + goto real; + + if (libtest_mremap_is_custom < 0) { + test_dummy = mremap(test_dummy, 1u, 1u, MREMAP_MAYMOVE); + assert(test_dummy != MAP_FAILED); + assert(test_dummy != NULL); + } + if (libtest_mremap_is_custom == 0) + goto real; + + if (libtest_munmap_is_custom < 0) + assert(!munmap(test_dummy, 1u)); + if (libtest_munmap_is_custom == 0) + goto real_deallocated; + +custom: + in_check_custom_mmap = 0; + return 1; + +real: + assert(!munmap(test_dummy, 1u)); +real_deallocated: + in_check_custom_mmap = 0; + libtest_mmap_is_custom = 0; + libtest_mremap_is_custom = 0; + libtest_munmap_is_custom = 0; + return 0; +} + + +void * +(mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t off) +{ + /* TODO implement tracking */ + + libtest_mmap_is_custom = 1; + if (!libtest_check_custom_mmap()) + goto real; + + if (!libtest_malloc_internal_usage) { + if (libtest_malloc_fail_in && !--libtest_malloc_fail_in) { + errno = ENOMEM; + return MAP_FAILED; + } + } + +real: + return libtest_real_mmap(addr, len, prot, flags, fd, off); +} + + +int +(munmap)(void *addr, size_t len) +{ + libtest_munmap_is_custom = 1; + if (!libtest_check_custom_mmap()) + goto real; + +real: + return libtest_real_munmap(addr, len); +} + + +void * +(mremap)(void *old_addr, size_t old_len, size_t new_len, int flags, ...) +{ + va_list args; + void *new_addr = NULL; + + if (flags & MREMAP_FIXED) { + va_start(args, flags); + new_addr = va_arg(args, void *); + va_end(args); + } + + libtest_mremap_is_custom = 1; + if (!libtest_check_custom_mmap()) + goto real; + + if (!libtest_malloc_internal_usage) { + if (libtest_malloc_fail_in && !--libtest_malloc_fail_in) { + errno = ENOMEM; + return MAP_FAILED; + } + } + +real: + return libtest_real_mremap(old_addr, old_len, new_len, flags, new_addr); +} + #else @@ -454,6 +569,9 @@ char *(strndup)(const char *s, size_t n); wchar_t *(wcsdup)(const wchar_t *s); wchar_t *(wcsndup)(const wchar_t *s, size_t n); void *(memdup)(const void *s, size_t n); +void *(mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t off); +int (munmap)(void *addr, size_t len); +void *(mremap)(void *old_addr, size_t old_len, size_t new_len, int flags, ...); static void @@ -599,6 +717,8 @@ check(int use_free) free(p); else free_aligned_sized(p, sizeof(void *), 11u); + + /* TODO mmap, munmap, mremap */ } @@ -696,6 +816,8 @@ check_successfuls(void) assert(GET_MEMINFO(w)->requested_alloc_size == 3u * sizeof(wchar_t)); EXPECT(!memcmp(w, (wchar_t[]){11, 22, 0}, 3u * sizeof(wchar_t))); free(w); + + /* TODO mmap, munmap, mremap */ } @@ -802,6 +924,8 @@ check_failures(void) EXPECT(!memdup("x", 1u)); EXPECT(errno == ENOMEM); EXPECT(!libtest_get_alloc_failure_in()); + + /* TODO mmap, munmap, mremap */ } diff --git a/libtest/alloc_have_custom.c b/libtest/alloc_have_custom.c index 9c213bb..0800e5e 100644 --- a/libtest/alloc_have_custom.c +++ b/libtest/alloc_have_custom.c @@ -26,6 +26,9 @@ char *(strndup)(const char *s, size_t n); wchar_t *(wcsdup)(const wchar_t *s); wchar_t *(wcsndup)(const wchar_t *s, size_t n); void *(memdup)(const void *s, size_t n); +void *(mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t off); +int (munmap)(void *addr, size_t len); +void *(mremap)(void *old_addr, size_t old_len, size_t new_len, int flags, ...); #if defined(__GNUC__) # pragma GCC diagnostic pop @@ -210,6 +213,16 @@ libtest_have_custom_free_aligned_sized(void) } +int +libtest_have_custom_mmap(void) +{ + static int r = -1; + if (r < 0) + r = libtest_check_custom_mmap(); + return r; +} + + #else @@ -243,6 +256,7 @@ main(void) CHECK(libtest_have_custom_wcsdup); CHECK(libtest_have_custom_wcsndup); CHECK(libtest_have_custom_memdup); + CHECK(libtest_have_custom_mmap); return 0; } diff --git a/libtest/common.h b/libtest/common.h index b78b69d..8d22b5b 100644 --- a/libtest/common.h +++ b/libtest/common.h @@ -147,6 +147,9 @@ extern volatile int libtest_strndup_is_custom; extern volatile int libtest_wcsdup_is_custom; extern volatile int libtest_wcsndup_is_custom; extern volatile int libtest_memdup_is_custom; +extern volatile int libtest_mmap_is_custom; +extern volatile int libtest_munmap_is_custom; +extern volatile int libtest_mremap_is_custom; extern struct meminfo libtest_allocs_head; extern struct meminfo libtest_allocs_tail; @@ -174,6 +177,7 @@ libtest_base_pointer(void *ptr) HIDDEN size_t libtest_get_pagesize(void); HIDDEN void *libtest_alloc(struct meminfo *); HIDDEN void libtest_free(void *, enum libtest_zero_check); +HIDDEN int libtest_check_custom_mmap(void); #ifdef WITH_BACKTRACE HIDDEN void libtest_print_backtrace(FILE *, const char *prefix, const char *indent, diff --git a/libtest/config.mk b/libtest/config.mk index aa20790..6dff8a9 100644 --- a/libtest/config.mk +++ b/libtest/config.mk @@ -1,5 +1,5 @@ WITH_BACKTRACE = true -IMPLEMENT_MMAP = false +IMPLEMENT_MMAP = true TEST_CONFIGFILE = config_backtraces=$(WITH_BACKTRACE).mk include $(TEST_INCLUDE_PREFIX)$(TEST_CONFIGFILE) diff --git a/libtest/globals.c b/libtest/globals.c index 430f037..cf8164e 100644 --- a/libtest/globals.c +++ b/libtest/globals.c @@ -21,6 +21,9 @@ volatile int libtest_strndup_is_custom = -1; volatile int libtest_wcsdup_is_custom = -1; volatile int libtest_wcsndup_is_custom = -1; volatile int libtest_memdup_is_custom = -1; +volatile int libtest_mmap_is_custom = -1; +volatile int libtest_munmap_is_custom = -1; +volatile int libtest_mremap_is_custom = -1; struct meminfo libtest_allocs_head; struct meminfo libtest_allocs_tail; diff --git a/libtest/libtest.h b/libtest/libtest.h index 41d1a41..9fa7e56 100644 --- a/libtest/libtest.h +++ b/libtest/libtest.h @@ -324,6 +324,25 @@ int libtest_have_custom_free_sized(void); */ int libtest_have_custom_free_aligned_sized(void); +/** + * Test whether mmap(3), munmap(3), and mremap(3) has + * been overridden, allowing allocations to be tracked, + * and memory allocation failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if all three overridden, + * 0 if none have been overridden + * + * The case that only some of the three functions have + * been overriden, those will redirect to the real + * implementation and identify as non-overridden + */ +int libtest_have_custom_mmap(void); + /** * Print a stack trace, to standard error, provided diff --git a/libtest/mmap.c b/libtest/mmap.c index 62ef06e..c3b3067 100644 --- a/libtest/mmap.c +++ b/libtest/mmap.c @@ -24,6 +24,7 @@ void * libtest_real_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off) { size_t pagesize = libtest_get_pagesize(); + uintptr_t ret; IF_MMAP2(assert(pagesize == 4096u)); if (off < 0 || off % (off_t)pagesize) @@ -34,10 +35,11 @@ libtest_real_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off goto einval; #ifdef SYS_mmap2 - return (void *)syscall(SYS_mmap2, addr, len, prot, flags, fd, off); + ret = (uintptr_t)syscall(SYS_mmap2, addr, len, prot, flags, fd, off); #else - return (void *)syscall(SYS_mmap, addr, len, prot, flags, fd, off); + ret = (uintptr_t)syscall(SYS_mmap, addr, len, prot, flags, fd, off); #endif + return (void *)ret; einval: errno = EINVAL; @@ -48,7 +50,7 @@ einval: int libtest_real_munmap(void *addr, size_t len) { - return syscall(SYS_munmap, addr, len); + return (int)syscall(SYS_munmap, addr, len); } @@ -57,6 +59,7 @@ libtest_real_mremap(void *old_addr, size_t old_len, size_t new_len, int flags, . { va_list args; void *new_addr = NULL; + uintptr_t ret; if (flags & MREMAP_FIXED) { va_start(args, flags); @@ -64,7 +67,8 @@ libtest_real_mremap(void *old_addr, size_t old_len, size_t new_len, int flags, . va_end(args); } - return (void *)syscall(SYS_mremap, old_addr, old_len, new_len, flags, new_addr); + ret = (uintptr_t)syscall(SYS_mremap, old_addr, old_len, new_len, flags, new_addr); + return (void *)ret; } |
