openvpn: three new fuzzers and improved proxy fuzzer (#5979)

* add list fuzzer

* add header file inclusion order.

* added an mroute fuzzer.

* add packet id fuzzer.

* refactor list, mroute and packet_id fuzzers.

* set it up so fgets always returns a string with an ASCII char.

* refactor build script.

* hook fopen and fclose in builtin_console.
This commit is contained in:
DavidKorczynski 2021-06-28 21:45:31 +01:00 committed by GitHub
parent 51a97a0c41
commit 1c54b327c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 307 additions and 4 deletions

View File

@ -28,6 +28,9 @@ sed -i 's/select(/fuzz_select(/g' ./src/openvpn/proxy.c
sed -i 's/send(/fuzz_send(/g' ./src/openvpn/proxy.c
sed -i 's/recv(/fuzz_recv(/g' ./src/openvpn/proxy.c
sed -i 's/fopen/fuzz_fopen/g' ./src/openvpn/console_builtin.c
sed -i 's/fclose/fuzz_fclose/g' ./src/openvpn/console_builtin.c
sed -i 's/fp = (flags/fp = stdout;\n\/\//g' ./src/openvpn/error.c
# Build openvpn
@ -44,13 +47,13 @@ ar r libopenvpn.a *.o
$CXX $CXXFLAGS -g -c $SRC/fuzz_randomizer.cpp -o $SRC/fuzz_randomizer.o
# Compile the fuzzers
for fuzzname in fuzz_dhcp fuzz_misc fuzz_base64 fuzz_proxy fuzz_buffer fuzz_route; do
for fuzzname in fuzz_dhcp fuzz_misc fuzz_base64 fuzz_proxy fuzz_buffer fuzz_route fuzz_packet_id fuzz_mroute fuzz_list; do
$CC -DHAVE_CONFIG_H -I. -I../.. -I../../include -I../../include -I../../src/compat \
-DPLUGIN_LIBDIR=\"/usr/local/lib/openvpn/plugins\" -Wall -std=c99 $CFLAGS \
-c $SRC/${fuzzname}.c -o ${fuzzname}.o
-c $SRC/${fuzzname}.c -o $SRC/${fuzzname}.o
# Link with CXX
$CXX ${CXXFLAGS} ${LIB_FUZZING_ENGINE} ./${fuzzname}.o -o $OUT/${fuzzname} $SRC/fuzz_randomizer.o \
$CXX ${CXXFLAGS} ${LIB_FUZZING_ENGINE} $SRC/${fuzzname}.o -o $OUT/${fuzzname} $SRC/fuzz_randomizer.o \
libopenvpn.a ../../src/compat/.libs/libcompat.a /usr/lib/x86_64-linux-gnu/libnsl.a \
/usr/lib/x86_64-linux-gnu/libresolv.a /usr/lib/x86_64-linux-gnu/liblzo2.a \
-lssl -lcrypto -ldl

View File

@ -25,9 +25,14 @@ ssize_t fuzz_read(int sockfd, void *buf, size_t len){
return fuzz_get_random_data(buf, len);
}
char *fuzz_fgets(char *s, int size, FILE *stream) {
ssize_t v = fuzz_get_random_data(s, size-1);
if (s[0] == '\0') {
// We use fgets to get trusted input. As such, assume we have
// an ascii printable char at the beginning.
printf("Calling into fgets\n");
if (s[0] <= 0x21 || s[0] >= 0x7f) {
s[0] = 'A';
}
s[size-1] = '\0';
@ -45,3 +50,14 @@ int fuzz_select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, s
ssize_t fuzz_send(int sockfd, const void *buf, size_t len, int flags) {
return len;
}
FILE *fp_p = NULL;
FILE *fuzz_fopen(const char *pathname, const char *mode) {
if (mode == NULL) return fp_p;
return fp_p;
}
int fuzz_fclose(FILE *stream) {
if (stream == NULL) return 1;
return 2;
}

View File

@ -0,0 +1,135 @@
/* Copyright 2021 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "config.h"
#include "syshead.h"
#include "list.h"
#include "fuzz_randomizer.h"
#define KEY_SIZE 23
/* Required for hash_init() */
static uint32_t word_hash_function(const void *key, uint32_t iv) {
return hash_func(key, KEY_SIZE, iv);
}
/* Required for hash_init() */
static bool word_compare_function(const void *key1, const void *key2) {
return ((size_t)key1 & 0xFFF) == ((size_t)key1 & 0xFFF);
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
struct gc_arena gc;
struct hash *hash = NULL;
ssize_t generic_ssizet, generic_ssizet2, num_loops;
fuzz_random_init(data, size);
gc = gc_new();
int total_to_fuzz = fuzz_randomizer_get_int(1, 20);
for (int i = 0; i < total_to_fuzz; i++) {
generic_ssizet = fuzz_randomizer_get_int(0, 8);
switch (generic_ssizet) {
case 0:
if (hash == NULL) {
int n_buckets = fuzz_randomizer_get_int(1, 1000);
uint32_t iv;
hash =
hash_init(n_buckets, iv, word_hash_function, word_compare_function);
}
break;
case 1:
if (hash) {
hash_free(hash);
hash = NULL;
}
break;
case 2:
if (hash) {
struct hash_iterator hi;
struct hash_element *he;
hash_iterator_init(hash, &hi);
while ((he = hash_iterator_next(&hi))) {
void *w = he->value;
}
hash_iterator_free(&hi);
}
break;
case 3:
if (hash) {
void *key;
void *value;
char arr[KEY_SIZE];
memset(arr, 0, KEY_SIZE);
fuzz_get_random_data(arr, KEY_SIZE);
key = (void *)arr;
if (!hash_lookup(hash, key)) {
generic_ssizet = fuzz_randomizer_get_int(0, 0xfffffff);
value = (void *)generic_ssizet;
hash_add(hash, key, value, false);
}
}
break;
case 4:
if (hash) {
hash_n_elements(hash);
}
break;
case 5:
if (hash) {
hash_n_buckets(hash);
}
break;
case 6:
if (hash) {
uint32_t hv;
generic_ssizet = fuzz_randomizer_get_int(0, 0xfffffff);
hv = generic_ssizet;
hash_bucket(hash, hv);
}
break;
case 7:
if (hash) {
void *key;
char arr[KEY_SIZE];
memset(arr, 0, KEY_SIZE);
fuzz_get_random_data(arr, KEY_SIZE);
key = (void *)arr;
hash_remove(hash, key);
}
break;
case 8:
if (hash) {
void *value;
generic_ssizet = fuzz_randomizer_get_int(0, 0xfffffff);
value = (void *)generic_ssizet;
hash_remove_by_value(hash, value);
}
default:
break;
}
}
if (hash) {
hash_free(hash);
}
gc_free(&gc);
fuzz_random_destroy();
return 0;
}

View File

@ -0,0 +1,72 @@
/* Copyright 2021 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "config.h"
#include "syshead.h"
#include "init.h"
#include "mroute.h"
#include "fuzz_randomizer.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fuzz_random_init(data, size);
struct buffer buf;
struct gc_arena gc;
gc = gc_new();
char *tmp = get_random_string();
buf = string_alloc_buf(tmp, &gc);
free(tmp);
struct mroute_addr src_addr;
struct mroute_addr dst_addr;
mroute_addr_init(&src_addr);
mroute_addr_init(&dst_addr);
unsigned int ret = mroute_extract_addr_ip(&src_addr, &dst_addr, &buf);
if (ret & MROUTE_EXTRACT_SUCCEEDED) {
mroute_addr_mask_host_bits(&src_addr);
mroute_addr_print(&src_addr, &gc);
mroute_learnable_address(&src_addr, &gc);
}
uint16_t vid;
struct mroute_addr a1, a2, a3, a4;
mroute_addr_init(&a1);
mroute_addr_init(&a2);
mroute_addr_init(&a3);
mroute_addr_init(&a4);
mroute_extract_addr_ether(&a1, &a2, &a3, &a3, vid, &buf);
if (size > sizeof(struct openvpn_sockaddr)) {
struct openvpn_sockaddr local_sock;
memcpy(&local_sock, data, sizeof(struct openvpn_sockaddr));
mroute_extract_openvpn_sockaddr(&a1, &local_sock, true);
mroute_extract_openvpn_sockaddr(&a1, &local_sock, false);
}
struct mroute_helper *mhelper = NULL;
mhelper = mroute_helper_init(fuzz_randomizer_get_int(0, 0xfffffff));
if (mhelper != NULL) {
mroute_helper_add_iroute46(mhelper, fuzz_randomizer_get_int(0, MR_HELPER_NET_LEN-1));
mroute_helper_free(mhelper);
}
gc_free(&gc);
fuzz_random_destroy();
return 0;
}

View File

@ -0,0 +1,77 @@
/* Copyright 2021 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "config.h"
#include "syshead.h"
#include "init.h"
#include "packet_id.h"
#include "fuzz_randomizer.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fuzz_random_init(data, size);
struct packet_id pid;
struct packet_id_net pin;
const int seq_backtrack = 10;
const int time_backtrack = 10;
packet_id_init(&pid, seq_backtrack, time_backtrack, "name", 0);
int total_sends = fuzz_randomizer_get_int(0, 10);
for (int i = 0; i < total_sends; i++) {
update_time();
pin.time = fuzz_randomizer_get_int(0, 0xfffffff);
pin.id = fuzz_randomizer_get_int(0, 0xfffffff);
packet_id_reap_test(&pid.rec);
bool test = packet_id_test(&pid.rec, &pin);
if (test) {
packet_id_add(&pid.rec, &pin);
}
}
packet_id_free(&pid);
struct gc_arena gc;
gc = gc_new();
struct buffer buf;
char *tmp = get_random_string();
buf = string_alloc_buf(tmp, &gc);
free(tmp);
packet_id_read(&pid, &buf, false);
packet_id_read(&pid, &buf, true);
gc_free(&gc);
char filename[256];
sprintf(filename, "/tmp/libfuzzer.%d", getpid());
FILE *fp = fopen(filename, "wb");
if (!fp) {
return 0;
}
fwrite(data, size, 1, fp);
fclose(fp);
struct packet_id_persist p;
memset(&p, 0, sizeof(struct packet_id_persist));
packet_id_persist_init(&p);
packet_id_persist_load(&p, filename);
gc = gc_new();
packet_id_persist_print(&p, &gc);
gc_free(&gc);
packet_id_persist_close(&p);
fuzz_random_destroy();
return 0;
}