From 7119bf5d860657dab7afb60fab8b7ad5dc0ef222 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 22 Jun 2020 21:58:16 +0200 Subject: [PATCH] Added rand, hash unittests --- .gitignore | 2 + GNUmakefile | 23 ++++++++--- include/afl-fuzz.h | 8 +++- src/afl-fuzz-one.c | 2 +- src/afl-fuzz.c | 9 +--- src/afl-performance.c | 10 +++++ test/unittests/unit_hash.c | 75 ++++++++++++++++++++++++++++++++++ test/unittests/unit_rand.c | 84 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 197 insertions(+), 16 deletions(-) create mode 100644 test/unittests/unit_hash.c create mode 100644 test/unittests/unit_rand.c diff --git a/.gitignore b/.gitignore index 505a4ecb..8448c8f6 100644 --- a/.gitignore +++ b/.gitignore @@ -49,5 +49,7 @@ core\.* test/unittests/unit_maybe_alloc test/unittests/unit_preallocable test/unittests/unit_list +test/unittests/unit_rand +test/unittests/unit_hash examples/afl_network_proxy/afl-network-server examples/afl_network_proxy/afl-network-client diff --git a/GNUmakefile b/GNUmakefile index a171e916..5a739ad8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -403,13 +403,24 @@ document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/ test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES) @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o -test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES) - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o - unit_maybe_alloc: test/unittests/unit_maybe_alloc.o @$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_maybe_alloc +test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o + +unit_hash: test/unittests/unit_hash.o src/afl-performance.o + @$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + ./test/unittests/unit_hash + +test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o + +unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + ./test/unittests/unit_rand + test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES) @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o @@ -417,8 +428,8 @@ unit_list: test/unittests/unit_list.o @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_list -test/unittests/preallocable.o : $(COMM_HDR) include/afl-prealloc.h test/unittests/preallocable.c $(AFL_FUZZ_FILES) - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CFLAGS_FLTO) -c test/unittests/preallocable.c -o test/unittests/preallocable.o +test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES) + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o unit_preallocable: test/unittests/unit_preallocable.o @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka @@ -429,7 +440,7 @@ unit_clean: ifneq "$(shell uname)" "Darwin" -unit: unit_maybe_alloc unit_preallocable unit_list unit_clean +unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash else diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e7b52d56..16f7d717 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -49,6 +49,7 @@ #include "sharedmem.h" #include "forkserver.h" #include "common.h" +#include "hash.h" #include #include @@ -971,13 +972,16 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) { } -static inline u32 get_rand_seed(afl_state_t *afl) { +static inline s64 rand_get_seed(afl_state_t *afl) { - if (unlikely(afl->fixed_seed)) { return (u32)afl->init_seed; } + if (unlikely(afl->fixed_seed)) { return afl->init_seed; } return afl->rand_seed[0]; } +/* initialize randomness with a given seed. Can be called again at any time. */ +void rand_set_seed(afl_state_t *afl, s64 init_seed); + /* Find first power of two greater or equal to val (assuming val under 2^63). */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index e42a323d..60db9777 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2458,7 +2458,7 @@ radamsa_stage: for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { u32 new_len = afl->radamsa_mutate_ptr(save_buf, len, new_buf, max_len, - get_rand_seed(afl)); + rand_get_seed(afl)); if (new_len) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index bfd7cb33..c8083f71 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -289,7 +289,7 @@ int main(int argc, char **argv_orig, char **envp) { doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH; gettimeofday(&tv, &tz); - afl->init_seed = tv.tv_sec ^ tv.tv_usec ^ getpid(); + rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid()); while ((opt = getopt(argc, argv, "+c:i:I:o:f:m:t:T:dnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) > @@ -311,7 +311,7 @@ int main(int argc, char **argv_orig, char **envp) { case 's': { - afl->init_seed = strtoul(optarg, 0L, 10); + rand_set_seed(afl, strtoul(optarg, 0L, 10)); afl->fixed_seed = 1; break; @@ -833,11 +833,6 @@ int main(int argc, char **argv_orig, char **envp) { } - afl->rand_seed[0] = hash64((void *)&afl->init_seed, sizeof(u32), HASH_CONST); - afl->rand_seed[1] = afl->rand_seed[0] ^ 0x1234567890abcdef; - afl->rand_seed[2] = afl->rand_seed[0] & 0x0123456789abcdef; - afl->rand_seed[3] = afl->rand_seed[0] | 0x01abcde43f567908; - if (afl->use_radamsa) { if (afl->limit_time_sig > 0) { diff --git a/src/afl-performance.c b/src/afl-performance.c index 8efefcd8..757bbe1e 100644 --- a/src/afl-performance.c +++ b/src/afl-performance.c @@ -33,6 +33,16 @@ static inline uint64_t rotl(const uint64_t x, int k) { } +void rand_set_seed(afl_state_t *afl, s64 init_seed) { + + afl->init_seed = init_seed; + afl->rand_seed[0] = hash64((void *)&afl->init_seed, sizeof(afl->init_seed), HASH_CONST); + afl->rand_seed[1] = afl->rand_seed[0] ^ 0x1234567890abcdef; + afl->rand_seed[2] = afl->rand_seed[0] & 0x0123456789abcdef; + afl->rand_seed[3] = afl->rand_seed[0] | 0x01abcde43f567908; + +} + uint64_t rand_next(afl_state_t *afl) { const uint64_t result = diff --git a/test/unittests/unit_hash.c b/test/unittests/unit_hash.c new file mode 100644 index 00000000..041d107a --- /dev/null +++ b/test/unittests/unit_hash.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +/* cmocka < 1.0 didn't support these features we need */ +#ifndef assert_ptr_equal +#define assert_ptr_equal(a, b) \ + _assert_int_equal(cast_ptr_to_largest_integral_type(a), \ + cast_ptr_to_largest_integral_type(b), \ + __FILE__, __LINE__) +#define CMUnitTest UnitTest +#define cmocka_unit_test unit_test +#define cmocka_run_group_tests(t, setup, teardown) run_tests(t) +#endif + + +extern void mock_assert(const int result, const char* const expression, + const char * const file, const int line); +#undef assert +#define assert(expression) \ + mock_assert((int)(expression), #expression, __FILE__, __LINE__); + +#include "afl-fuzz.h" +#include "hash.h" + +/* remap exit -> assert, then use cmocka's mock_assert + (compile with `--wrap=exit`) */ +extern void exit(int status); +extern void __real_exit(int status); +void __wrap_exit(int status); +void __wrap_exit(int status) { + assert(0); +} + +/* ignore all printfs */ +#undef printf +extern int printf(const char *format, ...); +extern int __real_printf(const char *format, ...); +int __wrap_printf(const char *format, ...); +int __wrap_printf(const char *format, ...) { + return 1; +} + +/* Rand with 0 seed would broke in the past */ +static void test_hash(void **state) { + + char bitmap[64] = {0}; + u64 hash0 = hash64(bitmap, sizeof(bitmap), 0xa5b35705); + + bitmap[10] = 1; + u64 hash1 = hash64(bitmap, sizeof(bitmap), 0xa5b35705); + + assert_int_not_equal(hash0, hash1); + + bitmap[10] = 0; + assert_int_equal(hash0, hash64(bitmap, sizeof(bitmap), 0xa5b35705)); + + bitmap[10] = 1; + assert_int_equal(hash1, hash64(bitmap, sizeof(bitmap), 0xa5b35705)); + +} + +int main(int argc, char **argv) { + + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_hash) + }; + + //return cmocka_run_group_tests (tests, setup, teardown); + __real_exit( cmocka_run_group_tests (tests, NULL, NULL) ); + + // fake return for dumb compilers + return 0; +} diff --git a/test/unittests/unit_rand.c b/test/unittests/unit_rand.c new file mode 100644 index 00000000..0a90d8d1 --- /dev/null +++ b/test/unittests/unit_rand.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include +#include +/* cmocka < 1.0 didn't support these features we need */ +#ifndef assert_ptr_equal +#define assert_ptr_equal(a, b) \ + _assert_int_equal(cast_ptr_to_largest_integral_type(a), \ + cast_ptr_to_largest_integral_type(b), \ + __FILE__, __LINE__) +#define CMUnitTest UnitTest +#define cmocka_unit_test unit_test +#define cmocka_run_group_tests(t, setup, teardown) run_tests(t) +#endif + + +extern void mock_assert(const int result, const char* const expression, + const char * const file, const int line); +#undef assert +#define assert(expression) \ + mock_assert((int)(expression), #expression, __FILE__, __LINE__); + +#include "afl-fuzz.h" + +/* remap exit -> assert, then use cmocka's mock_assert + (compile with `--wrap=exit`) */ +extern void exit(int status); +extern void __real_exit(int status); +void __wrap_exit(int status); +void __wrap_exit(int status) { + assert(0); +} + +/* ignore all printfs */ +#undef printf +extern int printf(const char *format, ...); +extern int __real_printf(const char *format, ...); +int __wrap_printf(const char *format, ...); +int __wrap_printf(const char *format, ...) { + return 1; +} + +/* Rand with 0 seed would broke in the past */ +static void test_rand_0(void **state) { + + afl_state_t afl = {0}; + rand_set_seed(&afl, 0); + + /* give this one chance to retry */ + assert_int_not_equal( + (rand_next(&afl) != rand_next(&afl) + || rand_next(&afl) != rand_next(&afl)) + , 0); + +} + +static void test_rand_below(void **state) { + + afl_state_t afl = {0}; + rand_set_seed(&afl, 1337); + + afl.fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY); + + assert(!(rand_below(&afl, 9000) > 9000)); + assert_int_equal(rand_below(&afl, 1), 0); + +} + +int main(int argc, char **argv) { + + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_rand_0), + cmocka_unit_test(test_rand_below) + }; + + //return cmocka_run_group_tests (tests, setup, teardown); + __real_exit( cmocka_run_group_tests (tests, NULL, NULL) ); + + // fake return for dumb compilers + return 0; +}