From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH 12/21] Add fuzzing infrastructure
Date: Thu, 5 Jun 2025 13:35:21 +0200 [thread overview]
Message-ID: <20250605113530.2076990-13-a.fatoum@pengutronix.de> (raw)
In-Reply-To: <20250605113530.2076990-1-a.fatoum@pengutronix.de>
To aid in detection of memory safety issues in security-critical code
add support for libfuzzer along with a first test exercising the
hexstring format specifier of printf.
More useful tests will follow. In addition to libfuzzer, there's also a
fuzz command that passes a fixed input to a buffer. This can be useful
when inspecting a crashing input from the barebox command line.
Note that libfuzzer is in maintenance-mode unfortunately, but it
requiring only LLVM support makes it very convenient to use, so it's a
good first step.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/sandbox/Kconfig | 5 ++
arch/sandbox/Makefile | 11 ++-
arch/sandbox/os/common.c | 137 +++++++++++++++++++++++++++++-
commands/Makefile | 1 +
commands/fuzz.c | 118 +++++++++++++++++++++++++
common/Kconfig | 5 ++
common/startup.c | 1 +
images/.gitignore | 1 +
images/Makefile.sandbox | 16 +++-
include/asm-generic/barebox.lds.h | 13 ++-
include/fuzz.h | 70 +++++++++++++++
lib/Makefile | 1 +
lib/fuzz.c | 79 +++++++++++++++++
lib/vsprintf.c | 15 ++++
scripts/Kconfig.include | 1 +
scripts/clang-runtime-dir.sh | 19 +++++
test/Kconfig | 37 ++++++++
17 files changed, 523 insertions(+), 7 deletions(-)
create mode 100644 commands/fuzz.c
create mode 100644 include/fuzz.h
create mode 100644 lib/fuzz.c
create mode 100755 scripts/clang-runtime-dir.sh
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index 7d8f88474781..5c7948b215cf 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -96,4 +96,9 @@ config HAVE_LIBFTDI
config SDL
bool
+config SANDBOX_LINK_CXX
+ def_bool FUZZ_EXTERNAL
+ help
+ Link with CXX instead of CC to support C++ static libraries.
+
endmenu
diff --git a/arch/sandbox/Makefile b/arch/sandbox/Makefile
index 2db1cb648a2b..6566cd563ed8 100644
--- a/arch/sandbox/Makefile
+++ b/arch/sandbox/Makefile
@@ -67,6 +67,15 @@ ifeq ($(CONFIG_UBSAN),y)
SANDBOX_LIBS += -fsanitize=undefined
endif
+ifeq ($(CONFIG_FUZZ_EXTERNAL),y)
+LIBARCH-y = $(UNAME_M)
+LIBARCH-$(CONFIG_SANDBOX_LINUX_I386) = i386
+
+KBUILD_CPPFLAGS += -fsanitize=fuzzer-no-link
+SANDBOX_LIBS += -Wl,-Bstatic -L"$(CONFIG_CLANG_RUNTIME_DIR)" \
+ -lclang_rt.fuzzer_no_main-$(LIBARCH-y) -Wl,-Bdynamic
+endif
+
ifeq ($(CONFIG_SANDBOX_LINUX_I386),y)
KBUILD_CFLAGS += -m32
KBUILD_LDFLAGS += -m elf_i386
@@ -80,7 +89,7 @@ SANDBOX_PROPER2PBL_GLUE_SYMS := \
strsep_unescaped start_barebox linux_get_stickypage_path \
stickypage mem_malloc_init \
barebox_register_filedev barebox_register_dtb barebox_register_console \
- barebox_errno barebox_loglevel
+ barebox_errno barebox_loglevel call_for_each_fuzz_test setup_external_fuzz
OBJCOPYFLAGS_barebox.o := $(addprefix --keep-global-symbol=, $(SANDBOX_PROPER2PBL_GLUE_SYMS))
diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c
index 3dbe61791ccd..86aaeb24ee3d 100644
--- a/arch/sandbox/os/common.c
+++ b/arch/sandbox/os/common.c
@@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#include <stdbool.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
@@ -54,6 +55,22 @@ int __attribute__((unused)) barebox_loglevel;
extern int barebox_loglevel;
#endif
+#ifdef CONFIG_FUZZ_EXTERNAL
+int call_for_each_fuzz_test(int (*fn)(const char **test));
+int setup_external_fuzz(const char *name,
+ int *argc, char ***argv);
+#else
+static inline int call_for_each_fuzz_test(int (*fn)(const char **test))
+{
+ return 0;
+}
+static inline int setup_external_fuzz(const char *name,
+ int *argc, char ***argv)
+{
+ return -1;
+}
+#endif
+
#define DELETED_OFFSET (sizeof(" (deleted)") - 1)
void __sanitizer_set_death_callback(void (*callback)(void));
@@ -514,6 +531,8 @@ const char *barebox_cmdline_get(void)
static void print_usage(const char*);
#define OPT_LOGLEVEL (CHAR_MAX + 1)
+#define OPT_LIST_FUZZERS (CHAR_MAX + 2)
+#define OPT_FUZZ (CHAR_MAX + 3)
static struct option long_options[] = {
{"help", 0, 0, 'h'},
@@ -529,14 +548,72 @@ static struct option long_options[] = {
{"yres", 1, 0, 'y'},
#ifndef CONFIG_CONSOLE_NONE
{"loglevel", 1, 0, OPT_LOGLEVEL},
+#endif
+#ifdef CONFIG_FUZZ_EXTERNAL
+ {"fuzz", 1, 0, OPT_FUZZ},
+ {"list-fuzzers", 0, 0, OPT_LIST_FUZZERS},
#endif
{0, 0, 0, 0},
};
static const char optstring[] = "hm:i:c:e:d:O:I:B:x:y:";
-ENTRY_FUNCTION(sandbox_main, argc, argv)
+static __attribute__((unused)) int print_fuzz_test_name(const char **test_name)
{
+ printf("%s\n", *test_name);
+ return 0;
+}
+
+static inline size_t str_has_prefix(const char *str, const char *prefix)
+{
+ size_t len = strlen(prefix);
+ return strncmp(str, prefix, len) == 0 ? len : 0;
+}
+
+static char *realpath_alloc(char *path)
+{
+ char *real;
+
+ real = malloc(PATH_MAX);
+ if (!real) {
+ perror("malloc");
+ exit(3);
+ }
+
+ if (!realpath(path, real)) {
+ perror("realpath");
+ exit(EXIT_FAILURE);
+ }
+
+ return real;
+}
+
+static void setup_external_fuzz_with_args(const char *fuzz, int *pargc, char **pargv[])
+{
+ char **argv = *pargv;
+ char *rlpath;
+ int ret;
+
+ rlpath = realpath_alloc(argv[0]);
+
+ asprintf(&argv[optind - 1], "%s/fuzz-%s", dirname(rlpath), fuzz);
+
+ free(rlpath);
+
+ *pargc -= optind - 1;
+ *pargv += optind - 1;
+
+ ret = setup_external_fuzz(fuzz, pargc, pargv);
+ if (ret) {
+ printf("unknown fuzz target '%s'\n", fuzz);
+ exit(ret);
+ }
+}
+
+static int normal_main(int argc, char *argv[])
+{
+ bool skip_opts = false;
+ const char *fuzz = NULL;
void *ram;
int opt, ret, fd, fd2;
int malloc_size = CONFIG_MALLOC_SIZE;
@@ -548,7 +625,7 @@ ENTRY_FUNCTION(sandbox_main, argc, argv)
__sanitizer_set_death_callback(prepare_exit);
#endif
- while (1) {
+ while (!skip_opts) {
option_index = 0;
opt = getopt_long(argc, argv, optstring,
long_options, &option_index);
@@ -589,10 +666,18 @@ ENTRY_FUNCTION(sandbox_main, argc, argv)
case 'y':
sdl_yres = strtoul(optarg, NULL, 0);
break;
+ case OPT_LIST_FUZZERS:
+ call_for_each_fuzz_test(print_fuzz_test_name);
+ exit(0);
+ break;
+ case OPT_FUZZ:
+ skip_opts = true;
+ break;
default:
break;
}
}
+ skip_opts = false;
saved_argv = argv;
@@ -610,7 +695,7 @@ ENTRY_FUNCTION(sandbox_main, argc, argv)
*/
optind = 1;
- while (1) {
+ while (!skip_opts) {
option_index = 0;
opt = getopt_long(argc, argv, optstring,
long_options, &option_index);
@@ -672,6 +757,10 @@ ENTRY_FUNCTION(sandbox_main, argc, argv)
barebox_register_console(fd2, fd);
break;
+ case OPT_FUZZ:
+ fuzz = optarg;
+ skip_opts = true;
+ break;
default:
break;
}
@@ -679,7 +768,10 @@ ENTRY_FUNCTION(sandbox_main, argc, argv)
barebox_register_console(fileno(stdin), fileno(stdout));
- rawmode();
+ if (fuzz)
+ setup_external_fuzz_with_args(fuzz, &argc, &argv);
+ else
+ rawmode();
if (loglevel >= 0)
barebox_loglevel = loglevel;
@@ -690,6 +782,39 @@ ENTRY_FUNCTION(sandbox_main, argc, argv)
return 0;
}
+ENTRY_FUNCTION(sandbox_main, argc, argv)
+{
+ char **args;
+ char *argv0;
+ size_t fuzz_off;
+ char *rlpath;
+
+ tcgetattr(0, &term_orig);
+
+ argv0 = basename(argv[0]);
+ fuzz_off = str_has_prefix(argv0, "fuzz-");
+ if (fuzz_off) {
+ args = malloc((argc + 3) * sizeof(*args));
+ if (!args)
+ exit(3);
+
+ rlpath = realpath_alloc(argv[0]);
+ asprintf(&args[0], "%s/barebox", dirname(rlpath));
+
+ free(rlpath);
+
+ args[1] = "--fuzz";
+ args[2] = argv0 + fuzz_off;
+
+ memcpy(&args[3], &argv[1], argc * sizeof(*args));
+
+ argc += 2;
+ argv = args;
+ }
+
+ return normal_main(argc, argv);
+}
+
#ifdef __PPC__
/* HACK: we need this symbol on PPC, better ask a PPC export about this :) */
char _SDA_BASE_[4096];
@@ -736,6 +861,10 @@ static void print_usage(const char *prgname)
" 6 informational (info)\n"
" 7 debug-level messages (debug)\n"
" 8 verbose debug messages (vdebug)\n"
+#endif
+#ifdef CONFIG_FUZZ_EXTERNAL
+" --fuzz=<test> Run libfuzzer against the <test> target.\n"
+" --list-fuzzers List all available fuzzing test targets.\n"
#endif
, prgname
);
diff --git a/commands/Makefile b/commands/Makefile
index 53337dfb5c2d..603e1a25244c 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -157,6 +157,7 @@ obj-$(CONFIG_CMD_IP_ROUTE_GET) += ip-route-get.o
obj-$(CONFIG_CMD_BTHREAD) += bthread.o
obj-$(CONFIG_CMD_UBSAN) += ubsan.o
obj-$(CONFIG_CMD_SELFTEST) += selftest.o
+obj-$(CONFIG_CMD_FUZZ) += fuzz.o
obj-$(CONFIG_CMD_TUTORIAL) += tutorial.o
obj-$(CONFIG_CMD_STACKSMASH) += stacksmash.o
obj-$(CONFIG_CMD_PARTED) += parted.o
diff --git a/commands/fuzz.c b/commands/fuzz.c
new file mode 100644
index 000000000000..f48032e7e1d9
--- /dev/null
+++ b/commands/fuzz.c
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define pr_fmt(fmt) "fuzz: " fmt
+
+#include <common.h>
+#include <command.h>
+#include <getopt.h>
+#include <fuzz.h>
+#include <libfile.h>
+#include <fs.h>
+
+static const struct fuzz_test *get_fuzz_test(const char *match, bool print)
+{
+ const struct fuzz_test *test;
+ unsigned matches = 0;
+
+ for_each_fuzz_test(test) {
+ if (print) {
+ printf("%s\n", test->name);
+ matches++;
+ }
+
+ if (match && !strcmp(test->name, match))
+ return test;
+
+ }
+
+ if (!matches) {
+ if (match)
+ printf("No fuzz tests matching '%s' found.\n", match);
+ else
+ printf("No fuzz tests registered.\n");
+ }
+
+ return NULL;
+}
+
+static int run_fuzz_test(const char *match, bool list, const u8 *buf, size_t len)
+{
+ const struct fuzz_test *test;
+
+ test = get_fuzz_test(match, list);
+ if (list)
+ return 0;
+ else if (!test)
+ return COMMAND_ERROR;
+
+ return fuzz_test_once(test, buf, len);
+}
+
+static int do_fuzz(int argc, char *argv[])
+{
+ const char *file = NULL;
+ u64 max_size = FILESIZE_MAX;
+ size_t size = 0;
+ const u8 *buf = NULL;
+ void *contents = NULL;
+ bool list = false;
+ int err = 0, opt;
+
+ while((opt = getopt(argc, argv, "ls:f:")) > 0) {
+ switch(opt) {
+ case 'l':
+ list = true;
+ break;
+ case 's':
+ err = kstrtou64(optarg, 0, &max_size);
+ if (err || max_size > SIZE_MAX) {
+ printf("invalid max size\n");
+ return COMMAND_ERROR;
+ }
+ break;
+ case 'f':
+ file = optarg;
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if ((list && argc) || (!list && argc != 1) || (!file && !list))
+ return COMMAND_ERROR_USAGE;
+
+ if (file) {
+ err = read_file_2(file, &size, &contents, max_size);
+ if (err && err != -EFBIG) {
+ printf("error reading file: %m\n");
+ return COMMAND_ERROR;
+ }
+
+ buf = contents;
+ }
+
+ err = run_fuzz_test(argv[0], list, buf, size);
+
+ free(contents);
+ return err;
+}
+
+BAREBOX_CMD_HELP_START(fuzz)
+BAREBOX_CMD_HELP_TEXT("Run barebox fuzz test on fixed input")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-l", "list registered fuzz tests")
+BAREBOX_CMD_HELP_OPT ("-f FILE", "use FILE as fuzz input")
+BAREBOX_CMD_HELP_OPT ("-s SIZE", "read only SIZE bytes from file")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(fuzz)
+ .cmd = do_fuzz,
+ BAREBOX_CMD_DESC("Run fuzz test")
+ BAREBOX_CMD_OPTS("[-ls] -f FILE [test]")
+ BAREBOX_CMD_GROUP(CMD_GRP_MISC)
+ BAREBOX_CMD_HELP(cmd_fuzz_help)
+BAREBOX_CMD_END
diff --git a/common/Kconfig b/common/Kconfig
index 6d41b7048a32..83a0717e76d6 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -18,6 +18,11 @@ config CLANG_VERSION
default $(cc-version) if CC_IS_CLANG
default 0
+config CLANG_RUNTIME_DIR
+ string
+ depends on CC_IS_CLANG
+ default "$(clang-runtime-dir)"
+
config GREGORIAN_CALENDER
bool
diff --git a/common/startup.c b/common/startup.c
index c9e99d47fbd7..c720664689f6 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -44,6 +44,7 @@
#include <bselftest.h>
#include <pbl/handoff-data.h>
#include <libfile.h>
+#include <fuzz.h>
extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[],
__barebox_initcalls_end[];
diff --git a/images/.gitignore b/images/.gitignore
index 20133074bf87..fc464ff2e3cb 100644
--- a/images/.gitignore
+++ b/images/.gitignore
@@ -42,3 +42,4 @@ barebox.sum
*.fit
*.missing-firmware
*.k3img
+fuzz-*
diff --git a/images/Makefile.sandbox b/images/Makefile.sandbox
index 0699a52663ef..ed5d740bc1fb 100644
--- a/images/Makefile.sandbox
+++ b/images/Makefile.sandbox
@@ -3,12 +3,26 @@
SYMLINK_TARGET_barebox = sandbox_main.elf
symlink-$(CONFIG_SANDBOX) += barebox
+fuzzer-$(CONFIG_PRINTF_HEXSTR) += printf
+
ifeq ($(CONFIG_SANDBOX),y)
+ifdef CONFIG_SANDBOX_LINK_CXX
+linker = $(CXX)
+else
+linker = $(CC)
+endif
+
quiet_cmd_elf__ = LD $@
- cmd_elf__ = $(CC) -o $@ $(BAREBOX_LDFLAGS) \
+ cmd_elf__ = $(linker) -o $@ $(BAREBOX_LDFLAGS) \
-Wl,-T,$(pbl-lds) -Wl,--defsym=main=$(2) -Wl,--whole-archive \
$(obj)/../$(BAREBOX_PROPER) $(BAREBOX_PBL_OBJS) -Wl,--no-whole-archive \
-lrt -pthread $(SANDBOX_LIBS) $(LDFLAGS_$(@F))
+ifeq ($(CONFIG_FUZZ_EXTERNAL),y)
+$(foreach fuzzer, $(fuzzer-y), \
+ $(eval SYMLINK_TARGET_fuzz-$(fuzzer) = barebox) \
+ $(eval symlink-y += fuzz-$(fuzzer)))
+endif
+
endif
diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h
index 54817b68fc22..2c0f4da9e5d4 100644
--- a/include/asm-generic/barebox.lds.h
+++ b/include/asm-generic/barebox.lds.h
@@ -118,6 +118,16 @@
KEEP(*(SORT_BY_NAME(.barebox_deep_probe*))) \
__barebox_deep_probe_end = .;
+#ifdef CONFIG_FUZZ
+#define BAREBOX_FUZZ_TESTS \
+ STRUCT_ALIGN(); \
+ __barebox_fuzz_tests_start = .; \
+ KEEP(*(SORT_BY_NAME(.barebox_fuzz_test*))) \
+ __barebox_fuzz_tests_end = .;
+#else
+#define BAREBOX_FUZZ_TESTS
+#endif
+
#ifdef CONFIG_CONSTRUCTORS
#define KERNEL_CTORS() . = ALIGN(8); \
@@ -142,7 +152,8 @@
BAREBOX_DTB \
BAREBOX_PUBLIC_KEYS \
BAREBOX_PCI_FIXUP \
- BAREBOX_DEEP_PROBE
+ BAREBOX_DEEP_PROBE \
+ BAREBOX_FUZZ_TESTS
#if defined(CONFIG_ARCH_BAREBOX_MAX_BARE_INIT_SIZE) && \
CONFIG_ARCH_BAREBOX_MAX_BARE_INIT_SIZE < CONFIG_BAREBOX_MAX_BARE_INIT_SIZE
diff --git a/include/fuzz.h b/include/fuzz.h
new file mode 100644
index 000000000000..35233f90154b
--- /dev/null
+++ b/include/fuzz.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022 Google, Inc.
+ * Written by Andrew Scull <ascull@google.com>
+ */
+
+#ifndef __TEST_FUZZ_H
+#define __TEST_FUZZ_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+/**
+ * struct fuzz_test - Information about a fuzz test
+ *
+ * @name: Name of fuzz test
+ * @func: Function to call to perform fuzz test on an input
+ */
+struct fuzz_test {
+ const char *name; /* must be first member */
+ int (*func)(const uint8_t * data, size_t size);
+};
+
+extern const struct fuzz_test __barebox_fuzz_tests_start;
+extern const struct fuzz_test __barebox_fuzz_tests_end;
+
+#define for_each_fuzz_test(test) \
+ for (test = &__barebox_fuzz_tests_start; \
+ test != &__barebox_fuzz_tests_end; test++)
+
+#if IS_ENABLED(CONFIG_FUZZ) && IN_PROPER
+/**
+ * fuzz_test() - register a fuzz test
+ *
+ * The fuzz test function must return 0 as other values are reserved for future
+ * use.
+ *
+ * @_name: the name of the fuzz test function
+ */
+#define fuzz_test(_name, _func) \
+ static const struct fuzz_test _func##_entry \
+ __ll_elem(.barebox_fuzz_tests_##_func) = { \
+ .name = _name, \
+ .func = _func, \
+ }
+#else
+#define fuzz_test(_name, _func) \
+ static __always_unused void * _unused##_func = _func
+#endif
+
+static inline int fuzz_test_once(const struct fuzz_test *test, const u8 *data, size_t len)
+{
+ return test->func(data, len);
+}
+
+int call_for_each_fuzz_test(int (*fn)(const struct fuzz_test *test));
+
+int setup_external_fuzz(const char *fuzz_name,
+ int *argc, char ***argv);
+
+#ifdef CONFIG_FUZZ
+bool fuzz_external_active(void);
+#else
+static inline bool fuzz_external_active(void)
+{
+ return false;
+}
+#endif
+
+#endif /* __TEST_FUZZ_H */
diff --git a/lib/Makefile b/lib/Makefile
index 370d4f31d45a..e5cd7ae9f762 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_XYMODEM) += xymodem.o
obj-y += unlink-recursive.o
obj-$(CONFIG_STMP_DEVICE) += stmp-device.o
obj-y += wchar.o
+obj-$(CONFIG_FUZZ) += fuzz.o
obj-y += libfile.o
obj-y += bitmap.o
obj-y += gcd.o
diff --git a/lib/fuzz.c b/lib/fuzz.c
new file mode 100644
index 000000000000..084455e365cd
--- /dev/null
+++ b/lib/fuzz.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <fuzz.h>
+#include <string.h>
+#include <common.h>
+
+int call_for_each_fuzz_test(int (*fn)(const struct fuzz_test *test))
+{
+ const struct fuzz_test *test;
+ int ret;
+
+ for_each_fuzz_test(test) {
+ ret = fn(test);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_FUZZ_EXTERNAL
+const u8 *fuzzer_get_data(size_t *len);
+#else
+static inline const u8 *fuzzer_get_data(size_t *len)
+{
+ return NULL;
+}
+#endif
+
+extern int LLVMFuzzerRunDriver(int *argc, char ***argv,
+ int (*cb)(const uint8_t *, size_t));
+
+static const struct fuzz_test *fuzz;
+static int *saved_argc;
+static char ***saved_argv;
+
+static int fuzzer_run(const uint8_t *buf, size_t len)
+{
+ return fuzz_test_once(fuzz, buf, len);
+}
+
+static int fuzz_main(void)
+{
+ int ret = -1;
+
+ if (IS_ENABLED(CONFIG_FUZZ_EXTERNAL)) {
+ ret = LLVMFuzzerRunDriver(saved_argc, saved_argv, fuzzer_run);
+ pr_emerg("libfuzzer unexpectedly ended: %d\n", ret);
+ } else {
+ pr_emerg("libfuzzer not supported in this build\n");
+ }
+
+ return ret;
+}
+
+int setup_external_fuzz(const char *fuzz_name,
+ int *argc, char ***argv)
+{
+ const struct fuzz_test *test;
+
+ saved_argc = argc;
+ saved_argv = argv;
+
+ for_each_fuzz_test(test) {
+ if (streq_ptr(test->name, fuzz_name)) {
+ fuzz = test;
+ barebox_main = fuzz_main;
+ barebox_loglevel = MSG_CRIT;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+bool fuzz_external_active(void)
+{
+ return fuzz != NULL;
+}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index ba87f6c210d2..11be17d8cceb 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -21,6 +21,7 @@
#include <wchar.h>
#include <of.h>
#include <efi.h>
+#include <fuzz.h>
#include <common.h>
#include <pbl.h>
@@ -989,3 +990,17 @@ int asprintf(char **strp, const char *fmt, ...)
return len;
}
EXPORT_SYMBOL(asprintf);
+
+static int __maybe_unused fuzz_printf(const uint8_t *data, size_t size)
+{
+ static bool initialized = false;
+
+ if (!initialized) {
+ printf("initializing\n");
+ initialized = true;
+ }
+
+ printf("%*ph\n", (int)size, data);
+ return 0;
+}
+fuzz_test("printf", fuzz_printf);
diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include
index 55ec8737d0db..93c33d9485b1 100644
--- a/scripts/Kconfig.include
+++ b/scripts/Kconfig.include
@@ -28,6 +28,7 @@ cc-info := $(shell,$(srctree)/scripts/cc-version.sh $(CC))
$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this C compiler is not supported.)
cc-name := $(shell,set -- $(cc-info) && echo $1)
cc-version := $(shell,set -- $(cc-info) && echo $2)
+clang-runtime-dir = $(shell,$(srctree)/scripts/clang-runtime-dir.sh $(CC))
# $(cc-option,<flag>)
# Return y if the compiler supports <flag>, n otherwise
diff --git a/scripts/clang-runtime-dir.sh b/scripts/clang-runtime-dir.sh
new file mode 100755
index 000000000000..65b3028ad04d
--- /dev/null
+++ b/scripts/clang-runtime-dir.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+CC=${1:-${CC}}
+
+if [ "${CC}" = "" ]; then
+ echo "Error: No compiler specified." >&2
+ printf "Usage:\n\t$0 <clang-command>\n" >&2
+ exit 1
+fi
+
+rundir=$("${CC}" --print-runtime-dir 2>/dev/null)
+if [ ! -e "$rundir" ]; then
+ # Workaround https://github.com/llvm/llvm-project/issues/112458
+ guess=$(dirname "$rundir")/linux
+ if [ -e "$guess" ]; then
+ rundir="$guess"
+ fi
+fi
+echo "$rundir"
diff --git a/test/Kconfig b/test/Kconfig
index 958b483ea946..ca2d75c6b025 100644
--- a/test/Kconfig
+++ b/test/Kconfig
@@ -7,4 +7,41 @@ if TEST
source "test/self/Kconfig"
+config FUZZ
+ bool "fuzz tests"
+ help
+ Say y here to add include fuzz tests into barebox.
+ These need to be exercised either via command or
+ by libfuzzer
+
+config FUZZ_EXTERNAL
+ bool "link against libfuzzer"
+ depends on SANDBOX && CC_IS_CLANG
+ help
+ LibFuzzer is an in-process, coverage-guided, evolutionary fuzzing
+ engine. It can be linked against barebox on the sandbox
+ architecture to feed fuzzed inputs into the fuzz tests.
+
+if FUZZ
+
+config CMD_FUZZ
+ bool "fuzz command"
+ depends on COMMAND_SUPPORT
+ default y
+ help
+ Command to run enabled barebox fuzz tests on fixed input.
+ If run without arguments, all tests are run.
+
+ This is mostly useful for debugging, use FUZZ_EXTERNAL
+ to have fuzzed inputs be bed automatically .
+
+ Usage: fuzz [-ls] -f FILE [test]
+
+ Options:
+ -l list registered fuzz tests
+ -f FILE use FILE as fuzz input
+ -s SIZE read only SIZE bytes from file
+
+endif
+
endif
--
2.39.5
next prev parent reply other threads:[~2025-06-05 11:39 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-05 11:35 [PATCH 00/21] sandbox: add libfuzzer-based fuzzing Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 01/21] pbl: add provision for architectures without piggy loader Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 02/21] firmware: make Layerscape FMan firmware proper-only Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 03/21] mci: sdhci: support compiling common SDHCI code for sandbox PBL Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 04/21] kbuild: define and use more generic symlink command Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 05/21] kbuild: collect compatibility symlink creation in symlink-y Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 06/21] kbuild: allow customizing barebox proper binary Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 07/21] sandbox: make available all CONFIG_ symbols to OS glue code Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 08/21] sandbox: switch to using PBL Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 09/21] kbuild: populate non-host CXX variables Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 10/21] string: add fortify source support Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 11/21] sandbox: populate UNAME_M variable Ahmad Fatoum
2025-06-05 11:35 ` Ahmad Fatoum [this message]
2025-06-05 11:35 ` [PATCH 13/21] filetype: add fuzz target Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 14/21] block: mark underlying cdev with DEVFS_IS_BLOCK_DEV Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 15/21] block: add lightweight ramdisk support Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 16/21] fuzz: add support for passing fuzz data as r/o ramdisk Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 17/21] partitions: add partition table parser fuzz target Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 18/21] fdt: add fuzz test Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 19/21] fit: " Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 20/21] Documentation: add LLVM libfuzzer documentation Ahmad Fatoum
2025-06-05 11:35 ` [PATCH 21/21] sandbox: add support for coverage info generation Ahmad Fatoum
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250605113530.2076990-13-a.fatoum@pengutronix.de \
--to=a.fatoum@pengutronix.de \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox