diff --git a/tools/oss-fuzzshark/build.sh b/tools/oss-fuzzshark/build.sh new file mode 100755 index 0000000000..6164cd3141 --- /dev/null +++ b/tools/oss-fuzzshark/build.sh @@ -0,0 +1,78 @@ +#!/bin/bash -eux +# Copyright 2017 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +FUZZ_DISSECTORS="ip" + +FUZZ_IP_PROTO_DISSECTORS="udp ospf" + +FUZZ_TCP_PORT_DISSECTORS="bgp" +# FUZZ_TCP_PORT_DISSECTORS="$FUZZ_TCP_PORT_DISSECTORS bzr" # disabled, cause of known problem. +# FUZZ_TCP_PORT_DISSECTORS="$FUZZ_TCP_PORT_DISSECTORS echo" # disabled, too simple. + +FUZZ_UDP_PORT_DISSECTORS="dns bootp" +# FUZZ_UDP_PORT_DISSECTORS="$FUZZ_UDP_PORT_DISSECTORS bfd" # disabled, too simple. + +FUZZ_MEDIA_TYPE_DISSECTORS="json" + +# TODO: support specifing targets in args. Google oss-fuzz specifies 'all'. + +# generate_fuzzer +generate_fuzzer() +{ + local fuzzer_target="$1" fuzzer_cflags="$2" fuzzer_name + + fuzzer_name="fuzzshark_$1" + + # -I$SRC/wireshark is correct, wireshark don't install header files. + $CC $CFLAGS -I $SRC/wireshark/ `pkg-config --cflags glib-2.0` \ + $SRC/wireshark/tools/oss-fuzzshark/fuzzshark.c \ + -c -o $WORK/${fuzzer_name}.o \ + $fuzzer_cflags + + $CXX $CXXFLAGS $WORK/${fuzzer_name}.o \ + -o $OUT/${fuzzer_name} \ + ${WIRESHARK_FUZZERS_COMMON_FLAGS} + + echo -en "[libfuzzer]\nmax_len = 1024\n" > $OUT/${fuzzer_name}.options + if [ -d "$SAMPLES_DIR/${fuzzer_target}" ]; then + zip -j $OUT/${fuzzer_name}_seed_corpus.zip $SAMPLES_DIR/${fuzzer_target}/*/*.bin + fi +} + +WIRESHARK_FUZZERS_COMMON_FLAGS="-lFuzzingEngine \ + -L"$WIRESHARK_INSTALL_PATH/lib" -lwireshark -lwiretap -lwsutil \ + -Wl,-Bstatic `pkg-config --libs glib-2.0` -pthread -lpcre -lgcrypt -lgpg-error -lz -Wl,-Bdynamic" + +for dissector in $FUZZ_DISSECTORS; do + generate_fuzzer "${dissector}" -DFUZZ_DISSECTOR_TARGET=\"$dissector\" +done + +for dissector in $FUZZ_IP_PROTO_DISSECTORS; do + generate_fuzzer "ip_proto-${dissector}" "-DFUZZ_DISSECTOR_TABLE=\"ip.proto\" -DFUZZ_DISSECTOR_TARGET=\"$dissector\"" +done + +for dissector in $FUZZ_TCP_PORT_DISSECTORS; do + generate_fuzzer "tcp_port-${dissector}" "-DFUZZ_DISSECTOR_TABLE=\"tcp.port\" -DFUZZ_DISSECTOR_TARGET=\"$dissector\"" +done + +for dissector in $FUZZ_UDP_PORT_DISSECTORS; do + generate_fuzzer "udp_port-${dissector}" "-DFUZZ_DISSECTOR_TABLE=\"udp.port\" -DFUZZ_DISSECTOR_TARGET=\"$dissector\"" +done + +for dissector in $FUZZ_MEDIA_TYPE_DISSECTORS; do + generate_fuzzer "media_type-${dissector}" "-DFUZZ_DISSECTOR_TABLE=\"media_type\" -DFUZZ_DISSECTOR_TARGET=\"$dissector\"" +done diff --git a/tools/oss-fuzzshark/fuzzshark.c b/tools/oss-fuzzshark/fuzzshark.c new file mode 100644 index 0000000000..6c77e28b1d --- /dev/null +++ b/tools/oss-fuzzshark/fuzzshark.c @@ -0,0 +1,330 @@ +/* oss-fuzzshark.c + * + * Fuzzer variant of Wireshark for oss-fuzz + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef HAVE_PLUGINS +#include +#endif + +#define EPAN_INIT_FAIL 2 + +static column_info fuzz_cinfo; +static epan_t *fuzz_epan; +static epan_dissect_t *fuzz_edt; + +/* + * General errors and warnings are reported with an console message + * in oss-fuzzshark. + */ +static void +failure_warning_message(const char *msg_format, va_list ap) +{ + fprintf(stderr, "oss-fuzzshark: "); + vfprintf(stderr, msg_format, ap); + fprintf(stderr, "\n"); +} + +/* + * Open/create errors are reported with an console message in oss-fuzzshark. + */ +static void +open_failure_message(const char *filename, int err, gboolean for_writing) +{ + fprintf(stderr, "oss-fuzzshark: "); + fprintf(stderr, file_open_error_message(err, for_writing), filename); + fprintf(stderr, "\n"); +} + +/* + * Read errors are reported with an console message in oss-fuzzshark. + */ +static void +read_failure_message(const char *filename, int err) +{ + cmdarg_err("An error occurred while reading from the file \"%s\": %s.", filename, g_strerror(err)); +} + +/* + * Write errors are reported with an console message in oss-fuzzshark. + */ +static void +write_failure_message(const char *filename, int err) +{ + cmdarg_err("An error occurred while writing to the file \"%s\": %s.", filename, g_strerror(err)); +} + +/* + * Report additional information for an error in command-line arguments. + */ +static void +failure_message_cont(const char *msg_format, va_list ap) +{ + vfprintf(stderr, msg_format, ap); + fprintf(stderr, "\n"); +} + +static const nstime_t * +fuzzshark_get_frame_ts(void *data _U_, guint32 frame_num _U_) +{ + static nstime_t empty; + + return ∅ +} + +static epan_t * +fuzzshark_epan_new(void) +{ + epan_t *epan = epan_new(); + + epan->get_frame_ts = fuzzshark_get_frame_ts; + epan->get_interface_name = NULL; + epan->get_interface_description = NULL; + epan->get_user_comment = NULL; + + return epan; +} + +static int +fuzz_init(int argc _U_, char **argv) +{ + GString *comp_info_str; + GString *runtime_info_str; + char *init_progfile_dir_error; + + char *err_msg = NULL; + e_prefs *prefs_p; + int ret = EXIT_SUCCESS; + +#if defined(FUZZ_DISSECTOR_TARGET) + dissector_handle_t fuzz_handle = NULL; +#endif + + cmdarg_err_init(failure_warning_message, failure_message_cont); + + /* + * Get credential information for later use, and drop privileges + * before doing anything else. + * Let the user know if anything happened. + */ + init_process_policies(); +#if 0 /* disable setresgid(), it fails with -EINVAL https://github.com/google/oss-fuzz/pull/532#issuecomment-294515463 */ + relinquish_special_privs_perm(); +#endif + + /* + * Attempt to get the pathname of the executable file. + */ + init_progfile_dir_error = init_progfile_dir(argv[0], fuzz_init); + if (init_progfile_dir_error != NULL) + fprintf(stderr, "fuzzshark: Can't get pathname of oss-fuzzshark program: %s.\n", init_progfile_dir_error); + + /* Get the compile-time version information string */ + comp_info_str = get_compiled_version_info(NULL, epan_get_compiled_version_info); + + /* Get the run-time version information string */ + runtime_info_str = get_runtime_version_info(epan_get_runtime_version_info); + + /* Add it to the information to be reported on a crash. */ + ws_add_crash_info("OSS Fuzzshark (Wireshark) %s\n" + "\n" + "%s" + "\n" + "%s", + get_ws_vcs_version_info(), + comp_info_str->str, + runtime_info_str->str); + g_string_free(comp_info_str, TRUE); + g_string_free(runtime_info_str, TRUE); + + init_report_message(failure_warning_message, failure_warning_message, + open_failure_message, read_failure_message, write_failure_message); + + timestamp_set_type(TS_RELATIVE); + timestamp_set_precision(TS_PREC_AUTO); + timestamp_set_seconds_type(TS_SECONDS_DEFAULT); + + wtap_init(); + +#ifdef HAVE_PLUGINS + /* Register all the plugin types we have. */ + epan_register_plugin_types(); /* Types known to libwireshark */ + + /* Scan for plugins. This does *not* call their registration routines; that's done later. */ + scan_plugins(REPORT_LOAD_FAILURE); + + /* Register all libwiretap plugin modules. */ + register_all_wiretap_modules(); +#endif + + /* Register all dissectors; we must do this before checking for the + "-G" flag, as the "-G" flag dumps information registered by the + dissectors, and we must do it before we read the preferences, in + case any dissectors register preferences. */ + if (!epan_init(register_all_protocols, register_all_protocol_handoffs, NULL, NULL)) + { + ret = EPAN_INIT_FAIL; + goto clean_exit; + } + + /* Load libwireshark settings from the current profile. */ + prefs_p = epan_load_settings(); + + if (!color_filters_init(&err_msg, NULL)) + { + fprintf(stderr, "color_filters_init() failed %s\n", err_msg); + g_free(err_msg); + } + + /* Notify all registered modules that have had any of their preferences + changed either from one of the preferences file or from the command + line that their preferences have changed. */ + prefs_apply_all(); + + /* Build the column format array */ + build_column_format_array(&fuzz_cinfo, prefs_p->num_cols, TRUE); + +#if defined(FUZZ_DISSECTOR_TABLE) && defined(FUZZ_DISSECTOR_TARGET) +# define FUZZ_EPAN 1 + fprintf(stderr, "oss-fuzzshark: configured for dissector: %s in table: %s\n", FUZZ_DISSECTOR_TARGET, FUZZ_DISSECTOR_TABLE); + + /* search for handle, cannot use dissector_table_get_dissector_handle() cause it's using short-name, and I already used filter name in samples ;/ */ + { + GSList *handle_list = dissector_table_get_dissector_handles(find_dissector_table(FUZZ_DISSECTOR_TABLE)); + while (handle_list) + { + dissector_handle_t handle = (dissector_handle_t) handle_list->data; + const char *handle_filter_name = proto_get_protocol_filter_name(dissector_handle_get_protocol_index(handle)); + + if (!strcmp(handle_filter_name, FUZZ_DISSECTOR_TARGET)) + fuzz_handle = handle; + handle_list = handle_list->next; + } + } + +#elif defined(FUZZ_DISSECTOR_TARGET) +# define FUZZ_EPAN 2 + fprintf(stderr, "oss-fuzzshark: configured for dissector: %s\n", FUZZ_DISSECTOR_TARGET); + fuzz_handle = find_dissector(FUZZ_DISSECTOR_TARGET); +#endif + +#ifdef FUZZ_EPAN + g_assert(fuzz_handle != NULL); + register_postdissector(fuzz_handle); +#endif + + fuzz_epan = fuzzshark_epan_new(); + fuzz_edt = epan_dissect_new(fuzz_epan, TRUE, FALSE); + + return 0; +clean_exit: + wtap_cleanup(); + free_progdirs(); +#ifdef HAVE_PLUGINS + plugins_cleanup(); +#endif + return ret; +} + +#ifdef FUZZ_EPAN +int +LLVMFuzzerTestOneInput(guint8 *buf, size_t real_len) +{ + static guint32 framenum = 0; + epan_dissect_t *edt = fuzz_edt; + + guint32 len = (guint32) real_len; + + struct wtap_pkthdr whdr; + frame_data fdlocal; + + memset(&whdr, 0, sizeof(whdr)); + + whdr.rec_type = REC_TYPE_PACKET; + whdr.caplen = len; + whdr.len = len; + + /* whdr.pkt_encap = WTAP_ENCAP_ETHERNET; */ + whdr.pkt_encap = G_MAXINT16; + whdr.presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN; /* most common flags... */ + + frame_data_init(&fdlocal, ++framenum, &whdr, /* offset */ 0, /* cum_bytes */ 0); + /* frame_data_set_before_dissect() not needed */ + epan_dissect_run(edt, WTAP_FILE_TYPE_SUBTYPE_UNKNOWN, &whdr, tvb_new_real_data(buf, len, len), &fdlocal, NULL /* &fuzz_cinfo */); + frame_data_destroy(&fdlocal); + + epan_dissect_reset(edt); + return 0; +} + +#else +# error "Missing fuzz target." +#endif + +int +LLVMFuzzerInitialize(int *argc, char ***argv) +{ + int ret; + + ret = fuzz_init(*argc, *argv); + if (ret != 0) + exit(ret); + + return 0; +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */