fuzzing: move harnesses from oss-fuzz to repo

This commit is contained in:
aarnav 2026-01-13 09:41:33 +00:00
parent 50a6b663e4
commit c3a79422c8
19 changed files with 3149 additions and 0 deletions

25
fuzz/README.md Normal file
View file

@ -0,0 +1,25 @@
# OpenVPN fuzzing harnesses
## How to build
```
git clone git@github.com:google/oss-fuzz
cd oss-fuzz
python3 infra_helpers.py build_fuzzers openvpn
ls -l ./build/out/openvpn | grep fuzz
```
For more configuration options such as sanitizers and fuzzers, run: ``python3 infra_helpers.py build_fuzzers --help``
## Harnesses
- `fuzz_base64.c`: Fuzzes OpenVPN base64 encode/decode functions.
- `fuzz_buffer.c`: Fuzzes buffer and string utility routines.
- `fuzz_crypto.c`: Fuzzes key handling plus OpenVPN encrypt/decrypt paths.
- `fuzz_dhcp.c`: Fuzzes DHCP router option parsing via `dhcp_extract_router_msg`.
- `fuzz_forward.c`: Fuzzes forward path functions for incoming/outgoing tun and link processing.
- `fuzz_list.c`: Fuzzes hash/list utilities (init/add/remove/iterate) in `list.h`.
- `fuzz_misc.c`: Fuzzes env_set management and misc string helpers like `sanitize_control_message`.
- `fuzz_mroute.c`: Fuzzes multicast route parsing/helpers (`mroute_extract_*`, helper init).
- `fuzz_packet_id.c`: Fuzzes packet ID tracking, read/write, and persistence load/save.
- `fuzz_proxy.c`: Fuzzes HTTP proxy auth/setup via `establish_http_proxy_passthru`.
- `fuzz_route.c`: Fuzzes IPv4/IPv6 route option parsing and add/delete routing logic.
- `fuzz_verify_cert.c`: Fuzzes X509 parsing and TLS cert verification (`verify_cert`).

81
fuzz/build.sh Executable file
View file

@ -0,0 +1,81 @@
#!/bin/bash -eu
# 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.
#
################################################################################
OPENVPN_ROOT=${SRC}/openvpn
FUZZ_DIR=${OPENVPN_ROOT}/fuzz
BASE=${OPENVPN_ROOT}/src/openvpn
apply_sed_changes() {
sed -i 's/read(/fuzz_read(/g' ${BASE}/console_systemd.c
sed -i 's/fgets(/fuzz_fgets(/g' ${BASE}/console_builtin.c
sed -i 's/fgets(/fuzz_fgets(/g' ${BASE}/misc.c
sed -i 's/#include "forward.h"/#include "fuzz_header.h"\n#include "forward.h"/g' ${BASE}/proxy.c
sed -i 's/openvpn_select(/fuzz_select(/g' ${BASE}/proxy.c
sed -i 's/openvpn_send(/fuzz_send(/g' ${BASE}/proxy.c
sed -i 's/recv(/fuzz_recv(/g' ${BASE}/proxy.c
sed -i 's/isatty/fuzz_isatty/g' ${BASE}/console_builtin.c
sed -i 's/fopen/fuzz_fopen/g' ${BASE}/console_builtin.c
sed -i 's/fclose/fuzz_fclose/g' ${BASE}/console_builtin.c
sed -i 's/sendto/fuzz_sendto/g' ${BASE}/socket.h
sed -i 's/#include "misc.h"/#include "misc.h"\nextern size_t fuzz_sendto(int sockfd, void *buf, size_t len, int flags, struct sockaddr *dest_addr, socklen_t addrlen);/g' ${BASE}/socket.h
sed -i 's/fp = (flags/fp = stdout;\n\/\//g' ${BASE}/error.c
sed -i 's/crypto_msg(M_FATAL/crypto_msg(M_WARN/g' ${BASE}/crypto_openssl.c
sed -i 's/msg(M_FATAL, \"Cipher/return;msg(M_FATAL, \"Cipher/g' ${BASE}/crypto.c
sed -i 's/msg(M_FATAL/msg(M_WARN/g' ${BASE}/crypto.c
sed -i 's/= write/= fuzz_write/g' ${BASE}/packet_id.c
}
echo "" >> ${BASE}/openvpn.c
echo "#include \"fake_fuzz_header.h\"" >> ${BASE}/openvpn.c
echo "ssize_t fuzz_get_random_data(void *buf, size_t len) { return 0; }" >> ${BASE}/fake_fuzz_header.h
echo "int fuzz_success;" >> ${BASE}/fake_fuzz_header.h
# Apply hooking changes
apply_sed_changes
# Copy corpuses out
zip -r $OUT/fuzz_verify_cert_seed_corpus.zip $SRC/boringssl/fuzz/cert_corpus
# Build openvpn
autoreconf -ivf
./configure --disable-lz4 --with-crypto-library=openssl OPENSSL_LIBS="-L/usr/local/ssl/ -lssl -lcrypto" OPENSSL_CFLAGS="-I/usr/local/ssl/include/"
make -j$(nproc)
# Make openvpn object files into a library we can link fuzzers to
cd src/openvpn
rm openvpn.o
ar r libopenvpn.a *.o
# Compile our fuzz helper
$CXX $CXXFLAGS -g -c ${FUZZ_DIR}/fuzz_randomizer.cpp -o ${FUZZ_DIR}/fuzz_randomizer.o
# Compile the fuzzers
for fuzzname in dhcp misc base64 proxy buffer route packet_id mroute list verify_cert; do
$CC -DHAVE_CONFIG_H -I. -I../.. -I../../include -I../../src/compat -I/usr/include/libnl3/ \
-DPLUGIN_LIBDIR=\"/usr/local/lib/openvpn/plugins\" -std=c99 $CFLAGS \
-c ${FUZZ_DIR}/fuzz_${fuzzname}.c -o ${FUZZ_DIR}/fuzz_${fuzzname}.o
# Link with CXX
$CXX ${CXXFLAGS} ${LIB_FUZZING_ENGINE} $FUZZ_DIR/fuzz_${fuzzname}.o -o $OUT/fuzz_${fuzzname} $FUZZ_DIR/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 -l:libnl-3.a -l:libnl-genl-3.a -lcap-ng -pthread
done

47
fuzz/fuzz.h Normal file
View file

@ -0,0 +1,47 @@
/* 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 <fuzzer/FuzzedDataProvider.h>
// Returns a NULL-terminated C string that should be freed by the caller.
char *get_modifiable_string(FuzzedDataProvider &provider) {
std::string s1 = provider.ConsumeRandomLengthString();
char *tmp = (char *)malloc(s1.size() + 1);
memcpy(tmp, s1.c_str(), s1.size());
tmp[s1.size()] = '\0';
return tmp;
}
FuzzedDataProvider *prov = NULL;
extern "C" ssize_t fuzz_get_random_data(void *buf, size_t len) {
size_t ret_val;
char *cbuf = (char*)buf;
if (prov->remaining_bytes() == 0) {
return -1;
}
double prob = prov->ConsumeProbability<double>();
if (prob < 0.05) {
return 0;
}
if (len == 1) {
ret_val = prov->ConsumeData(buf, 1);
return ret_val;
}
ret_val = prov->ConsumeData(buf, len);
return ret_val;
}

43
fuzz/fuzz_base64.c Normal file
View file

@ -0,0 +1,43 @@
/* 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 <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "base64.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size > 500) {
return 0;
}
char *new_str = (char *)malloc(size + 1);
if (new_str == NULL) {
return 0;
}
memcpy(new_str, data, size);
new_str[size] = '\0';
char *str = NULL;
openvpn_base64_encode(data, size, &str);
if(str != NULL) {
free(str);
}
uint16_t outsize = 10000;
char *output_buf = (char *)malloc(outsize);
openvpn_base64_decode(new_str, output_buf, outsize);
free(output_buf);
free(new_str);
return 0;
}

263
fuzz/fuzz_buffer.c Normal file
View file

@ -0,0 +1,263 @@
/* 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 "misc.h"
#include "buffer.h"
#include "fuzz_randomizer.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fuzz_random_init(data,size);
struct gc_arena gc;
struct buffer *bufp;
struct buffer buf, buf2;
struct buffer_list *buflistp = NULL;
ssize_t generic_ssizet, _size;
char *tmp;
char *tmp2;
char match;
gc = gc_new();
bufp = NULL;
int total_to_fuzz = fuzz_randomizer_get_int(1, 20);
for (int i = 0; i < total_to_fuzz; i++) {
if (bufp == NULL) {
generic_ssizet = fuzz_randomizer_get_int(0, 1);
if (generic_ssizet == 0) {
_size = fuzz_randomizer_get_int(0, 100);
buf = alloc_buf_gc(_size, &gc);
bufp = &buf;
} else {
tmp = get_random_string();
buf = string_alloc_buf(tmp, &gc);
bufp = &buf;
free(tmp);
tmp = NULL;
}
} else {
#define NUM_TARGETS 31
generic_ssizet = fuzz_randomizer_get_int(0, NUM_TARGETS);
switch (generic_ssizet) {
case 0:
buf_clear(bufp);
break;
case 1:
buf2 = clone_buf(bufp);
free_buf(&buf2);
break;
case 2:
buf_defined(bufp);
break;
case 3:
buf_valid(bufp);
break;
case 4:
buf_bptr(bufp);
break;
case 5:
buf_len(bufp);
break;
case 6:
buf_bend(bufp);
break;
case 7:
buf_blast(bufp);
break;
case 8:
buf_str(bufp);
break;
case 9:
generic_ssizet = fuzz_randomizer_get_int(0, 255);
buf_rmtail(bufp, (uint8_t)generic_ssizet);
break;
case 10:
buf_chomp(bufp);
break;
case 11:
tmp = get_random_string();
skip_leading_whitespace(tmp);
free(tmp);
tmp = NULL;
break;
case 12:
tmp = get_random_string();
chomp(tmp);
free(tmp);
tmp = NULL;
break;
case 13:
tmp = get_random_string();
tmp2 = get_random_string();
rm_trailing_chars(tmp, tmp2);
free(tmp);
free(tmp2);
tmp = NULL;
tmp2 = NULL;
break;
case 14:
tmp = get_random_string();
string_clear(tmp);
free(tmp);
tmp = NULL;
break;
case 15:
tmp = get_random_string();
buf_string_match_head_str(bufp, tmp);
free(tmp);
tmp = NULL;
break;
case 16:
tmp = get_random_string();
buf_string_compare_advance(bufp, tmp);
free(tmp);
tmp = NULL;
break;
case 17:
generic_ssizet = fuzz_randomizer_get_int(0, 255);
tmp = get_random_string();
if (strlen(tmp) > 0) {
buf_parse(bufp, (int)generic_ssizet, tmp, strlen(tmp));
}
free(tmp);
tmp = NULL;
break;
case 18:
tmp = get_random_string();
string_mod(tmp, fuzz_randomizer_get_int(0, 12312),
fuzz_randomizer_get_int(0, 23141234),
(char)fuzz_randomizer_get_int(0, 255));
free(tmp);
tmp = NULL;
break;
case 19:
tmp = get_random_string();
match = (char)fuzz_randomizer_get_int(0, 255);
if (match != 0) {
string_replace_leading(tmp, match, (char)fuzz_randomizer_get_int(0, 255));
}
free(tmp);
tmp = NULL;
break;
case 20:
tmp = get_random_string();
buf_write(bufp, tmp, strlen(tmp));
free(tmp);
tmp = NULL;
break;
case 21:
tmp = get_random_string();
buf_write_prepend(bufp, tmp, strlen(tmp));
free(tmp);
tmp = NULL;
break;
case 22:
buf_write_u8(bufp, fuzz_randomizer_get_int(0, 255));
break;
case 23:
buf_write_u16(bufp, fuzz_randomizer_get_int(0, 1024));
break;
case 24:
buf_write_u32(bufp, fuzz_randomizer_get_int(0, 12312));
break;
case 25:
tmp = get_random_string();
buf_catrunc(bufp, tmp);
free(tmp);
tmp = NULL;
break;
case 26:
tmp = get_random_string();
buf_puts(bufp, tmp);
free(tmp);
tmp = NULL;
break;
case 27:
buf_advance(bufp, fuzz_randomizer_get_int(0, 25523));
break;
case 28:
buf_prepend(bufp, fuzz_randomizer_get_int(0, 251235));
break;
case 29:
buf_reverse_capacity(bufp);
break;
case 30:
buf_forward_capacity_total(bufp);
break;
case 31:
buf_forward_capacity(bufp);
break;
}
}
if (buflistp == NULL) {
buflistp = buffer_list_new();
} else {
#define NUM_LIST_TARGETS 6
generic_ssizet = fuzz_randomizer_get_int(0, NUM_LIST_TARGETS);
switch (generic_ssizet) {
case 0:
buffer_list_free(buflistp);
buflistp = NULL;
break;
case 1:
buffer_list_defined(buflistp);
break;
case 2:
tmp = get_random_string();
if (strlen(tmp) < BUF_SIZE_MAX) {
buffer_list_push(buflistp, tmp);
}
free(tmp);
tmp = NULL;
break;
case 3:
buffer_list_peek(buflistp);
break;
case 4:
buffer_list_pop(buflistp);
break;
case 5:
tmp = get_random_string();
buffer_list_aggregate_separator(
buflistp, fuzz_randomizer_get_int(0, 1024), tmp);
free(tmp);
tmp = NULL;
break;
case 6:
buffer_list_aggregate(buflistp,
fuzz_randomizer_get_int(0, 1024));
break;
}
}
}
// Cleanup
buffer_list_free(buflistp);
gc_free(&gc);
fuzz_random_destroy();
return 0;
}

258
fuzz/fuzz_crypto.c Normal file
View file

@ -0,0 +1,258 @@
/* 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 <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "fuzz_verify_cert.h"
#include "misc.h"
#include "manage.h"
#include "otime.h"
#include "base64.h"
#include "ssl_verify.h"
#include "ssl_verify_backend.h"
#include "fuzz_randomizer.h"
static void key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key,
size_t key_len) {
//const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher);
cipher_ctx_t *cipher_kt = ctx->cipher;
/* Only use implicit IV in AEAD cipher mode, where HMAC key is not used */
if (cipher_ctx_mode_aead(cipher_kt)) {
size_t impl_iv_len = 0;
ASSERT(cipher_kt_iv_size(cipher_kt) >= OPENVPN_AEAD_MIN_IV_LEN);
impl_iv_len = cipher_kt_iv_size(cipher_kt) - sizeof(packet_id_type);
ASSERT(impl_iv_len <= OPENVPN_MAX_IV_LENGTH);
ASSERT(impl_iv_len <= key_len);
memcpy(ctx->implicit_iv, key, impl_iv_len);
ctx->implicit_iv_len = impl_iv_len;
}
}
static int init_frame(struct frame *frame) {
frame->link_mtu = fuzz_randomizer_get_int(100, 1000);
frame->extra_buffer = fuzz_randomizer_get_int(100, 1000);
frame->link_mtu_dynamic = fuzz_randomizer_get_int(100, 1000);
frame->extra_frame = fuzz_randomizer_get_int(100, 1000);
frame->extra_tun = fuzz_randomizer_get_int(100, 1000);
frame->extra_link = fuzz_randomizer_get_int(100, 1000);
frame->align_flags = 0;
frame->align_adjust = 0;
if (TUN_MTU_SIZE(frame) <= 0) {
return -1;
}
return 0;
}
int LLVMFuzzerInitialize(int *argc, char ***argv) {
OPENSSL_malloc_init();
SSL_library_init();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fuzz_random_init(data, size);
fuzz_success = 1;
bool key_ctx_dec_initialized = false;
bool key_ctx_enc_initialized = false;
struct key_ctx key_ctx_dec;
memset(&key_ctx_dec, 0, sizeof(struct key_ctx));
struct key_ctx key_ctx_enc;
memset(&key_ctx_enc, 0, sizeof(struct key_ctx));
struct gc_arena gc;
struct tls_session *session = NULL;
X509 *x509 = NULL;
gc = gc_new();
gb_init();
// Read key file
struct key2 key2;
char *keydata = gb_get_random_string();
read_key_file(&key2, keydata, RKF_INLINE);
// init key type
struct key_type kt;
memset(&kt, 0, sizeof(struct key_type));
char *ciphername = gb_get_random_string();
char *authname = gb_get_random_string();
bool key_type_initialized = false;
if (strcmp(ciphername, "AES-256-GCM") == 0 ||
strcmp(ciphername, "AES-128-GCM") == 0 ||
strcmp(ciphername, "AES-192-GCM") == 0 ||
strcmp(ciphername, "CAMELLIA-128-CFB128") == 0) {
int v = fuzz_randomizer_get_int(0, 1);
if (v == 0) {
init_key_type(&kt, ciphername, authname, true, 0);
} else {
init_key_type(&kt, ciphername, authname, false, 0);
}
key_type_initialized = true;
}
if (fuzz_success == 0) {
goto cleanup;
}
// Generate key.
// Identify which one we should do, read or generate a random key.
int c = fuzz_randomizer_get_int(0, 1);
const uint8_t d[1024];
int key_read = 0;
struct key key;
if (c == 0) {
if (fuzz_get_random_data(d, 1024) != 1024) {
struct buffer buf = alloc_buf(1024);
buf_write(&buf, d, 1024);
if (read_key(&key, &kt, &buf) == 1) {
key_read = 1;
}
free_buf(&buf);
}
}
else {
if (key_type_initialized == true) {
generate_key_random(&key, &kt);
}
}
if (fuzz_success == 0) {
goto cleanup;
}
key_read = 1;
// init decryption context
if (key_type_initialized && key_read) {
init_key_ctx(&key_ctx_dec, &key, &kt, OPENVPN_OP_DECRYPT, "x");
key_ctx_update_implicit_iv(&key_ctx_dec, &(key.hmac), MAX_HMAC_KEY_LENGTH);
key_ctx_dec_initialized = true;
}
// init encryption context
if (key_type_initialized && key_read) {
init_key_ctx(&key_ctx_enc, &key, &kt, OPENVPN_OP_DECRYPT, "x");
key_ctx_update_implicit_iv(&key_ctx_enc, &(key.hmac), MAX_HMAC_KEY_LENGTH);
key_ctx_enc_initialized = true;
}
// perform encryption
struct frame frame;
memset(&frame, 0, sizeof(struct frame));
if (key_ctx_enc_initialized == true && key_ctx_dec_initialized == true &&
init_frame(&frame) == 0) {
struct crypto_options opt;
memset(&opt, 0, sizeof(opt));
opt.pid_persist = NULL;
opt.key_ctx_bi.encrypt = key_ctx_enc;
opt.key_ctx_bi.decrypt = key_ctx_dec;
opt.key_ctx_bi.initialized = true;
opt.packet_id.rec.initialized = true;
opt.packet_id.rec.seq_list = NULL;
opt.packet_id.rec.name = NULL;
void *buf_p;
struct buffer encrypt_workspace = alloc_buf_gc(BUF_SIZE(&(frame)), &gc);
struct buffer work = alloc_buf_gc(BUF_SIZE(&(frame)), &gc);
struct buffer src = alloc_buf_gc(TUN_MTU_SIZE(&(frame)), &gc);
struct buffer buf = clear_buf();
int x = fuzz_randomizer_get_int(1, TUN_MTU_SIZE(&frame));
ASSERT(buf_init(&work, FRAME_HEADROOM(&(frame))));
ASSERT(buf_init(&src, 0));
src.len = x;
ASSERT(rand_bytes(BPTR(&src), BLEN(&src)));
buf = work;
buf_p = buf_write_alloc(&buf, BLEN(&src));
ASSERT(buf_p);
memcpy(buf_p, BPTR(&src), BLEN(&src));
ASSERT(buf_init(&encrypt_workspace, FRAME_HEADROOM(&(frame))));
openvpn_encrypt(&buf, encrypt_workspace, &opt);
}
// perform decryption
memset(&frame, 0, sizeof(struct frame));
if (key_ctx_dec_initialized == true && key_ctx_enc_initialized == true &&
init_frame(&frame) == 0) {
struct crypto_options opt;
memset(&opt, 0, sizeof(opt));
opt.pid_persist = NULL;
opt.key_ctx_bi.encrypt = key_ctx_enc;
opt.key_ctx_bi.decrypt = key_ctx_dec;
opt.key_ctx_bi.initialized = true;
opt.packet_id.rec.initialized = true;
opt.packet_id.rec.seq_list = NULL;
opt.packet_id.rec.name = NULL;
void *buf_p;
struct buffer decrypt_workspace = alloc_buf_gc(BUF_SIZE(&(frame)), &gc);
struct buffer work = alloc_buf_gc(BUF_SIZE(&(frame)), &gc);
struct buffer src = alloc_buf_gc(TUN_MTU_SIZE(&(frame)), &gc);
struct buffer buf = clear_buf();
int x = fuzz_randomizer_get_int(1, TUN_MTU_SIZE(&frame));
ASSERT(buf_init(&work, FRAME_HEADROOM(&(frame))));
ASSERT(buf_init(&src, 0));
src.len = x;
ASSERT(rand_bytes(BPTR(&src), BLEN(&src)));
buf = work;
buf_p = buf_write_alloc(&buf, BLEN(&src));
ASSERT(buf_p);
memcpy(buf_p, BPTR(&src), BLEN(&src));
ASSERT(buf_init(&decrypt_workspace, FRAME_HEADROOM(&(frame))));
openvpn_decrypt(&buf, decrypt_workspace, &opt, &frame, BPTR(&buf));
}
cleanup:
// cleanup
gc_free(&gc);
if (key_ctx_dec_initialized == true) {
free_key_ctx(&key_ctx_dec);
}
if (key_ctx_enc_initialized == true) {
free_key_ctx(&key_ctx_enc);
}
fuzz_random_destroy();
gb_cleanup();
return 0;
}

37
fuzz/fuzz_dhcp.c Normal file
View file

@ -0,0 +1,37 @@
/* 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 "dhcp.h"
#include "buffer.h"
#include "fuzz_randomizer.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
struct buffer ipbuf;
in_addr_t ret;
fuzz_random_init(data, size);
char *ran_val = get_random_string();
ipbuf = alloc_buf(strlen(ran_val));
if (buf_write(&ipbuf, ran_val, strlen(ran_val)) != false) {
ret = dhcp_extract_router_msg(&ipbuf);
}
free_buf(&ipbuf);
fuzz_random_destroy();
free(ran_val);
return 0;
}

228
fuzz/fuzz_forward.c Normal file
View file

@ -0,0 +1,228 @@
/* 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 <sys/time.h>
#include "syshead.h"
#include "interval.h"
#include "init.h"
#include "buffer.h"
#include "forward.h"
#include "fuzz_randomizer.h"
static int init_c2_outgoing_link(struct context_2 *c2, struct gc_arena *gc) {
struct link_socket_actual *to_link_addr = NULL;
struct link_socket *link_socket = NULL;
struct socks_proxy_info *socks_proxy = NULL;
struct buffer buf;
c2->tun_write_bytes = 0;
ALLOC_ARRAY_GC(link_socket, struct link_socket, 1, gc);
memset(link_socket, 0, sizeof(*link_socket));
c2->link_socket = link_socket;
if (fuzz_randomizer_get_int(0, 2) != 0) {
c2->link_socket->info.proto = PROTO_UDP;
} else {
c2->link_socket->info.proto = PROTO_TCP_SERVER;
}
ALLOC_ARRAY_GC(socks_proxy, struct socks_proxy_info, 1, gc);
memset(socks_proxy, 0, sizeof(*socks_proxy));
c2->link_socket->socks_proxy = socks_proxy;
c2->frame.link_mtu_dynamic = fuzz_randomizer_get_int(0, 0xfffffff);
c2->frame.extra_frame = fuzz_randomizer_get_int(0, 0xfffffff);
c2->frame.extra_tun = fuzz_randomizer_get_int(0, 0xfffffff);
c2->frame.link_mtu = fuzz_randomizer_get_int(0, 0xfffffff);
ALLOC_ARRAY_GC(to_link_addr, struct link_socket_actual, 1, gc);
memset(to_link_addr, 0, sizeof(*to_link_addr));
c2->to_link_addr = to_link_addr;
c2->to_link_addr->dest.addr.sa.sa_family = AF_INET;
c2->to_link_addr->dest.addr.in4.sin_addr.s_addr = 1;
char *tmp = get_random_string();
buf = alloc_buf_gc(strlen(tmp), gc);
buf_write(&buf, tmp, strlen(tmp));
int val = fuzz_randomizer_get_int(0, strlen(tmp));
buf.offset = val;
free(tmp);
c2->link_socket->stream_buf.maxlen = BLEN(&buf);
c2->to_link = buf;
if (buf.offset < 10) {
return -1;
}
return 0;
}
void fuzz_process_outgoing_link(const uint8_t *data, size_t size) {
struct context ctx;
struct gc_arena gc = gc_new();
memset(&ctx, 0, sizeof(ctx));
if (init_c2_outgoing_link(&ctx.c2, &gc) == 0) {
process_outgoing_link(&ctx);
}
gc_free(&gc);
}
static int _init_options(struct options *options, struct client_nat_entry **cne,
struct gc_arena *gc) {
options->passtos = false;
options->mode = MODE_POINT_TO_POINT;
options->allow_recursive_routing = true;
options->client_nat = new_client_nat_list(gc);
struct client_nat_entry *_cne;
ALLOC_ARRAY_GC(cne[0], struct client_nat_entry, 1, gc);
_cne = cne[0];
memset(_cne, 0, sizeof(struct client_nat_entry));
struct client_nat_option_list clist;
clist.n = 1;
clist.entries[0] = *_cne;
copy_client_nat_option_list(options->client_nat, &clist);
options->route_gateway_via_dhcp = false;
return 0;
}
static int init_c2_incoming_tun(struct context_2 *c2, struct gc_arena *gc) {
struct buffer buf;
memset(&buf, 0, sizeof(buf));
struct link_socket *link_socket = NULL;
ALLOC_ARRAY_GC(link_socket, struct link_socket, 1, gc);
c2->link_socket = link_socket;
ALLOC_OBJ_GC(c2->link_socket_info, struct link_socket_info, gc);
ALLOC_OBJ_GC(c2->link_socket_info->lsa, struct link_socket_addr, gc);
c2->link_socket_info->lsa->bind_local = NULL;
c2->link_socket_info->lsa->remote_list = NULL;
c2->link_socket_info->lsa->current_remote = NULL;
c2->link_socket_info->lsa->remote_list = NULL;
c2->es = env_set_create(gc);
c2->frame.link_mtu_dynamic = 0;
c2->frame.extra_frame = 0;
c2->frame.extra_tun = 0;
c2->to_link_addr = NULL;
char *tmp = get_random_string();
buf = alloc_buf(strlen(tmp));
buf_write(&buf, tmp, strlen(tmp));
int retval;
if (strlen(tmp) > 5) {
retval = 0;
} else {
retval = 1;
}
free(tmp);
c2->buf = buf;
c2->buffers = init_context_buffers(&c2->frame);
c2->log_rw = false;
return retval;
}
int run_process_incoming_tun(const uint8_t *data, size_t size) {
struct gc_arena gc;
struct context ctx;
struct client_nat_entry *cne[MAX_CLIENT_NAT];
struct route_list route_list;
memset(&ctx, 0, sizeof(ctx));
memset(cne, 0, sizeof(cne));
gc = gc_new();
_init_options(&ctx.options, cne, &gc);
// Init tuntap
struct tuntap tuntap;
tuntap.type = DEV_TYPE_TAP;
ctx.c1.tuntap = &tuntap;
int retval = init_c2_incoming_tun(&ctx.c2, &gc);
ctx.c1.route_list = &route_list;
if (retval == 0) {
process_incoming_tun(&ctx);
}
free(ctx.c2.buf.data);
free_context_buffers(ctx.c2.buffers);
gc_free(&gc);
}
static int init_c2_outgoing_tun(struct context_2 *c2, struct gc_arena *gc) {
struct buffer buf;
c2->tun_write_bytes = 0;
c2->frame.link_mtu_dynamic = fuzz_randomizer_get_int(0, 0xfffffff);
c2->frame.extra_frame = fuzz_randomizer_get_int(0, 0xfffffff);
c2->frame.extra_tun = fuzz_randomizer_get_int(0, 0xfffffff);
char *tmp = get_random_string();
buf = alloc_buf_gc(strlen(tmp), gc);
buf_write(&buf, tmp, strlen(tmp));
free(tmp);
c2->to_tun = buf;
return 0;
}
void run_process_outgoing_tun(uint8_t *data, size_t size) {
struct gc_arena gc;
struct context ctx;
struct tuntap tuntap;
memset(&ctx, 0, sizeof(ctx));
gc = gc_new();
tuntap.type = DEV_TYPE_TAP;
ctx.c1.tuntap = &tuntap;
init_c2_outgoing_tun(&ctx.c2, &gc);
process_outgoing_tun(&ctx);
gc_free(&gc);
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fuzz_random_init(data, size);
int dec = fuzz_randomizer_get_int(0, 2);
if (dec == 0) {
run_process_incoming_tun(data, size);
}
else if (dec == 1) {
run_process_outgoing_tun(data, size);
}
else {
fuzz_process_outgoing_link(data, size);
}
fuzz_random_destroy();
return 0;
}

79
fuzz/fuzz_header.h Normal file
View file

@ -0,0 +1,79 @@
/* 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.
*/
#ifndef FUZZ_H
#define FUZZ_H
#include <sys/types.h>
#include <sys/socket.h>
// Forward declared because we want to use FuzzedDataProvider,
// which requires CPP.
extern ssize_t fuzz_get_random_data(void *buf, size_t len);
ssize_t fuzz_recv(int sockfd, void *buf, size_t len, int flags){
return fuzz_get_random_data(buf, len);
}
ssize_t fuzz_read(int sockfd, void *buf, size_t len){
return fuzz_get_random_data(buf, len);
}
ssize_t fuzz_write(int fd, const void *buf, size_t count) {
return count;
}
int fuzz_isatty(int fd) {
return 1;
}
char *fuzz_fgets(char *s, int size, FILE *stream) {
ssize_t v = fuzz_get_random_data(s, size-1);
// 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';
return s;
}
int fuzz_select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout) {
char val;
ssize_t c = fuzz_get_random_data(&val, 1);
return c;
}
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;
}
size_t fuzz_sendto(int sockfd, void *buf, size_t len, int flags, struct sockaddr *dest_addr, socklen_t addrlen) {
if (buf == NULL) {
return len;
}
return len;
}
#endif

135
fuzz/fuzz_list.c Normal file
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;
}

62
fuzz/fuzz_misc.c Normal file
View file

@ -0,0 +1,62 @@
/* 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 "misc.h"
#include "buffer.h"
#include "fuzz_randomizer.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fuzz_random_init(data, size);
struct gc_arena gc;
struct env_set *es;
gc = gc_new();
es = env_set_create(&gc);
int total_to_fuzz = fuzz_randomizer_get_int(1, 9);
for (int i = 0; i <total_to_fuzz; i++) {
int type = fuzz_randomizer_get_int(0, 3);
char *tmp1 = get_random_string();
char *tmp2 = get_random_string();
switch (type) {
case 0:
env_set_del(es, tmp1);
break;
case 1:
env_set_add(es, tmp1);
break;
case 2:
env_set_get(es, tmp1);
break;
case 3:
if (strlen(tmp1) > 1 && strlen(tmp2) > 1) {
setenv_str(es, tmp2, tmp1);
}
break;
default:
sanitize_control_message(tmp1, &gc);
}
free(tmp1);
free(tmp2);
}
env_set_destroy(es);
gc_free(&gc);
fuzz_random_destroy();
return 0;
}

70
fuzz/fuzz_mroute.c Normal file
View file

@ -0,0 +1,70 @@
/* 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;
mroute_addr_init(&a1);
mroute_addr_init(&a2);
mroute_extract_addr_ether(&a1, &a2, 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;
}

104
fuzz/fuzz_packet_id.c Normal file
View file

@ -0,0 +1,104 @@
/* 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);
// packet id send
char *tmp2 = get_random_string();
if (strlen(tmp2) > sizeof(struct packet_id_send)) {
struct packet_id_send pidsend;
memcmp(&pidsend, tmp2, sizeof(struct packet_id_send));
struct timeval tv;
tv.tv_sec = pidsend.time;
tv.tv_usec = 0;
if (localtime(&tv)) {
struct buffer iv_buffer;
buf_set_write(&iv_buffer, tmp2, strlen(tmp2));
packet_id_write(&pidsend, &iv_buffer, false, false);
packet_id_write(&pidsend, &iv_buffer, false, true);
packet_id_write(&pidsend, &iv_buffer, true, true);
packet_id_write(&pidsend, &iv_buffer, true, false);
}
}
free(tmp2);
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);
//p.time = NULL;
struct timeval tv;
tv.tv_sec = p.time;
tv.tv_usec = 0;
if (localtime(&tv) != NULL) {
gc = gc_new();
p.id_last_written = fuzz_randomizer_get_int(0, 0xfffffff);
//packet_id_persist_print(&p, &gc);
packet_id_persist_save(&p);
gc_free(&gc);
}
packet_id_persist_close(&p);
fuzz_random_destroy();
return 0;
}

144
fuzz/fuzz_proxy.c Normal file
View file

@ -0,0 +1,144 @@
/* 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 <sys/time.h>
#include "syshead.h"
#include "interval.h"
#include "proxy.h"
#include <openssl/err.h>
#include <openssl/ssl.h>
#include "sig.h"
#include "fuzz_randomizer.h"
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
OPENSSL_malloc_init();
SSL_library_init();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OpenSSL_add_ssl_algorithms();
OpenSSL_add_all_digests();
SSL_load_error_strings();
return 1;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
char *tmp = NULL;
char *tmp2 = NULL;
if (size < 500) {
return 0;
}
fuzz_random_init(data, size);
struct gc_arena gc = gc_new();
struct http_proxy_info pi;
ssize_t generic_ssizet;
struct signal_info signal_received = {0};
// TODO: This coul be randomized
register_signal(&signal_received, SIGUSR1, "remote-exit");
struct buffer lookahead = alloc_buf(1024);
struct event_timeout evt;
memset(&evt, 0, sizeof(struct event_timeout));
memset(&pi, 0, sizeof(struct http_proxy_info));
memset(&pi, 0, sizeof(pi));
generic_ssizet = 0;
char *fuzz_usrnm = fuzz_random_get_string_max_length(USER_PASS_LEN);
strcpy(pi.up.username, fuzz_usrnm);
if (strlen(pi.up.username) == 0) {
gc_free(&gc);
free_buf(&lookahead);
free(fuzz_usrnm);
fuzz_random_destroy();
return 0;
}
char *pswd = fuzz_random_get_string_max_length(USER_PASS_LEN);
strcpy(pi.up.password, pswd);
if (strlen(pi.up.password) == 0) {
gc_free(&gc);
free_buf(&lookahead);
free(pswd);
free(fuzz_usrnm);
fuzz_random_destroy();
return 0;
}
generic_ssizet = fuzz_randomizer_get_int(0, 3);
switch (generic_ssizet) {
case 0:
pi.auth_method = HTTP_AUTH_NONE;
break;
case 1:
pi.auth_method = HTTP_AUTH_BASIC;
break;
case 2:
pi.auth_method = HTTP_AUTH_DIGEST;
break;
case 3:
pi.auth_method = HTTP_AUTH_NTLM2;
break;
}
pi.options.http_version = "1.1";
generic_ssizet = fuzz_randomizer_get_int(0, 2);
switch (generic_ssizet) {
case 0:
pi.options.auth_retry = PAR_NO;
break;
case 1:
pi.options.auth_retry = PAR_ALL;
break;
case 2:
pi.options.auth_retry = PAR_NCT;
break;
}
char *tmp_authenticate = get_random_string();
pi.proxy_authenticate = tmp_authenticate;
//if (provider.ConsumeProbability<double>() < 0.5) {
//tmp = get_modifiable_string(provider);
tmp = get_random_string();
pi.options.custom_headers[0].name = tmp;
//if (provider.ConsumeProbability<double>() < 0.5) {
//tmp2 = get_modifiable_string(provider);
tmp2 = get_random_string();
pi.options.custom_headers[0].content = tmp2;
//}
//}
establish_http_proxy_passthru(&pi, 0, "1.2.3.4", "777", &evt, &lookahead,
&signal_received);
free(pi.proxy_authenticate);
gc_free(&gc);
free_buf(&lookahead);
if (tmp != NULL) free(tmp);
if (tmp2 != NULL) free(tmp2);
free(pswd);
free(fuzz_usrnm);
fuzz_random_destroy();
return 0;
}

107
fuzz/fuzz_randomizer.cpp Normal file
View file

@ -0,0 +1,107 @@
/* 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 <fuzzer/FuzzedDataProvider.h>
#include <assert.h>
FuzzedDataProvider *prov = NULL;
extern "C" void fuzz_random_init(const uint8_t *data, size_t size) {
assert(prov == NULL);
prov = new FuzzedDataProvider(data, size);
}
extern "C" void fuzz_random_destroy() {
assert(prov != NULL);
delete prov;
prov = NULL;
}
extern "C" char *get_random_string() {
assert(prov != NULL);
std::string s1 = prov->ConsumeRandomLengthString();
char *tmp = (char *)malloc(s1.size() + 1);
memcpy(tmp, s1.c_str(), s1.size());
tmp[s1.size()] = '\0';
return tmp;
}
extern "C" int fuzz_randomizer_get_int(int min, int max) {
assert(prov != NULL);
return prov->ConsumeIntegralInRange<int>(min, max);
}
extern "C" char *fuzz_random_get_string_max_length(int max_len) {
assert(prov != NULL);
std::string s1 = prov->ConsumeBytesAsString(
prov->ConsumeIntegralInRange<uint32_t>(1, max_len));
char *tmp123 = (char*)malloc(s1.size()+1);
memcpy(tmp123, s1.c_str(), s1.size());
tmp123[s1.size()] = '\0';
return tmp123;
}
extern "C" size_t fuzz_get_random_data(void *buf, size_t len) {
assert(prov != NULL);
size_t ret_val;
char *cbuf = (char*)buf;
if (prov->remaining_bytes() == 0) {
return -1;
}
double prob = prov->ConsumeProbability<double>();
if (prob < 0.05) {
return 0;
}
//if (len == 1) {
// ret_val = prov->ConsumeData(buf, 1);
// return ret_val;
//}
ret_val = prov->ConsumeData(buf, len);
return ret_val;
}
// Simple garbage collector
#define GB_SIZE 100
void *pointer_arr[GB_SIZE];
static int pointer_idx = 0;
// If the garbage collector is used then this must be called as first thing
// during a fuzz run.
extern "C" void gb_init() {
pointer_idx = 0;
for (int i = 0; i < GB_SIZE; i++) {
pointer_arr[i] = NULL;
}
}
extern "C" void gb_cleanup() {
for(int i = 0; i < GB_SIZE; i++) {
if (pointer_arr[i] != NULL) {
free(pointer_arr[i]);
}
}
}
extern "C" char *gb_get_random_string() {
char *tmp = get_random_string();
pointer_arr[pointer_idx++] = (void*)tmp;
return tmp;
}

27
fuzz/fuzz_randomizer.h Normal file
View file

@ -0,0 +1,27 @@
/* 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 <stdio.h>
#include <stdint.h>
void fuzz_random_init(const uint8_t *data, size_t size);
void fuzz_random_destroy();
char *get_random_string();
int fuzz_randomizer_get_int(int min, int max);
size_t fuzz_get_random_data(void *buf, size_t len);
char *fuzz_random_get_string_max_length(int max_len);
void gb_init();
void gb_cleanup();
char *gb_get_random_string();
int fuzz_success;

207
fuzz/fuzz_route.c Normal file
View file

@ -0,0 +1,207 @@
/* 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 "proxy.h"
#include "interval.h"
#include "route.h"
#include "buffer.h"
#include "fuzz_randomizer.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fuzz_random_init(data, size);
gb_init();
struct route_option_list *opt;
struct route_list rl;
int route_list_inited = 0;
int route_list_ipv6_inited = 0;
struct context c;
memset(&c, 0, sizeof(struct context));
gc_init(&c.gc);
c.es = env_set_create(&c.gc);
init_options(&c.options, true);
net_ctx_init(&c, &c.net_ctx);
init_verb_mute(&c, IVM_LEVEL_1);
init_options_dev(&c.options);
// options_postprocess(&c.options);
pre_setup(&c.options);
setenv_settings(c.es, &c.options);
ALLOC_OBJ_CLEAR_GC(c.options.ce.local_list, struct local_list, &c.options.gc);
ALLOC_OBJ_CLEAR_GC(c.options.connection_list, struct connection_list,
&c.options.gc);
context_init_1(&c);
in_addr_t remote_host;
ssize_t default_metric;
struct route_ipv6_list rl6;
struct route_ipv6_option_list *opt6;
memset(&rl, 0, sizeof(rl));
memset(&rl6, 0, sizeof(rl6));
memset(&opt, 0, sizeof(opt));
memset(&opt6, 0, sizeof(opt6));
opt6 = new_route_ipv6_option_list(&c.gc);
opt = new_route_option_list(&c.gc);
int total_to_fuzz = fuzz_randomizer_get_int(1, 20);
for (int i = 0; i < total_to_fuzz; i++) {
int selector = fuzz_randomizer_get_int(0, 13);
switch (selector) {
case 0:
if (route_list_inited == 0) {
const char *remote_endpoint = gb_get_random_string();
memset(&rl, 0, sizeof(struct route_list));
rl.flags = fuzz_randomizer_get_int(0, 0xffffff);
init_route_list(&rl, opt, remote_endpoint, default_metric, remote_host,
c.es, &c);
route_list_inited = 1;
}
break;
case 1:
if (route_list_inited) {
in_addr_t addr;
route_list_add_vpn_gateway(&rl, c.es, addr);
}
break;
case 2:
if (route_list_inited && route_list_ipv6_inited) {
struct tuntap tt;
memset(&tt, 0, sizeof(tt));
add_routes(&rl, &rl6, &tt, 0, c.es, &c);
}
break;
case 3:
if (route_list_inited) {
setenv_routes(c.es, &rl);
}
break;
case 4:
if (route_list_inited) {
struct route_ipv4 r;
struct route_option ro;
ro.network = gb_get_random_string();
ro.netmask = gb_get_random_string();
ro.gateway = gb_get_random_string();
ro.metric = gb_get_random_string();
ro.next = NULL;
memset(&r, 0, sizeof(struct route_ipv4));
r.option = &ro;
r.flags = RT_DEFINED;
add_route(&r, NULL, 0, NULL, c.es, &c);
}
break;
case 5:
if (route_list_inited) {
char *s1 = get_random_string();
is_special_addr(s1);
free(s1);
}
break;
case 6:
if (route_list_ipv6_inited == 0) {
const char *remote_endpoint = gb_get_random_string();
memset(&rl, 0, sizeof(struct route_list));
struct in6_addr remote_host;
rl6.rgi6.flags = fuzz_randomizer_get_int(0, 0xffffff);
fuzz_get_random_data(&rl6.rgi6.hwaddr, 6);
char *t1 = gb_get_random_string();
if (strlen(t1) > 16) {
memcpy(rl6.rgi6.iface, t1, 16);
} else {
memcpy(rl6.rgi6.iface, t1, strlen(t1));
}
init_route_ipv6_list(&rl6, opt6, remote_endpoint, 0, &remote_host, c.es,
&c);
route_list_ipv6_inited = 1;
}
break;
case 7: {
unsigned int flags;
struct route_ipv6 r6;
struct tuntap tt;
memset(&tt, 0, sizeof(tt));
tt.actual_name = gb_get_random_string();
r6.iface = gb_get_random_string();
r6.flags = fuzz_randomizer_get_int(0, 0xfffff);
r6.netbits = fuzz_randomizer_get_int(0, 0xfffff);
r6.metric = fuzz_randomizer_get_int(0, 0xfffff);
r6.next = NULL;
add_route_ipv6(&r6, &tt, 0, c.es, &c);
} break;
case 8:
if (route_list_ipv6_inited && route_list_inited) {
delete_routes(&rl, &rl6, NULL, 0, c.es, &c);
route_list_ipv6_inited = 0;
route_list_inited = 0;
}
break;
case 9:
if (route_list_ipv6_inited) {
setenv_routes_ipv6(c.es, &rl6);
}
break;
case 10: {
add_route_ipv6_to_option_list(opt6,
gb_get_random_string(),
gb_get_random_string(),
gb_get_random_string(),
fuzz_randomizer_get_int(0, 100));
} break;
case 11: {
print_route_options(opt, M_NONFATAL);
} break;
case 12: {
add_route_to_option_list(opt,
gb_get_random_string(),
gb_get_random_string(),
gb_get_random_string(),
gb_get_random_string(),
fuzz_randomizer_get_int(0, 100));
} break;
default:
break;
}
}
if (route_list_inited) {
gc_free(&rl.gc);
}
env_set_destroy(c.es);
context_gc_free(&c);
fuzz_random_destroy();
gb_cleanup();
return 0;
}

167
fuzz/fuzz_verify_cert.c Normal file
View file

@ -0,0 +1,167 @@
/* 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 <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "fuzz_verify_cert.h"
#include "misc.h"
#include "manage.h"
#include "otime.h"
#include "base64.h"
#include "ssl_verify.h"
#include "ssl_verify_backend.h"
#include "fuzz_randomizer.h"
static int parse_x509(const uint8_t *data, size_t size, X509 **out) {
*out = d2i_X509(NULL, (const unsigned char **)&data, size);
if (*out == NULL) {
return -1;
}
return 0;
}
int LLVMFuzzerInitialize(int *argc, char ***argv) {
OPENSSL_malloc_init();
SSL_library_init();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
return 1;
}
static int init_session_opt(struct tls_options **_opt, struct gc_arena *gc) {
ssize_t nid;
ssize_t generic_ssizet;
struct tls_options *opt;
int r;
ALLOC_OBJ_GC(*_opt, struct tls_options, gc);
if (opt == NULL) {
return -1;
}
opt = *_opt;
memset(opt, 0xFE, sizeof(struct tls_options));
opt->es = env_set_create(gc);
opt->x509_username_field[0] = NULL;
opt->remote_cert_eku = NULL;
/* Prevents failure if x509 sha1 hashes do not match */
opt->verify_hash = NULL;
/* Prevent attempt to run --tls-verify script */
opt->verify_command = NULL;
/* Do not verify against CRL file */
opt->crl_file = NULL;
/* Do not run --tls-verify plugins */
opt->plugins = NULL;
r = fuzz_randomizer_get_int(0, 1);
if (r == 0) {
opt->x509_username_field[0] = nidstrs[fuzz_randomizer_get_int(0, (sizeof(nidstrs)/sizeof(nidstrs[0])) - 1)];
}
else {
opt->x509_username_field[0] = "ext:subjectAltName";
}
opt->x509_username_field[1] = NULL;
r = fuzz_randomizer_get_int(0, 2);
if (r == 0)
opt->ns_cert_type = NS_CERT_CHECK_CLIENT;
else if (r == 1)
opt->ns_cert_type = NS_CERT_CHECK_SERVER;
else
opt->ns_cert_type = NS_CERT_CHECK_NONE;
opt->x509_track = NULL;
r = fuzz_randomizer_get_int(0, 1);
if (r == 0)
opt->remote_cert_eku = NULL;
else
opt->remote_cert_eku = get_random_string();
return 0;
}
static int init_session(struct tls_session **_session, struct gc_arena *gc) {
struct tls_session *session;
ALLOC_OBJ_GC(*_session, struct tls_session, gc);
if (*_session == NULL) {
return -1;
}
session = *_session;
memset(session, 0xFE, sizeof(struct tls_session));
/* Accessed in set_common_name() */
session->common_name = get_random_string();;
/* Initialize the session->opt structure */
if (init_session_opt(&(session->opt), gc) == -1) {
free(session->common_name);
return -1;
}
/* Accessed in server_untrusted() */
session->untrusted_addr.dest.addr.sa.sa_family = AF_UNSPEC;
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fuzz_random_init(data, size);
struct gc_arena gc;
struct tls_session *session = NULL;
X509 *x509 = NULL;
gc = gc_new();
if (parse_x509(data, size, &x509) == 0) {
if (init_session(&session, &gc) == 0) {
verify_cert(session, x509, 100);
if (session->opt->remote_cert_eku != NULL) {
free(session->opt->remote_cert_eku);
}
free(session->common_name);
}
}
X509_free(x509);
gc_free(&gc);
fuzz_random_destroy();
return 0;
}

1065
fuzz/fuzz_verify_cert.h Normal file

File diff suppressed because it is too large Load diff