From 065e6e7010942c5dea2a9d8b8a049c144cb695d4 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 1 Jun 2019 14:53:24 +0300 Subject: [PATCH] tests: New style fuzzing tool for wpa_supplicant WNM handling This is a newer version of tests/wnm-fuzzer tool as the initial step in creating a more uniform set of fuzzing tools that can be used with both libFuzzer and afl-fuzz. Signed-off-by: Jouni Malinen --- tests/README | 5 ++ tests/fuzzing/README | 23 +++++ tests/fuzzing/fuzzer-common.c | 56 ++++++++++++ tests/fuzzing/fuzzer-common.h | 14 +++ tests/fuzzing/rules.include | 88 ++++++++++++++++++ tests/fuzzing/wnm/Makefile | 52 +++++++++++ tests/fuzzing/wnm/corpus/bss-tm-req.dat | Bin 0 -> 31 bytes tests/fuzzing/wnm/corpus/oss-fuzz-0001.dat | Bin 0 -> 64 bytes tests/fuzzing/wnm/corpus/oss-fuzz-0002.dat | Bin 0 -> 104 bytes tests/fuzzing/wnm/corpus/wnm-notif.dat | Bin 0 -> 56 bytes tests/fuzzing/wnm/wnm.c | 99 +++++++++++++++++++++ 11 files changed, 337 insertions(+) create mode 100644 tests/fuzzing/README create mode 100644 tests/fuzzing/fuzzer-common.c create mode 100644 tests/fuzzing/fuzzer-common.h create mode 100644 tests/fuzzing/rules.include create mode 100644 tests/fuzzing/wnm/Makefile create mode 100644 tests/fuzzing/wnm/corpus/bss-tm-req.dat create mode 100644 tests/fuzzing/wnm/corpus/oss-fuzz-0001.dat create mode 100644 tests/fuzzing/wnm/corpus/oss-fuzz-0002.dat create mode 100644 tests/fuzzing/wnm/corpus/wnm-notif.dat create mode 100644 tests/fuzzing/wnm/wnm.c diff --git a/tests/README b/tests/README index b11e07b08..0e2dcffcf 100644 --- a/tests/README +++ b/tests/README @@ -27,6 +27,11 @@ cd build Fuzz testing ------------ +Newer fuzz testing tools are under the fuzzing directory. See +fuzzing/README for more details on them. The following text describes +the older fuzz testing tools that are subject to removal once the same +newer tools have the same coverage available. + Number of the test tools here can be used for fuzz testing with tools like American fuzzy lop (afl-fuzz) that are designed to modify an external file for program input. ap-mgmt-fuzzer, eapol-fuzzer, diff --git a/tests/fuzzing/README b/tests/fuzzing/README new file mode 100644 index 000000000..9ba0f176f --- /dev/null +++ b/tests/fuzzing/README @@ -0,0 +1,23 @@ +hostap.git fuzz testing +----------------------- + +These tools can be used for fuzz testing of various components used +within wpa_supplicant and hostapd. Each directory contains a fuzzing +tool that focuses on one input handler. Each tool can be compiled either +to work with the libFuzzer or as a separate tool that reads the input +from a file specified on the command line, e.g., for American fuzzy lop +(afl-fuzz). Example test corpus is included in */corpus directory. + +Example fuzzing with libFuzzer + +cd @TOOL@ +make clean +make LIBFUZZER=y +./@TOOL@ corpus + +Example fuzzing with afl-fuzz + +cd @TOOL@ +make clean +CC=afl-gcc make +afl-fuzz -i corpus -o findings -- $PWD/@TOOL@ @@ diff --git a/tests/fuzzing/fuzzer-common.c b/tests/fuzzing/fuzzer-common.c new file mode 100644 index 000000000..43b91e19a --- /dev/null +++ b/tests/fuzzing/fuzzer-common.c @@ -0,0 +1,56 @@ +/* + * Common helper functions for fuzzing tools + * Copyright (c) 2019, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" + + +void wpa_fuzzer_set_debug_level(void) +{ + static int first = 1; + + if (first) { + char *env; + + first = 0; + env = getenv("WPADEBUG"); + if (env) + wpa_debug_level = atoi(env); + else + wpa_debug_level = MSG_ERROR + 1; + + wpa_debug_show_keys = 1; + } +} + + +#ifndef TEST_LIBFUZZER +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +int main(int argc, char *argv[]) +{ + char *data; + size_t len; + + if (argc < 2) { + printf("usage: %s \n", argv[0]); + return -1; + } + + data = os_readfile(argv[1], &len); + if (!data) { + printf("Could not read '%s'\n", argv[1]); + return -1; + } + + LLVMFuzzerTestOneInput((const uint8_t *) data, len); + os_free(data); + return 0; +} +#endif /* !TEST_LIBFUZZER */ diff --git a/tests/fuzzing/fuzzer-common.h b/tests/fuzzing/fuzzer-common.h new file mode 100644 index 000000000..80ebfd28b --- /dev/null +++ b/tests/fuzzing/fuzzer-common.h @@ -0,0 +1,14 @@ +/* + * Common helper functions for fuzzing tools + * Copyright (c) 2019, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef FUZZER_COMMON_H +#define FUZZER_COMMON_H + +void wpa_fuzzer_set_debug_level(void); + +#endif /* FUZZER_COMMON_H */ diff --git a/tests/fuzzing/rules.include b/tests/fuzzing/rules.include new file mode 100644 index 000000000..69548cd74 --- /dev/null +++ b/tests/fuzzing/rules.include @@ -0,0 +1,88 @@ +ifdef LIBFUZZER +CC=clang +CFLAGS = -MMD -O2 -Wall -g +CFLAGS += -fsanitize=fuzzer,address,signed-integer-overflow,unsigned-integer-overflow +CFLAGS += -DTEST_LIBFUZZER +LDFLAGS += -fsanitize=fuzzer,address,signed-integer-overflow,unsigned-integer-overflow +endif + +ifndef CC +CC=gcc +endif + +ifndef LDO +LDO=$(CC) +endif + +ifndef CFLAGS +CFLAGS = -MMD -O2 -Wall -g +endif + +CFLAGS += -DCONFIG_NO_RANDOM_POOL +CFLAGS += -DTEST_FUZZ + +WPAS_SRC=../../../wpa_supplicant +SRC=../../../src + +CFLAGS += -I$(SRC) -I$(SRC)/utils -I$(WPAS_SRC) +OBJS += ../fuzzer-common.o + +$(SRC)/ap/libap.a: + $(MAKE) -C $(SRC)/ap TEST_FUZZ=y + +$(SRC)/common/libcommon.a: + $(MAKE) -C $(SRC)/common + +$(SRC)/crypto/libcrypto.a: + $(MAKE) -C $(SRC)/crypto + +$(SRC)/eapol_auth/libeapol_auth.a: + $(MAKE) -C $(SRC)/eapol_auth + +$(SRC)/eapol_supp/libeapol_supp.a: + $(MAKE) -C $(SRC)/eapol_supp + +$(SRC)/eap_common/libeap_common.a: + $(MAKE) -C $(SRC)/eap_common + +$(SRC)/eap_peer/libeap_peer.a: + $(MAKE) -C $(SRC)/eap_peer + +$(SRC)/eap_server/libeap_server.a: + $(MAKE) -C $(SRC)/eap_server + +$(SRC)/l2_packet/libl2_packet.a: + $(MAKE) -C $(SRC)/l2_packet + +$(SRC)/p2p/libp2p.a: + $(MAKE) -C $(SRC)/p2p + +$(SRC)/radius/libradius.a: + $(MAKE) -C $(SRC)/radius + +$(SRC)/rsn_supp/librsn_supp.a: + $(MAKE) -C $(SRC)/rsn_supp TEST_FUZZ=y + +$(SRC)/tls/libtls.a: + $(MAKE) -C $(SRC)/tls TEST_FUZZ=y + +$(SRC)/utils/libutils.a: + $(MAKE) -C $(SRC)/utils TEST_FUZZ=y + +$(SRC)/wps/libwps.a: + $(MAKE) -C $(SRC)/wps + +Q=@ +E=echo +ifeq ($(V), 1) +Q= +E=true +endif +ifeq ($(QUIET), 1) +Q=@ +E=true +endif + +%.o: %.c + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + @$(E) " CC " $< diff --git a/tests/fuzzing/wnm/Makefile b/tests/fuzzing/wnm/Makefile new file mode 100644 index 000000000..2c7e2f776 --- /dev/null +++ b/tests/fuzzing/wnm/Makefile @@ -0,0 +1,52 @@ +all: wnm +include ../rules.include + +CFLAGS += -DCONFIG_WNM +CFLAGS += -DCONFIG_INTERWORKING +CFLAGS += -DCONFIG_GAS +CFLAGS += -DCONFIG_HS20 +CFLAGS += -DIEEE8021X_EAPOL + +LIBS += $(SRC)/common/libcommon.a +LIBS += $(SRC)/crypto/libcrypto.a +LIBS += $(SRC)/tls/libtls.a +LIBS += $(SRC)/rsn_supp/librsn_supp.a +LIBS += $(SRC)/eapol_supp/libeapol_supp.a +LIBS += $(SRC)/eap_peer/libeap_peer.a +LIBS += $(SRC)/eap_common/libeap_common.a +LIBS += $(SRC)/l2_packet/libl2_packet.a +LIBS += $(SRC)/utils/libutils.a + +ELIBS += $(SRC)/crypto/libcrypto.a +ELIBS += $(SRC)/tls/libtls.a + +OBJS += $(WPAS_SRC)/blacklist.o +OBJS += $(WPAS_SRC)/bss.o +OBJS += $(WPAS_SRC)/config.o +OBJS += $(WPAS_SRC)/config_file.o +OBJS += $(WPAS_SRC)/eap_register.o +OBJS += $(WPAS_SRC)/events.o +OBJS += $(WPAS_SRC)/gas_query.o +OBJS += $(WPAS_SRC)/hs20_supplicant.o +OBJS += $(WPAS_SRC)/interworking.o +OBJS += $(WPAS_SRC)/notify.o +OBJS += $(WPAS_SRC)/offchannel.o +OBJS += $(WPAS_SRC)/op_classes.o +OBJS += $(WPAS_SRC)/rrm.o +OBJS += $(WPAS_SRC)/scan.o +OBJS += $(WPAS_SRC)/wmm_ac.o +OBJS += $(WPAS_SRC)/wnm_sta.o +OBJS += $(WPAS_SRC)/wpa_supplicant.o +OBJS += $(WPAS_SRC)/wpas_glue.o +OBJS += $(SRC)/drivers/driver_common.o +OBJS += $(SRC)/drivers/drivers.o + +wnm: wnm.o $(OBJS) $(LIBS) + $(LDO) $(LDFLAGS) -o $@ $^ $(LIBS) $(ELIBS) + +clean: + $(MAKE) -C $(SRC) clean + $(MAKE) -C $(WPAS_SRC) clean + rm -f wnm *~ *.o *.d ../*~ ../*.o ../*.d + +-include $(OBJS:%.o=%.d) diff --git a/tests/fuzzing/wnm/corpus/bss-tm-req.dat b/tests/fuzzing/wnm/corpus/bss-tm-req.dat new file mode 100644 index 0000000000000000000000000000000000000000..14510bb3ad11f70bd8277a5cc4828e0021f97281 GIT binary patch literal 31 ccmcb>V8zJ900JPA8A=*3aIrJ8a4|3d03#v+XaE2J literal 0 HcmV?d00001 diff --git a/tests/fuzzing/wnm/corpus/oss-fuzz-0001.dat b/tests/fuzzing/wnm/corpus/oss-fuzz-0001.dat new file mode 100644 index 0000000000000000000000000000000000000000..53fdf659c4389923203d0efc0d8729c79d634430 GIT binary patch literal 64 icmX?l6bLxDBp76v7#J9s8Mr1guoDD|TwH<>zyts~(*|4s literal 0 HcmV?d00001 diff --git a/tests/fuzzing/wnm/corpus/oss-fuzz-0002.dat b/tests/fuzzing/wnm/corpus/oss-fuzz-0002.dat new file mode 100644 index 0000000000000000000000000000000000000000..cb700936fad550800f551b837b4d81fe88820810 GIT binary patch literal 104 zcmdOS!OqUW@Qs0ii;01Off^PD+zkeGA07<8aY Nz=pCgGrVA6000eq3aS7A literal 0 HcmV?d00001 diff --git a/tests/fuzzing/wnm/corpus/wnm-notif.dat b/tests/fuzzing/wnm/corpus/wnm-notif.dat new file mode 100644 index 0000000000000000000000000000000000000000..c234d3ad5b69b08d0a4caa217475d1d91391b24c GIT binary patch literal 56 zcmcb>V8zJ900JPA8A=8)a7i&T-jxc-pT!`OQBqP+Y^ATCT9KGrkdvyHoS&=D2ms%~ B3q}9{ literal 0 HcmV?d00001 diff --git a/tests/fuzzing/wnm/wnm.c b/tests/fuzzing/wnm/wnm.c new file mode 100644 index 000000000..9c0d5418b --- /dev/null +++ b/tests/fuzzing/wnm/wnm.c @@ -0,0 +1,99 @@ +/* + * wpa_supplicant - WNM fuzzer + * Copyright (c) 2015-2019, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "utils/eloop.h" +#include "common/ieee802_11_defs.h" +#include "rsn_supp/wpa.h" +#include "rsn_supp/wpa_i.h" +#include "wpa_supplicant_i.h" +#include "bss.h" +#include "wnm_sta.h" +#include "config.h" +#include "../fuzzer-common.h" + + +struct arg_ctx { + const u8 *data; + size_t data_len; + struct wpa_supplicant wpa_s; + struct wpa_bss bss; + struct wpa_driver_ops driver; + struct wpa_sm wpa; + struct wpa_config conf; +}; + + +static void test_send_wnm(void *eloop_data, void *user_ctx) +{ + struct arg_ctx *ctx = eloop_data; + const struct ieee80211_mgmt *mgmt; + + wpa_hexdump(MSG_MSGDUMP, "fuzzer - WNM", ctx->data, ctx->data_len); + + mgmt = (const struct ieee80211_mgmt *) ctx->data; + ieee802_11_rx_wnm_action(&ctx->wpa_s, mgmt, ctx->data_len); + + eloop_terminate(); +} + + +static int init_wpa(struct arg_ctx *ctx) +{ + ctx->wpa_s.wpa_state = WPA_COMPLETED; + os_memcpy(ctx->wpa_s.bssid, "\x02\x00\x00\x00\x03\x00", ETH_ALEN); + ctx->wpa_s.current_bss = &ctx->bss; + ctx->wpa_s.driver = &ctx->driver; + ctx->wpa_s.wpa = &ctx->wpa; + ctx->wpa_s.conf = &ctx->conf; + + return 0; +} + + +static void deinit_wpa(struct arg_ctx *ctx) +{ + wnm_deallocate_memory(&ctx->wpa_s); +} + + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + struct arg_ctx ctx; + + wpa_fuzzer_set_debug_level(); + + if (os_program_init()) + return 0; + + if (eloop_init()) { + wpa_printf(MSG_ERROR, "Failed to initialize event loop"); + return 0; + } + + os_memset(&ctx, 0, sizeof(ctx)); + ctx.data = data; + ctx.data_len = size; + if (init_wpa(&ctx)) + goto fail; + + eloop_register_timeout(0, 0, test_send_wnm, &ctx, NULL); + + wpa_printf(MSG_DEBUG, "Starting eloop"); + eloop_run(); + wpa_printf(MSG_DEBUG, "eloop done"); + deinit_wpa(&ctx); + +fail: + eloop_destroy(); + os_program_deinit(); + + return 0; +}