From 4ec1657c85d193346d9d2382b62b25e8bddbf01e Mon Sep 17 00:00:00 2001 From: Guido Vranken Date: Thu, 10 Aug 2017 23:29:50 +0200 Subject: [PATCH] Add comments to fuzzing.c, fuzzing.h, remove unused function (fuzzer_read) --- src/openvpn/fuzzing.c | 83 ++++++++++++++++++++++++++++++++++++------- src/openvpn/fuzzing.h | 12 ++++++- 2 files changed, 81 insertions(+), 14 deletions(-) diff --git a/src/openvpn/fuzzing.c b/src/openvpn/fuzzing.c index 2bf31750c..3e826238c 100644 --- a/src/openvpn/fuzzing.c +++ b/src/openvpn/fuzzing.c @@ -8,20 +8,29 @@ #include "buffer.h" #include "fuzzing.h" +/* Pointer to current position in the input buffer. + * Incremented by 1 for every byte read. */ static unsigned char* fuzzer_data = NULL; + +/* Remaining buffer size. + * Decremented by 1 for every byte read */ static size_t fuzzer_data_size = 0; +/* Sets internal buffer state. Must be called before any other functions + * in this file */ void fuzzer_set_input(unsigned char* data, size_t size) { fuzzer_data = data; fuzzer_data_size = size; } +/* Getter for pointer to current buffer position */ unsigned char* fuzzer_get_current_data(void) { return fuzzer_data; } +/* Getter for pointer to current remaining buffer size */ size_t fuzzer_get_current_size(void) { return fuzzer_data_size; @@ -33,6 +42,7 @@ void fuzzer_set_recv_no_rnd(int yesno) recv_no_rnd = yesno; } +/* Extract data of size 'size' and store it in 'dest' */ ssize_t fuzzer_get_data(void* dest, size_t size) { if ( size > fuzzer_data_size ) @@ -47,7 +57,10 @@ ssize_t fuzzer_get_data(void* dest, size_t size) return size; } - +/* Does two things: + * - Extract an integer of max size 'size' from the input stream + * - If that much data is left in the input stream, copy it to 'dest' + */ ssize_t fuzzer_get_data_rnd(void* dest, size_t size) { size_t realsize; @@ -55,18 +68,24 @@ ssize_t fuzzer_get_data_rnd(void* dest, size_t size) unsigned short realsize_us; unsigned char realsize_uc; + /* No operation */ if ( size == 0 ) { return 0; } + /* Refuse to serve requests for more than 2 gigabytes */ if ( size > 0x7FFFFFFF ) { return 0; } + /* Get an integer from the input stream. + * Use different data types for different size requests, so as not + * to waste input buffer space */ if ( size > 65535 ) { + /* An unsigned int is needed */ if ( fuzzer_get_data(&realsize_ui, sizeof(realsize_ui)) < 0 ) { return -1; @@ -75,6 +94,7 @@ ssize_t fuzzer_get_data_rnd(void* dest, size_t size) } else if ( size > 255 ) { + /* An unsigned short is needed */ if ( fuzzer_get_data(&realsize_us, sizeof(realsize_us)) < 0 ) { return -1; @@ -83,6 +103,7 @@ ssize_t fuzzer_get_data_rnd(void* dest, size_t size) } else { + /* An unsigned char will suffice */ if ( fuzzer_get_data(&realsize_uc, sizeof(realsize_uc)) < 0 ) { return -1; @@ -90,8 +111,10 @@ ssize_t fuzzer_get_data_rnd(void* dest, size_t size) realsize = realsize_uc; } + /* Map the retrieved integer to the space [0..size+1] using modulo */ realsize %= (size+1); + /* Attempt to get this much data */ return fuzzer_get_data(dest, realsize); } @@ -99,6 +122,7 @@ ssize_t fuzzer_get_integer(size_t max) { size_t s; + /* No operation */ if ( max == 0 ) { return 0; @@ -111,11 +135,13 @@ ssize_t fuzzer_get_integer(size_t max) } */ + /* Get a size_t from the input buffer */ if ( fuzzer_get_data(&s, sizeof(s)) < 0 ) { return -1; } + /* Map the retrieved integer to the space [0..max+1] using modulo */ return s % (max+1); } @@ -124,6 +150,7 @@ static char* fuzzer_get_string_inner(size_t maxsize, struct gc_arena* gc) ssize_t strsize; char* ret; + /* Get integer in range [0..maxsize] */ if ( (strsize = fuzzer_get_integer(maxsize)) < 0 ) { return NULL; @@ -131,13 +158,16 @@ static char* fuzzer_get_string_inner(size_t maxsize, struct gc_arena* gc) if ( gc == NULL ) { + /* Use default allocator */ ret = malloc(strsize+1); } else { + /* Use the garbage collector allocator */ ALLOC_ARRAY_GC(ret, char, strsize+1, gc); } + /* Allocation failure */ if ( ret == NULL ) { return NULL; @@ -152,45 +182,49 @@ static char* fuzzer_get_string_inner(size_t maxsize, struct gc_arena* gc) return NULL; } + /* Null-terminate */ ret[strsize] = 0; return ret; } +/* Create null-terminated string of length 'maxsize' from + * fuzzer input data */ char* fuzzer_get_string(size_t maxsize) { return fuzzer_get_string_inner(maxsize, NULL); } +/* Create null-terminated string of length 'maxsize' from + * fuzzer input data, allocate memory using 'gc' */ char* fuzzer_get_string_gc(size_t maxsize, struct gc_arena* gc) { return fuzzer_get_string_inner(maxsize, gc); } -ssize_t fuzzer_read(void* dest, size_t size) -{ - if ( recv_no_rnd ) - { - return fuzzer_get_data(dest, size); - } - else - { - return fuzzer_get_data_rnd(dest, size); - } -} - +/* Abstraction function for POSIX read/recv/.. + * Rather than giving socket or file data to the caller, + * return data from the fuzzer input stream + */ ssize_t fuzzer_recv(void* dest, size_t size) { if ( recv_no_rnd ) { + /* Store 'size' bytes in 'dest', or fail if insufficient data + * is available */ return fuzzer_get_data(dest, size); } else { + /* Store up to 'size' bytes in 'dest', or fail if insufficient data + * is available */ return fuzzer_get_data_rnd(dest, size); } } +/* Abstraction function for POSIX send/write/.. + * Currently always succeeds + */ ssize_t fuzzer_send(size_t size) { /* @@ -205,29 +239,52 @@ ssize_t fuzzer_send(size_t size) //return r; } +/* Pseudo-randomly alter the struct buffer members + * 'offset' and 'len' such that: + * + * offset >= 0 and offset <= capacity + * len >= 0 and len <= (capacity - offset) + */ void fuzzer_alter_buffer(struct buffer* buffer) { ssize_t newoffset, newlen; + if ( buffer->capacity == 0 ) { return; } + + /* newoffset = integer in range [0..buffer->capacity] */ FUZZER_GET_INTEGER(newoffset, buffer->capacity); + newlen = buffer->capacity - newoffset; if ( newlen != 0 ) { + /* newlen = integer in range [0..newlen] */ FUZZER_GET_INTEGER(newlen, newlen); } + buffer->offset = newoffset; buffer->len = newlen; return; + cleanup: return; } void test_undefined_memory(void* vp, size_t s) { + /* MemorySanitizer (MSAN) will not trigger an exception for + * uninitialized data unless: + * - The data is used for branching + * - The data is serialized + * + * So here we "serialize" data 'vp' of size 's' to /dev/null. + * This is a trick to force MSAN to evaluate whether any bit in this + * buffer constitutes uninitialized data. + */ + FILE* fp = fopen("/dev/null", "wb"); unsigned char* p = (unsigned char*)vp; fwrite(p, s, 1, fp); diff --git a/src/openvpn/fuzzing.h b/src/openvpn/fuzzing.h index 0dec200ac..a976d77b4 100644 --- a/src/openvpn/fuzzing.h +++ b/src/openvpn/fuzzing.h @@ -15,22 +15,29 @@ ssize_t fuzzer_get_data_rnd(void* dest, size_t size); ssize_t fuzzer_get_integer(size_t max); char* fuzzer_get_string(size_t maxsize); char* fuzzer_get_string_gc(size_t maxsize, struct gc_arena* gc); -ssize_t fuzzer_read(void* dest, size_t size); ssize_t fuzzer_recv(void* dest, size_t size); ssize_t fuzzer_send(size_t size); void fuzzer_alter_buffer(struct buffer* buffer); void test_undefined_memory(void* vp, size_t s); + +/* Get data of size 'size', store result in 'dest', + * go to 'cleanup' upon failure */ #define FUZZER_GET_DATA(dest, size) { \ if ( fuzzer_get_data((dest), (size)) < 0 ) { \ goto cleanup; \ } \ } +/* Get integer in range [0..max], store result in 'dest', + * go to 'cleanup' upon failure */ #define FUZZER_GET_INTEGER(dest, max) { \ (dest) = fuzzer_get_integer(max); \ if ( (dest) < 0 ) { \ goto cleanup; \ } \ } + +/* Get null-terminated string of size up to 'size', store + * result in 'dest', go to 'cleanup' upon failure */ #define FUZZER_GET_STRING(dest, max) { \ (dest) = NULL; \ if ( ((dest) = fuzzer_get_string(max)) == NULL ) { \ @@ -38,6 +45,9 @@ void test_undefined_memory(void* vp, size_t s); } \ } +/* Get null-terminated string of size up to 'size' using + * garbage collector 'gc', store result in 'dest', + * go to 'cleanup' upon failure */ #define FUZZER_GET_STRING_GC(dest, max, gc) { \ (dest) = NULL; \ if ( ((dest) = fuzzer_get_string_gc((max), (gc))) == NULL ) { \ -- 2.47.2