-
Notifications
You must be signed in to change notification settings - Fork 297
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
shim takes several forms of input from several sources that are not necessarily trustworthy. As such, we need to take measures to validate that we don't have unacceptable results from bad inputs. One such measure is "fuzzing" the inputs which parse untrusted data by running them with randomized or partially randomized input. This change adds such testing using clang's "libFuzzer" to our CSV parser. I've run this on 24-cores at 4GHz for half an hour, and so far each fuzzer has converged on 79% coverage. I expect the 21% that's not getting covered are the EFI API mock interfaces we're building in from test.c and similar. So far no errors have been found, which is what was expected since this particular API is being manually fuzzed with ~8kB of /dev/urandom on every build since 2021-02-23. Signed-off-by: Peter Jones <pjones@redhat.com>
- Loading branch information
Showing
4 changed files
with
185 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// SPDX-License-Identifier: BSD-2-Clause-Patent | ||
/* | ||
* test-csv.c - test our csv parser | ||
*/ | ||
|
||
#ifndef SHIM_UNIT_TEST | ||
#define SHIM_UNIT_TEST | ||
#endif | ||
#include "shim.h" | ||
|
||
#include <stdio.h> | ||
|
||
int | ||
test_csv_simple_fuzz(char *random_bin, size_t random_bin_len) | ||
{ | ||
list_t entry_list; | ||
size_t i; | ||
char *current, *end; | ||
list_t *pos = NULL; | ||
EFI_STATUS efi_status; | ||
|
||
INIT_LIST_HEAD(&entry_list); | ||
|
||
current = &random_bin[0]; | ||
current = current + 1 - 1; | ||
end = current + random_bin_len - 1; | ||
*end = '\0'; | ||
|
||
efi_status = parse_csv_data(current, end, 7, &entry_list); | ||
if (efi_status != EFI_SUCCESS) | ||
return 0; | ||
if (list_size(&entry_list) <= 1) | ||
goto fail; | ||
|
||
i = 0; | ||
list_for_each(pos, &entry_list) { | ||
struct csv_row *csv_row; | ||
|
||
csv_row = list_entry(pos, struct csv_row, list); | ||
i++; | ||
} | ||
|
||
free_csv_list(&entry_list); | ||
|
||
return 0; | ||
fail: | ||
free_csv_list(&entry_list); | ||
return -1; | ||
} | ||
|
||
int | ||
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | ||
{ | ||
int rc; | ||
uint8_t *data_copy; | ||
|
||
if (size < 1) | ||
return 0; | ||
|
||
data_copy = malloc(size); | ||
if (!data_copy) | ||
return -1; | ||
|
||
memcpy(data_copy, data, size); | ||
rc = test_csv_simple_fuzz((char *)data_copy, size); | ||
free(data_copy); | ||
|
||
return rc; // Values other than 0 and -1 are reserved for future use. | ||
} | ||
|
||
// vim:fenc=utf-8:tw=75:noet |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# SPDX-License-Identifier: BSD-2-Clause-Patent | ||
# | ||
# fuzz.mk - makefile to fuzz local test programs | ||
# | ||
|
||
.SUFFIXES: | ||
|
||
include Make.defaults | ||
|
||
CC = clang | ||
VALGRIND ?= | ||
DEBUG_PRINTS ?= 0 | ||
OPTIMIZATIONS=-fsanitize=fuzzer,address -Og -ggdb | ||
CFLAGS = $(OPTIMIZATIONS) -std=gnu11 \ | ||
-isystem $(TOPDIR)/include/system \ | ||
$(EFI_INCLUDES) \ | ||
-Iinclude -iquote . \ | ||
-isystem /usr/include \ | ||
-isystem $(shell $(CC) $(ARCH_CFLAGS) -print-file-name=include) \ | ||
$(ARCH_CFLAGS) \ | ||
-fshort-wchar \ | ||
-fno-builtin \ | ||
-rdynamic \ | ||
-fno-inline \ | ||
-fno-eliminate-unused-debug-types \ | ||
-fno-eliminate-unused-debug-symbols \ | ||
-gpubnames \ | ||
-grecord-gcc-switches \ | ||
$(if $(findstring clang,$(CC)),-Wno-unknown-warning-option) \ | ||
$(DEFAULT_WARNFLAGS) \ | ||
-Wsign-compare \ | ||
-Wno-deprecated-declarations \ | ||
$(if $(findstring gcc,$(CC)),-Wno-unused-but-set-variable) \ | ||
-Wno-unused-but-set-variable \ | ||
-Wno-unused-variable \ | ||
-Wno-pointer-sign \ | ||
$(DEFAULT_WERRFLAGS) \ | ||
-Werror=nonnull \ | ||
$(shell $(CC) -Werror=nonnull-compare -E -x c /dev/null >/dev/null 2>&1 && echo -Werror=nonnull-compare) \ | ||
$(ARCH_DEFINES) \ | ||
-DEFI_FUNCTION_WRAPPER \ | ||
-DGNU_EFI_USE_MS_ABI -DPAGE_SIZE=4096 \ | ||
-DSHIM_UNIT_TEST \ | ||
-DSHIM_ENABLE_LIBFUZZER \ | ||
"-DDEFAULT_DEBUG_PRINT_STATE=$(DEBUG_PRINTS)" | ||
|
||
# On some systems (e.g. Arch Linux), limits.h is in the "include-fixed" instead | ||
# of the "include" directory | ||
CFLAGS += -isystem $(shell $(CC) $(ARCH_CFLAGS) -print-file-name=include-fixed) | ||
|
||
# And on Debian also check the multi-arch include path | ||
CFLAGS += -isystem /usr/include/$(shell $(CC) $(ARCH_CFLAGS) -print-multiarch) | ||
|
||
libefi-test.a : | ||
$(MAKE) -C gnu-efi \ | ||
COMPILER="$(COMPILER)" \ | ||
CC="$(CC)" \ | ||
ARCH=$(ARCH_GNUEFI) \ | ||
TOPDIR=$(TOPDIR)/gnu-efi \ | ||
-f $(TOPDIR)/gnu-efi/Makefile \ | ||
clean lib | ||
mv gnu-efi/$(ARCH)/lib/libefi.a $@ | ||
$(MAKE) -C gnu-efi \ | ||
COMPILER="$(COMPILER)" \ | ||
ARCH=$(ARCH_GNUEFI) \ | ||
TOPDIR=$(TOPDIR)/gnu-efi \ | ||
-f $(TOPDIR)/gnu-efi/Makefile \ | ||
clean | ||
|
||
fuzz-str_FILES = lib/string.c | ||
|
||
fuzzers := $(patsubst %.c,%,$(wildcard fuzz-*.c)) | ||
|
||
$(fuzzers) :: fuzz-% : | libefi-test.a | ||
|
||
$(fuzzers) :: fuzz-% : test.c fuzz-%.c $(fuzz-%_FILES) | ||
$(CC) $(CFLAGS) -o $@ $(sort $^ $(wildcard $*.c) $(fuzz-$*_FILES)) libefi-test.a -lefivar | ||
$(VALGRIND) ./$@ -max_len=4096 -jobs=24 | ||
|
||
fuzz : $(fuzzers) | ||
$(MAKE) -f include/fuzz.mk fuzz-clean | ||
|
||
fuzz-clean : | ||
@rm -vf random.bin libefi-test.a | ||
@rm -vf vgcore.* fuzz*.log | ||
|
||
clean : fuzz-clean | ||
|
||
all : fuzz-clean fuzz | ||
|
||
.PHONY: $(fuzzers) all fuzz clean | ||
.SECONDARY: random.bin | ||
|
||
# vim:ft=make |