From 5467b4180b68b3e7318adec1e15ce3ffd23b25c9 Mon Sep 17 00:00:00 2001 From: disconnect3d Date: Thu, 30 Nov 2023 16:48:42 +0100 Subject: [PATCH 1/5] add fuzzing --- meson.build | 13 +++++++++++++ src/fuzzing/fuzz_util_string_length.c | 26 +++++++++++++++++++++++++ src/fuzzing/fuzz_wordsplit.c | 28 +++++++++++++++++++++++++++ src/fuzzing/meson.build | 3 +++ src/pacman/util.c | 2 +- src/pacman/util.h | 1 + 6 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/fuzzing/fuzz_util_string_length.c create mode 100644 src/fuzzing/fuzz_wordsplit.c create mode 100644 src/fuzzing/meson.build diff --git a/meson.build b/meson.build index f4935e76..38b51661 100644 --- a/meson.build +++ b/meson.build @@ -305,6 +305,8 @@ subdir('src/pacman') subdir('src/util') subdir('scripts') +subdir('src/fuzzing') + # Internationalization if get_option('i18n') i18n = import('i18n') @@ -398,6 +400,17 @@ executable( install : true, ) +# Note: this target must be built with clang! +executable( + 'fuzz_wordsplit', + fuzzing_sources, + include_directories : includes, + link_with : [libcommon], + dependencies : [], + c_args : ['-fsanitize=fuzzer,address', '-ggdb'], + link_args : ['-fsanitize=fuzzer,address', '-ggdb'], +) + foreach wrapper : script_wrappers cdata = configuration_data() cdata.set_quoted('BASH', BASH.full_path()) diff --git a/src/fuzzing/fuzz_util_string_length.c b/src/fuzzing/fuzz_util_string_length.c new file mode 100644 index 00000000..f7761434 --- /dev/null +++ b/src/fuzzing/fuzz_util_string_length.c @@ -0,0 +1,26 @@ +#define _XOPEN_SOURCE +#include +#include +#include +#include +#include + +#include "util.h" + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +static int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size == 0) + return 0; + + // Prepare a null terminated string + char* cstring = malloc(Size+1); + memcpy(cstring, Data, Size); + cstring[Size] = 0; + + string_length(cstring); + + free(cstring); + + return 0; +} \ No newline at end of file diff --git a/src/fuzzing/fuzz_wordsplit.c b/src/fuzzing/fuzz_wordsplit.c new file mode 100644 index 00000000..06c0fc48 --- /dev/null +++ b/src/fuzzing/fuzz_wordsplit.c @@ -0,0 +1,28 @@ +#define _XOPEN_SOURCE +#include +#include +#include +#include +#include + +#include "util-common.h" + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size == 0) + return 0; + + // Prepare a null terminated string + char* cstring = malloc(Size+1); + memcpy(cstring, Data, Size); + cstring[Size] = 0; + + char** ptr = wordsplit(cstring); + if (ptr) + free(ptr); + + free(cstring); + + return 0; +} diff --git a/src/fuzzing/meson.build b/src/fuzzing/meson.build new file mode 100644 index 00000000..e7f02a28 --- /dev/null +++ b/src/fuzzing/meson.build @@ -0,0 +1,3 @@ +fuzzing_sources = files(''' + fuzz_wordsplit.c +'''.split()) diff --git a/src/pacman/util.c b/src/pacman/util.c index 5d42a6e9..a41c9e5e 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -449,7 +449,7 @@ static char *concat_list(alpm_list_t *lst, formatfn fn) return output; } -static size_t string_length(const char *s) +size_t string_length(const char *s) { int len; wchar_t *wcstr; diff --git a/src/pacman/util.h b/src/pacman/util.h index 52e79915..d8f7f5f2 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -47,6 +47,7 @@ typedef struct _pm_target_t { int is_explicit; } pm_target_t; +size_t string_length(const char *s); void trans_init_error(void); /* flags is a bitfield of alpm_transflag_t flags */ int trans_init(int flags, int check_valid); From ee352110f5fda215fccdd2b7b4850a6e80e1ad64 Mon Sep 17 00:00:00 2001 From: disconnect3d Date: Fri, 1 Dec 2023 18:51:13 +0100 Subject: [PATCH 2/5] Fix memory leak in fuzz_wordsplit --- meson.build | 6 ++++-- src/fuzzing/fuzz_util_string_length.c | 2 +- src/fuzzing/fuzz_wordsplit.c | 14 ++++++++++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 38b51661..8c71a63f 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,8 @@ libalpm_version = '13.0.1' cc = meson.get_compiler('c') +add_project_arguments(['-fsanitize=address', '-fno-omit-frame-pointer', '-ggdb', '-O0'], language : 'c') + # commandline options PREFIX = get_option('prefix') DATAROOTDIR = join_paths(PREFIX, get_option('datarootdir')) @@ -407,8 +409,8 @@ executable( include_directories : includes, link_with : [libcommon], dependencies : [], - c_args : ['-fsanitize=fuzzer,address', '-ggdb'], - link_args : ['-fsanitize=fuzzer,address', '-ggdb'], + c_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer'], + link_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer'], ) foreach wrapper : script_wrappers diff --git a/src/fuzzing/fuzz_util_string_length.c b/src/fuzzing/fuzz_util_string_length.c index f7761434..a6b04fb2 100644 --- a/src/fuzzing/fuzz_util_string_length.c +++ b/src/fuzzing/fuzz_util_string_length.c @@ -23,4 +23,4 @@ static int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { free(cstring); return 0; -} \ No newline at end of file +} diff --git a/src/fuzzing/fuzz_wordsplit.c b/src/fuzzing/fuzz_wordsplit.c index 06c0fc48..2e4b41ce 100644 --- a/src/fuzzing/fuzz_wordsplit.c +++ b/src/fuzzing/fuzz_wordsplit.c @@ -19,9 +19,19 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { cstring[Size] = 0; char** ptr = wordsplit(cstring); - if (ptr) - free(ptr); + // Free the memory allocated by wordsplit + if (ptr) { + int i = 0; + char* p = ptr[i++]; + while (p) { + free(p); + p = ptr[i++]; + } + free(ptr); + } + + // Free the allocated cstring free(cstring); return 0; From 275fb8997fa52c679e78e790db5db749478f1ea2 Mon Sep 17 00:00:00 2001 From: disconnect3d Date: Fri, 1 Dec 2023 19:03:27 +0100 Subject: [PATCH 3/5] add fuzz_string_length --- meson.build | 14 +++++++++++++- ...z_util_string_length.c => fuzz_string_length.c} | 7 +++++-- src/fuzzing/meson.build | 6 +++++- src/pacman/pacman.c | 2 ++ 4 files changed, 25 insertions(+), 4 deletions(-) rename src/fuzzing/{fuzz_util_string_length.c => fuzz_string_length.c} (67%) diff --git a/meson.build b/meson.build index 8c71a63f..c73c73ca 100644 --- a/meson.build +++ b/meson.build @@ -405,7 +405,7 @@ executable( # Note: this target must be built with clang! executable( 'fuzz_wordsplit', - fuzzing_sources, + fuzz_wordsplit_sources, include_directories : includes, link_with : [libcommon], dependencies : [], @@ -413,6 +413,18 @@ executable( link_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer'], ) +# Note: this target must be built with clang! +executable( + 'fuzz_string_length', + [fuzz_string_length_sources, pacman_sources], + include_directories : includes, + link_with : [libalpm_a, libcommon], + dependencies : [], + c_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer', '-DFUZZING_PACMAN'], + link_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer'], +) + + foreach wrapper : script_wrappers cdata = configuration_data() cdata.set_quoted('BASH', BASH.full_path()) diff --git a/src/fuzzing/fuzz_util_string_length.c b/src/fuzzing/fuzz_string_length.c similarity index 67% rename from src/fuzzing/fuzz_util_string_length.c rename to src/fuzzing/fuzz_string_length.c index a6b04fb2..f6dac010 100644 --- a/src/fuzzing/fuzz_util_string_length.c +++ b/src/fuzzing/fuzz_string_length.c @@ -5,11 +5,14 @@ #include #include -#include "util.h" +// TODO/FIXME: Fix the util.h include +//#include "util.h" +// And remove that function header from here +size_t string_length(const char *s); int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); -static int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if (Size == 0) return 0; diff --git a/src/fuzzing/meson.build b/src/fuzzing/meson.build index e7f02a28..13a95b3e 100644 --- a/src/fuzzing/meson.build +++ b/src/fuzzing/meson.build @@ -1,3 +1,7 @@ -fuzzing_sources = files(''' +fuzz_wordsplit_sources = files(''' fuzz_wordsplit.c '''.split()) + +fuzz_string_length_sources = files(''' + fuzz_string_length.c +'''.split()) diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index e5c6e420..77c88392 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -1079,6 +1079,7 @@ static void cl_to_log(int argc, char *argv[]) } } +#ifndef FUZZING_PACMAN /** Main function. * @param argc * @param argv @@ -1273,3 +1274,4 @@ int main(int argc, char *argv[]) /* not reached */ return EXIT_SUCCESS; } +#endif //FUZZING_PACMAN From b89287281d757e6259a16b5fc1524f13354c887c Mon Sep 17 00:00:00 2001 From: disconnect3d Date: Fri, 1 Dec 2023 19:14:21 +0100 Subject: [PATCH 4/5] add fuzz_alpm_extract_keyid --- meson.build | 11 ++++++++++- src/fuzzing/fuzz_alpm_extract_keyid.c | 26 ++++++++++++++++++++++++++ src/fuzzing/meson.build | 4 ++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/fuzzing/fuzz_alpm_extract_keyid.c diff --git a/meson.build b/meson.build index c73c73ca..f880f3a4 100644 --- a/meson.build +++ b/meson.build @@ -423,7 +423,16 @@ executable( c_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer', '-DFUZZING_PACMAN'], link_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer'], ) - +# Note: this target must be built with clang! +executable( + 'fuzz_alpm_extract_keyid', + [fuzz_alpm_extract_keyid_sources, pacman_sources], + include_directories : includes, + link_with : [libalpm_a, libcommon], + dependencies : [], + c_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer', '-DFUZZING_PACMAN'], + link_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer'], +) foreach wrapper : script_wrappers cdata = configuration_data() diff --git a/src/fuzzing/fuzz_alpm_extract_keyid.c b/src/fuzzing/fuzz_alpm_extract_keyid.c new file mode 100644 index 00000000..febbd57a --- /dev/null +++ b/src/fuzzing/fuzz_alpm_extract_keyid.c @@ -0,0 +1,26 @@ +#define _XOPEN_SOURCE +#include +#include +#include +#include +#include + +/* libalpm */ +#include "alpm.h" +#include "alpm_list.h" +#include "handle.h" + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size == 0) + return 0; + + alpm_handle_t handle; // TODO/FIXME? + const char* filename = "/dev/null"; // TODO/FIXME? + + alpm_list_t *keys = NULL; + alpm_extract_keyid(&handle, filename, /* sig */ Data, /* len */ Size, &keys); + + return 0; +} diff --git a/src/fuzzing/meson.build b/src/fuzzing/meson.build index 13a95b3e..9fe120b7 100644 --- a/src/fuzzing/meson.build +++ b/src/fuzzing/meson.build @@ -5,3 +5,7 @@ fuzz_wordsplit_sources = files(''' fuzz_string_length_sources = files(''' fuzz_string_length.c '''.split()) + +fuzz_alpm_extract_keyid_sources = files(''' + fuzz_alpm_extract_keyid.c +'''.split()) From ee1d49b8a64397cb9b067661af9f12596f817ef1 Mon Sep 17 00:00:00 2001 From: disconnect3d Date: Mon, 4 Dec 2023 16:38:39 +0100 Subject: [PATCH 5/5] add parseconfigfile fuzzer --- meson.build | 13 ++++++--- src/fuzzing/fuzz_parseconfigfile.c | 43 ++++++++++++++++++++++++++++++ src/fuzzing/fuzz_string_length.c | 3 --- src/fuzzing/fuzz_wordsplit.c | 2 -- src/fuzzing/meson.build | 4 +++ 5 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 src/fuzzing/fuzz_parseconfigfile.c diff --git a/meson.build b/meson.build index f880f3a4..b04e0970 100644 --- a/meson.build +++ b/meson.build @@ -402,7 +402,7 @@ executable( install : true, ) -# Note: this target must be built with clang! +# Note: fuzz targets below must be built with Clang compiler executable( 'fuzz_wordsplit', fuzz_wordsplit_sources, @@ -413,7 +413,6 @@ executable( link_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer'], ) -# Note: this target must be built with clang! executable( 'fuzz_string_length', [fuzz_string_length_sources, pacman_sources], @@ -423,7 +422,6 @@ executable( c_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer', '-DFUZZING_PACMAN'], link_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer'], ) -# Note: this target must be built with clang! executable( 'fuzz_alpm_extract_keyid', [fuzz_alpm_extract_keyid_sources, pacman_sources], @@ -433,6 +431,15 @@ executable( c_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer', '-DFUZZING_PACMAN'], link_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer'], ) +executable( + 'fuzz_parseconfigfile', + [fuzz_parseconfigfile_sources, pacman_sources], + include_directories : includes, + link_with : [libalpm_a], + dependencies : [], + c_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer', '-DFUZZING_PACMAN'], + link_args : ['-fsanitize=fuzzer,address', '-ggdb', '-O0', '-fno-omit-frame-pointer'], +) foreach wrapper : script_wrappers cdata = configuration_data() diff --git a/src/fuzzing/fuzz_parseconfigfile.c b/src/fuzzing/fuzz_parseconfigfile.c new file mode 100644 index 00000000..4746141d --- /dev/null +++ b/src/fuzzing/fuzz_parseconfigfile.c @@ -0,0 +1,43 @@ +#include +#include +#include +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include +#include + +// TODO/FIXME: Fix the util.h include +//#include "conf.h" +// And remove that function header from here +int parseconfigfile(const char *s); +extern void *config; +void *config_new(void); + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +// TODO/FIXME: This fuzzer should always be run from a chroot +// without any other files in it; otherwise the configfile may refer +// to other files +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + static void* config_object = 0; + + // TODO/FIXME: The harness needs to be run with -detect_leaks=0 + // because the config object here is detected as a leak + if (!config_object) { + config = config_object = config_new(); + } + + if (Size == 0) + return 0; + + int fd = memfd_create("input", 0); + write(fd, Data, Size); + + char path[64] = {0}; + sprintf(path, "/proc/self/fd/%d", fd); + + parseconfigfile(path); + + close(fd); + + return 0; +} diff --git a/src/fuzzing/fuzz_string_length.c b/src/fuzzing/fuzz_string_length.c index f6dac010..8991b476 100644 --- a/src/fuzzing/fuzz_string_length.c +++ b/src/fuzzing/fuzz_string_length.c @@ -1,9 +1,6 @@ -#define _XOPEN_SOURCE #include #include -#include #include -#include // TODO/FIXME: Fix the util.h include //#include "util.h" diff --git a/src/fuzzing/fuzz_wordsplit.c b/src/fuzzing/fuzz_wordsplit.c index 2e4b41ce..e2e10210 100644 --- a/src/fuzzing/fuzz_wordsplit.c +++ b/src/fuzzing/fuzz_wordsplit.c @@ -2,8 +2,6 @@ #include #include #include -#include -#include #include "util-common.h" diff --git a/src/fuzzing/meson.build b/src/fuzzing/meson.build index 9fe120b7..9a8555c2 100644 --- a/src/fuzzing/meson.build +++ b/src/fuzzing/meson.build @@ -9,3 +9,7 @@ fuzz_string_length_sources = files(''' fuzz_alpm_extract_keyid_sources = files(''' fuzz_alpm_extract_keyid.c '''.split()) + +fuzz_parseconfigfile_sources = files(''' + fuzz_parseconfigfile.c +'''.split()) \ No newline at end of file