diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 358f9f3142..e07cc2f151 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -366,6 +366,14 @@ jobs: (cd libfuzzer-dotnet; make) cp -r libfuzzer-dotnet/my-fuzzer libfuzzer-dotnet/inputs artifacts/linux-libfuzzer-dotnet/ + mkdir -p artifacts/linux-libfuzzer-dlopen + (cd libfuzzer-dlopen; make) + cp -r libfuzzer-dlopen/{fuzz.exe,*.so,seeds} artifacts/linux-libfuzzer-dlopen/ + + mkdir -p artifacts/linux-libfuzzer-linked-library + (cd libfuzzer-linked-library; make) + cp -r libfuzzer-linked-library/{fuzz.exe,*.so,seeds} artifacts/linux-libfuzzer-linked-library/ + mkdir -p artifacts/linux-trivial-crash-asan (cd trivial-crash ; make clean; make CFLAGS='-fsanitize=address -fno-omit-frame-pointer') cp -r trivial-crash/fuzz.exe trivial-crash/seeds artifacts/linux-trivial-crash-asan @@ -417,6 +425,12 @@ jobs: cp fuzz.exe,fuzz.pdb,seeds ../artifacts/windows-trivial-crash -Recurse cd ../ + mkdir artifacts/windows-libfuzzer-linked-library + cd libfuzzer-linked-library + make -f Makefile.windows + cp fuzz.exe,fuzz.pdb,bad1.dll,bad1.pdb,bad2.dll,bad2.pdb,seeds ../artifacts/windows-libfuzzer-linked-library -Recurse + cd ../ + mkdir artifacts/windows-trivial-crash-asan cd trivial-crash make clean diff --git a/src/integration-tests/integration-test.py b/src/integration-tests/integration-test.py index de945e8900..0bed5fbc1b 100755 --- a/src/integration-tests/integration-test.py +++ b/src/integration-tests/integration-test.py @@ -88,6 +88,32 @@ class Integration(BaseModel): }, reboot_after_setup=True, ), + "linux-libfuzzer-dlopen": Integration( + template=TemplateType.libfuzzer, + os=OS.linux, + target_exe="fuzz.exe", + inputs="seeds", + wait_for_files={ + ContainerType.unique_reports: 1, + ContainerType.coverage: 1, + ContainerType.inputs: 2, + }, + reboot_after_setup=True, + use_setup=True, + ), + "linux-libfuzzer-linked-library": Integration( + template=TemplateType.libfuzzer, + os=OS.linux, + target_exe="fuzz.exe", + inputs="seeds", + wait_for_files={ + ContainerType.unique_reports: 1, + ContainerType.coverage: 1, + ContainerType.inputs: 2, + }, + reboot_after_setup=True, + use_setup=True, + ), "linux-libfuzzer-dotnet": Integration( template=TemplateType.libfuzzer_dotnet, os=OS.linux, @@ -140,6 +166,18 @@ class Integration(BaseModel): ContainerType.coverage: 1, }, ), + "windows-libfuzzer-linked-library": Integration( + template=TemplateType.libfuzzer, + os=OS.windows, + target_exe="fuzz.exe", + inputs="seeds", + wait_for_files={ + ContainerType.inputs: 2, + ContainerType.unique_reports: 1, + ContainerType.coverage: 1, + }, + use_setup=True, + ), "windows-trivial-crash": Integration( template=TemplateType.radamsa, os=OS.windows, diff --git a/src/integration-tests/libfuzzer-dlopen/Makefile b/src/integration-tests/libfuzzer-dlopen/Makefile new file mode 100644 index 0000000000..f7284b3e52 --- /dev/null +++ b/src/integration-tests/libfuzzer-dlopen/Makefile @@ -0,0 +1,18 @@ +CC=clang +CFLAGS=-fsanitize=address,fuzzer -fPIC -O0 -ggdb3 + +.PHONY: all clean test + +all: libbad.so fuzz.exe + +fuzz.exe: main.o + $(CC) $(CFLAGS) -o $@ $< + +libbad.so: bad.o + $(CC) -shared -o $@ $< + +test: all + LD_LIBRARY_PATH=. ./fuzz.exe + +clean: + rm -rf fuzz.exe *.o *.so crash-* diff --git a/src/integration-tests/libfuzzer-dlopen/bad.c b/src/integration-tests/libfuzzer-dlopen/bad.c new file mode 100644 index 0000000000..3cf7449734 --- /dev/null +++ b/src/integration-tests/libfuzzer-dlopen/bad.c @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include + +int func(const uint8_t *data, size_t len) { + int cnt = 0; + + if (len < 4) { + return 0; + } + + if (data[0] == 'x') { cnt++; } + if (data[1] == 'y') { cnt++; } + if (data[2] == 'z') { cnt++; } + + if (cnt >= 3) { + switch (data[3]) { + case '0': { + // segv + int *p = NULL; *p = 123; + break; + } + case '1': { + // stack-buffer-underflow + int* p = &cnt - 32; for (int i = 0; i < 32; i++) { *(p + i) = 0; } + break; + } + case '2': { + // stack-buffer-overflow + int* p = &cnt + 32; for (int i = 0; i < 32; i++) { *(p - i) = 0; } + break; + } + case '3': { + // bad-free + int *p = &cnt; free(p); + break; + } + case '4': { + // double-free + int* p = malloc(sizeof(int)); free(p); free(p); + break; + } + case '5': { + // heap-use-after-free + int* p = malloc(sizeof(int)); free(p); *p = 123; + break; + } + case '6': { + // heap-buffer-overflow + int* p = malloc(8 * sizeof(int)); for (int i = 0; i < 32; i++) { *(p + i) = 0; } + break; + } + case '7': { + // fpe + int x = 0; int y = 123 / x; + break; + } + } + } + + return 0; +} diff --git a/src/integration-tests/libfuzzer-dlopen/bad.h b/src/integration-tests/libfuzzer-dlopen/bad.h new file mode 100644 index 0000000000..1fcd630cbd --- /dev/null +++ b/src/integration-tests/libfuzzer-dlopen/bad.h @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef BAD_H +#define BAD_H + +int func(const uint8_t *data, size_t len); + +#endif diff --git a/src/integration-tests/libfuzzer-dlopen/main.c b/src/integration-tests/libfuzzer-dlopen/main.c new file mode 100644 index 0000000000..26e8ab1cad --- /dev/null +++ b/src/integration-tests/libfuzzer-dlopen/main.c @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include +#include +#include +#include + +int (*fuzz_func)(const uint8_t *data, size_t size); + +int LLVMFuzzerInitialize(int *argc, char ***argv) +{ + printf("initialize\n"); + void *handle; + int (*b)(void); + char *error; + + handle = dlopen("libbad.so", RTLD_LAZY); + if (!handle) + { + printf("can't open %s", dlerror()); + return 1; + } + fuzz_func = (int (*)(const uint8_t *data, size_t size))dlsym(handle, "func"); + error = dlerror(); + if (error != NULL) + { + printf("%s\n", error); + exit(EXIT_FAILURE); + } + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + assert(fuzz_func != NULL); + return fuzz_func(data, size); +} diff --git a/src/integration-tests/libfuzzer-dlopen/seeds/good.txt b/src/integration-tests/libfuzzer-dlopen/seeds/good.txt new file mode 100644 index 0000000000..12799ccbe7 --- /dev/null +++ b/src/integration-tests/libfuzzer-dlopen/seeds/good.txt @@ -0,0 +1 @@ +good diff --git a/src/integration-tests/libfuzzer-linked-library/Makefile b/src/integration-tests/libfuzzer-linked-library/Makefile new file mode 100644 index 0000000000..515d7f0b23 --- /dev/null +++ b/src/integration-tests/libfuzzer-linked-library/Makefile @@ -0,0 +1,22 @@ +CC=clang + +.PHONY: all clean test + +all: fuzz.exe + +CFLAGS=-fsanitize=address,fuzzer -fPIC -O0 -ggdb3 + +fuzz.exe: main.o libbad1.so libbad2.so + $(CC) $(CFLAGS) -o $@ $< -lbad1 -lbad2 -L. + +libbad1.so: bad1.o + $(CC) -fsanitize=address -shared -o $@ $< + +libbad2.so: bad2.o + $(CC) -fsanitize=address -shared -o $@ $< + +test: all + LD_LIBRARY_PATH=. ./fuzz.exe + +clean: + rm -rf fuzz.exe *.o *.so *.dll crash-* *.lib *.exp *.pdb diff --git a/src/integration-tests/libfuzzer-linked-library/Makefile.windows b/src/integration-tests/libfuzzer-linked-library/Makefile.windows new file mode 100644 index 0000000000..620fb6edfc --- /dev/null +++ b/src/integration-tests/libfuzzer-linked-library/Makefile.windows @@ -0,0 +1,23 @@ +CC=clang + +.PHONY: all clean test + +all: fuzz.exe + +CFLAGS=-g3 -fsanitize=address,fuzzer + +fuzz.exe: main.o bad1.dll bad2.dll + $(CC) $(CFLAGS) main.o -o fuzz.exe -L. -lbad1 -lbad2 + +bad1.dll: bad1.o + $(CC) $(CFLAGS) -shared -o bad1.dll bad1.o + +bad2.dll: bad2.o + $(CC) $(CFLAGS) -shared -o bad2.dll bad2.o + + +test: all + LD_LIBRARY_PATH=. ./fuzz.exe + +clean: + rm -f *.dll *.exe *.exp *.pdb *.o *.lib diff --git a/src/integration-tests/libfuzzer-linked-library/bad1.c b/src/integration-tests/libfuzzer-linked-library/bad1.c new file mode 100644 index 0000000000..5563a62be6 --- /dev/null +++ b/src/integration-tests/libfuzzer-linked-library/bad1.c @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include + +#if defined(_WIN32) + #define LIBRARY_API __declspec(dllexport) +#else + #define LIBRARY_API +#endif + +int LIBRARY_API func1(const uint8_t *data, size_t len) { + int cnt = 0; + + if (len < 4) { + return 0; + } + + if (data[0] == 'x') { cnt++; } + if (data[1] == 'y') { cnt++; } + if (data[2] == 'z') { cnt++; } + + if (cnt >= 3) { + switch (data[3]) { + case '0': { + // segv + int *p = NULL; *p = 123; + break; + } + case '1': { + // stack-buffer-underflow + int* p = &cnt - 32; for (int i = 0; i < 32; i++) { *(p + i) = 0; } + break; + } + case '2': { + // stack-buffer-overflow + int* p = &cnt + 32; for (int i = 0; i < 32; i++) { *(p - i) = 0; } + break; + } + case '3': { + // bad-free + int *p = &cnt; free(p); + break; + } + case '4': { + // double-free + int* p = malloc(sizeof(int)); free(p); free(p); + break; + } + case '5': { + // heap-use-after-free + int* p = malloc(sizeof(int)); free(p); *p = 123; + break; + } + case '6': { + // heap-buffer-overflow + int* p = malloc(8 * sizeof(int)); for (int i = 0; i < 32; i++) { *(p + i) = 0; } + break; + } + case '7': { + // fpe + int x = 0; int y = 123 / x; + break; + } + } + } + + return 0; +} diff --git a/src/integration-tests/libfuzzer-linked-library/bad1.h b/src/integration-tests/libfuzzer-linked-library/bad1.h new file mode 100644 index 0000000000..a18736708c --- /dev/null +++ b/src/integration-tests/libfuzzer-linked-library/bad1.h @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef BAD1_H +#define BAD1_H + +int func1(const uint8_t *data, size_t len); + +#endif diff --git a/src/integration-tests/libfuzzer-linked-library/bad2.c b/src/integration-tests/libfuzzer-linked-library/bad2.c new file mode 100644 index 0000000000..d863ffb265 --- /dev/null +++ b/src/integration-tests/libfuzzer-linked-library/bad2.c @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include + +#if defined(_WIN32) + #define LIBRARY_API __declspec(dllexport) +#else + #define LIBRARY_API +#endif + +int LIBRARY_API func2(const uint8_t *data, size_t len) { + int cnt = 0; + + if (len < 4) { + return 0; + } + + if (data[0] == 'a') { cnt++; } + if (data[1] == 'b') { cnt++; } + if (data[2] == 'c') { cnt++; } + + if (cnt >= 3) { + switch (data[3]) { + case '0': { + // segv + int *p = NULL; *p = 123; + break; + } + case '1': { + // stack-buffer-underflow + int* p = &cnt - 32; for (int i = 0; i < 32; i++) { *(p + i) = 0; } + break; + } + case '2': { + // stack-buffer-overflow + int* p = &cnt + 32; for (int i = 0; i < 32; i++) { *(p - i) = 0; } + break; + } + case '3': { + // bad-free + int *p = &cnt; free(p); + break; + } + case '4': { + // double-free + int* p = malloc(sizeof(int)); free(p); free(p); + break; + } + case '5': { + // heap-use-after-free + int* p = malloc(sizeof(int)); free(p); *p = 123; + break; + } + case '6': { + // heap-buffer-overflow + int* p = malloc(8 * sizeof(int)); for (int i = 0; i < 32; i++) { *(p + i) = 0; } + break; + } + case '7': { + // fpe + int x = 0; int y = 123 / x; + break; + } + } + } + + return 0; +} diff --git a/src/integration-tests/libfuzzer-linked-library/bad2.h b/src/integration-tests/libfuzzer-linked-library/bad2.h new file mode 100644 index 0000000000..2ded409026 --- /dev/null +++ b/src/integration-tests/libfuzzer-linked-library/bad2.h @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef BAD2_H +#define BAD2_H + +int func2(const uint8_t *data, size_t len); + +#endif diff --git a/src/integration-tests/libfuzzer-linked-library/main.c b/src/integration-tests/libfuzzer-linked-library/main.c new file mode 100644 index 0000000000..81f3634a41 --- /dev/null +++ b/src/integration-tests/libfuzzer-linked-library/main.c @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include + +#include "bad1.h" +#include "bad2.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + func1(data, size); + func2(data, size); + return 0; +} diff --git a/src/integration-tests/libfuzzer-linked-library/seeds/good.txt b/src/integration-tests/libfuzzer-linked-library/seeds/good.txt new file mode 100644 index 0000000000..12799ccbe7 --- /dev/null +++ b/src/integration-tests/libfuzzer-linked-library/seeds/good.txt @@ -0,0 +1 @@ +good