sandbox: Add libfuzzer integration

Add an implementation of LLVMFuzzerTestOneInput() that starts the
sandbox on a secondary thread and exposes a function to synchronize the
generation of fuzzing inputs with their consumption by the sandbox.

Signed-off-by: Andrew Scull <ascull@google.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Andrew Scull 2022-05-30 10:00:11 +00:00 committed by Tom Rini
parent 001c39a196
commit d9962b12f2
3 changed files with 98 additions and 0 deletions

View file

@ -19,6 +19,9 @@ SANITIZERS :=
ifdef CONFIG_ASAN
SANITIZERS += -fsanitize=address
endif
ifdef CONFIG_FUZZ
SANITIZERS += -fsanitize=fuzzer
endif
KBUILD_CFLAGS += $(SANITIZERS)
cmd_u-boot__ = $(CC) -o $@ -Wl,-T u-boot.lds $(u-boot-init) \

View file

@ -8,6 +8,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <getopt.h>
#include <setjmp.h>
#include <signal.h>
@ -26,6 +27,7 @@
#include <linux/compiler_attributes.h>
#include <linux/types.h>
#include <asm/fuzzing_engine.h>
#include <asm/getopt.h>
#include <asm/main.h>
#include <asm/sections.h>
@ -1003,7 +1005,75 @@ void os_relaunch(char *argv[])
os_exit(1);
}
#ifdef CONFIG_FUZZ
static void *fuzzer_thread(void * ptr)
{
char cmd[64];
char *argv[5] = {"./u-boot", "-T", "-c", cmd, NULL};
const char *fuzz_test;
/* Find which test to run from an environment variable. */
fuzz_test = getenv("UBOOT_SB_FUZZ_TEST");
if (!fuzz_test)
os_abort();
snprintf(cmd, sizeof(cmd), "fuzz %s", fuzz_test);
sandbox_main(4, argv);
os_abort();
return NULL;
}
static bool fuzzer_initialized = false;
static pthread_mutex_t fuzzer_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t fuzzer_cond = PTHREAD_COND_INITIALIZER;
static const uint8_t *fuzzer_data;
static size_t fuzzer_size;
int sandbox_fuzzing_engine_get_input(const uint8_t **data, size_t *size)
{
if (!fuzzer_initialized)
return -ENOSYS;
/* Tell the main thread we need new inputs then wait for them. */
pthread_mutex_lock(&fuzzer_mutex);
pthread_cond_signal(&fuzzer_cond);
pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex);
*data = fuzzer_data;
*size = fuzzer_size;
pthread_mutex_unlock(&fuzzer_mutex);
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
static pthread_t tid;
pthread_mutex_lock(&fuzzer_mutex);
/* Initialize the sandbox on another thread. */
if (!fuzzer_initialized) {
fuzzer_initialized = true;
if (pthread_create(&tid, NULL, fuzzer_thread, NULL))
os_abort();
pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex);
}
/* Hand over the input. */
fuzzer_data = data;
fuzzer_size = size;
pthread_cond_signal(&fuzzer_cond);
/* Wait for the inputs to be finished with. */
pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex);
pthread_mutex_unlock(&fuzzer_mutex);
return 0;
}
#else
int main(int argc, char *argv[])
{
return sandbox_main(argc, argv);
}
#endif

View file

@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2022 Google, Inc.
* Written by Andrew Scull <ascull@google.com>
*/
#ifndef __ASM_FUZZING_ENGINE_H
#define __ASM_FUZZING_ENGINE_H
/** Function to get fuzzing engine input data. */
/**
* sandbox_fuzzing_engine_get_input() - get an input from the sandbox fuzzing
* engine
*
* The function will return a pointer to the input data and the size of the
* data pointed to. The pointer will remain valid until the next invocation of
* this function.
*
* @data: output pointer to input data
* @size output size of input data
* Return: 0 if OK, -ve on error
*/
int sandbox_fuzzing_engine_get_input(const uint8_t **data, size_t *size);
#endif /* __ASM_FUZZING_ENGINE_H */