diff --git a/projects/apache-httpd/Dockerfile b/projects/apache-httpd/Dockerfile index bb6a63ee9..e1d46896d 100644 --- a/projects/apache-httpd/Dockerfile +++ b/projects/apache-httpd/Dockerfile @@ -17,6 +17,9 @@ FROM gcr.io/oss-fuzz-base/base-builder RUN apt-get update && apt-get install -y make autoconf automake libtool wget libpcre3 \ libpcre3-dev uuid-dev pkg-config libtool-bin + +RUN git clone https://github.com/AdaLogics/fuzz-headers + RUN wget https://github.com/libexpat/libexpat/releases/download/R_2_4_1/expat-2.4.1.tar.gz && \ tar -xf expat-2.4.1.tar.gz && \ cd expat-2.4.1 && \ diff --git a/projects/apache-httpd/build.sh b/projects/apache-httpd/build.sh index a1383577b..eed379dbd 100755 --- a/projects/apache-httpd/build.sh +++ b/projects/apache-httpd/build.sh @@ -27,8 +27,10 @@ svn checkout https://svn.apache.org/repos/asf/apr/apr/trunk/ srclib/apr make # Build the fuzzers -for fuzzname in utils parse tokenize addr_parse; do - $CC $CFLAGS $LIB_FUZZING_ENGINE -I./include -I./os/unix -I./srclib/apr/include -I./srclib/apr-util/include/ \ +for fuzzname in utils parse tokenize addr_parse uri; do + $CC $CFLAGS $LIB_FUZZING_ENGINE \ + -I$SRC/fuzz-headers/lang/c -I./include -I./os/unix \ + -I./srclib/apr/include -I./srclib/apr-util/include/ \ $SRC/fuzz_${fuzzname}.c -o $OUT/fuzz_${fuzzname} \ ./modules.o buildmark.o \ -Wl,--start-group ./server/.libs/libmain.a \ diff --git a/projects/apache-httpd/fuzz_uri.c b/projects/apache-httpd/fuzz_uri.c new file mode 100644 index 000000000..789b96f05 --- /dev/null +++ b/projects/apache-httpd/fuzz_uri.c @@ -0,0 +1,65 @@ +/* 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 "apr.h" +#include "apr_file_io.h" +#include "apr_poll.h" +#include "apr_portable.h" +#include "apr_proc_mutex.h" +#include "apr_signal.h" +#include "apr_strings.h" +#include "apr_thread_mutex.h" +#include "apr_thread_proc.h" + +#define APR_WANT_STRFUNC +#include "apr_file_io.h" +#include "apr_fnmatch.h" +#include "apr_want.h" + +#include "apr_poll.h" +#include "apr_want.h" + +#include "apr_uri.h" + +#include "ap_config.h" +#include "ap_expr.h" +#include "ap_listen.h" +#include "ap_provider.h" +#include "ap_regex.h" + +#include "ada_fuzz_header.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + af_gb_init(); + const uint8_t *data2 = data; + size_t size2 = size; + + // Get a NULL terminated string + char *cstr = af_gb_get_null_terminated(&data2, &size2); + + // Fuzz URI routines + if (cstr && apr_pool_initialize() == APR_SUCCESS) { + apr_pool_t *pool = NULL; + apr_pool_create(&pool, NULL); + + apr_uri_t tmp_uri; + if (apr_uri_parse(pool, cstr, &tmp_uri) == APR_SUCCESS) { + apr_uri_unparse(pool, &tmp_uri, 0); + } + apr_uri_parse_hostinfo(pool, cstr, &tmp_uri); + + // Cleanup + apr_pool_terminate(); + } + + af_gb_cleanup(); + return 0; +} diff --git a/projects/apache-httpd/fuzz_utils.c b/projects/apache-httpd/fuzz_utils.c index 1ced86fe5..577c1cf90 100644 --- a/projects/apache-httpd/fuzz_utils.c +++ b/projects/apache-httpd/fuzz_utils.c @@ -33,99 +33,148 @@ limitations under the License. #include "ap_provider.h" #include "ap_regex.h" +#include "ada_fuzz_header.h" + + int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - char *new_str = (char *)malloc(size + 1); - if (new_str == NULL) { - return 0; - } - memcpy(new_str, data, size); - new_str[size] = '\0'; + // Initialize fuzzing garbage collector. We use this to easily + // get data types seeded with random input from the fuzzer. + af_gb_init(); - // Targets that do not require a pool - ap_cstr_casecmp(new_str, new_str); - ap_getparents(new_str); - ap_unescape_url(new_str); - ap_unescape_urlencoded(new_str); - ap_strcmp_match(new_str, "AAAAAABDKJSAD"); + const uint8_t *data2 = data; + size_t size2 = size; - // Pool initialisation - if (apr_pool_initialize() == APR_SUCCESS) { - apr_pool_t *pool = NULL; - apr_pool_create(&pool, NULL); + char *new_str = af_gb_get_null_terminated(&data2, &size2); + char *new_dst = af_gb_get_null_terminated(&data2, &size2); + if (new_str != NULL && new_dst != NULL) { - // Targets that require a pool - ap_field_noparam(pool, new_str); + // Targets that do not require a pool + ap_cstr_casecmp(new_str, new_str); + ap_getparents(new_str); + ap_unescape_url(new_str); + ap_unescape_urlencoded(new_str); + ap_strcmp_match(new_str, new_dst); - ap_escape_shell_cmd(pool, new_str); - ap_os_escape_path(pool, new_str, 0); - ap_escape_html2(pool, new_str, 0); - ap_escape_logitem(pool, new_str); - - // This line causes some issues if something bad is allocated - ap_escape_quotes(pool, new_str); - - if (size > 2) { - ap_cstr_casecmpn(new_str, new_str + 2, size - 2); + char *ns3 = af_gb_get_null_terminated(&data2, &size2); + if (ns3 != NULL) { + ap_no2slash(ns3); + } + char *ns10 = af_gb_get_null_terminated(&data2, &size2); + char *ns11 = af_gb_get_null_terminated(&data2, &size2); + if (ns10 != NULL && ns11 != NULL) { + ap_escape_path_segment_buffer(ns10, ns11); } - char *d = malloc(size * 2); - ap_escape_errorlog_item(d, new_str, size * 2); - free(d); + // Pool initialisation + if (apr_pool_initialize() == APR_SUCCESS) { + apr_pool_t *pool = NULL; + apr_pool_create(&pool, NULL); - // base64 - char *decoded = NULL; - decoded = ap_pbase64decode(pool, new_str); - ap_pbase64encode(pool, new_str); + // Targets that require a pool + ns3 = af_gb_get_null_terminated(&data2, &size2); + if (ns3 != NULL) { + ap_make_dirstr_parent(pool, ns3); + } - char *tmp_s = new_str; - ap_getword_conf2(pool, &tmp_s); + ap_field_noparam(pool, new_str); - // str functions - ap_strcasecmp_match(tmp_s, "asdfkj"); - ap_strcasestr(tmp_s, "AAAAAAAAAAAAAA"); - ap_strcasestr(tmp_s, "AasdfasbA"); - ap_strcasestr(tmp_s, "1341234"); - ap_strcasestr("AAAAAAAAAAAAAA", tmp_s); - ap_strcasestr("AasdfasbA", tmp_s); - ap_strcasestr("1341234", tmp_s); + ap_escape_shell_cmd(pool, new_str); + ap_os_escape_path(pool, new_str, 0); + ap_escape_html2(pool, new_str, 0); + ap_escape_logitem(pool, new_str); - // List functions - tmp_s = new_str; - ap_get_list_item(pool, &tmp_s); - tmp_s = new_str; - ap_find_list_item(pool, &tmp_s, "kjahsdfkj"); - ap_find_token(pool, tmp_s, "klsjdfk"); - ap_find_last_token(pool, tmp_s, "sdadf"); - ap_is_chunked(pool, tmp_s); + // This line causes some issues if something bad is allocated + ap_escape_quotes(pool, new_str); - apr_array_header_t *offers = NULL; - ap_parse_token_list_strict(pool, new_str, &offers, 0); + if (size > 2) { + ap_cstr_casecmpn(new_str, new_str + 2, size - 2); + } - char *tmp_null = NULL; - ap_pstr2_alnum(pool, new_str, &tmp_null); + char *d = malloc(size * 2); + ap_escape_errorlog_item(d, new_str, size * 2); + free(d); - // Word functions - tmp_s = new_str; - ap_getword(pool, &tmp_s, 0); + // base64 + char *decoded = NULL; + decoded = ap_pbase64decode(pool, new_str); + ap_pbase64encode(pool, new_str); - tmp_s = new_str; - ap_getword_white_nc(pool, &tmp_s); + char *ns12 = af_gb_get_null_terminated(&data2, &size2); + if (ns12 != NULL) { + char *d; + apr_size_t dlen; + ap_pbase64decode_strict(pool, ns12, &d, &dlen); + } - tmp_s = new_str; - ap_get_token(pool, &tmp_s, 1); + char *tmp_s = new_str; + ap_getword_conf2(pool, &tmp_s); - tmp_s = new_str; - ap_escape_urlencoded(pool, tmp_s); + // str functions + ap_strcasecmp_match(tmp_s, new_dst); + ap_strcasestr(tmp_s, new_dst); - apr_interval_time_t timeout; - ap_timeout_parameter_parse(new_str, &timeout, "ms"); + // List functions + tmp_s = new_str; + ap_get_list_item(pool, &tmp_s); + tmp_s = new_str; + ap_find_list_item(pool, &tmp_s, "kjahsdfkj"); + ap_find_token(pool, tmp_s, "klsjdfk"); + ap_find_last_token(pool, tmp_s, "sdadf"); + ap_is_chunked(pool, tmp_s); - tmp_s = new_str; - ap_content_type_tolower(tmp_s); + apr_array_header_t *offers = NULL; + ap_parse_token_list_strict(pool, new_str, &offers, 0); - // Cleanup - apr_pool_terminate(); + char *tmp_null = NULL; + ap_pstr2_alnum(pool, new_str, &tmp_null); + + // Word functions + tmp_s = new_str; + ap_getword(pool, &tmp_s, 0); + + tmp_s = new_str; + ap_getword_white_nc(pool, &tmp_s); + + tmp_s = new_str; + ap_get_token(pool, &tmp_s, 1); + + tmp_s = new_str; + ap_escape_urlencoded(pool, tmp_s); + + apr_interval_time_t timeout; + ap_timeout_parameter_parse(new_str, &timeout, "ms"); + + tmp_s = new_str; + ap_content_type_tolower(tmp_s); + + + char filename[256]; + sprintf(filename, "/tmp/libfuzzer.%d", getpid()); + FILE *fp = fopen(filename, "wb"); + fwrite(data, size, 1, fp); + fclose(fp); + + // Fuzzer logic here + ap_configfile_t *cfg; + ap_pcfg_openfile(&cfg, pool, filename); + char tmp_line[100]; + if ((af_get_short(&data2, &size2) % 2) == 0) { + ap_cfg_getline(tmp_line, 100, cfg); + } + else { + cfg->getstr = NULL; + ap_cfg_getline(tmp_line, 100, cfg); + } + // Fuzzer logic end + + unlink(filename); + + // Cleanup + apr_pool_terminate(); + } } - free(new_str); + + // Cleanup all of the memory allocated by the fuzz headers. + af_gb_cleanup(); return 0; }