sample fuzzer: Move fuzzer specific code to sample and fix for native_sim

Move the LLVM fuzzing specific code out of the board main
file and into the sample.
That way we avoid needing to duplicate it for native_sim and
avoid having a very adhoc interface between the fuzzer test
and runner code.

Also ensure it works for native_sim and not just native_posix

Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
This commit is contained in:
Alberto Escolar Piedras 2024-04-11 11:56:30 +02:00 committed by Johan Hedberg
commit f5553004b0
3 changed files with 52 additions and 39 deletions

View file

@ -178,6 +178,7 @@ endif()
if(CONFIG_ARCH_POSIX_LIBFUZZER)
list(APPEND LLVM_SANITIZERS "fuzzer")
target_compile_options(native_simulator INTERFACE "-DNSI_NO_MAIN=1")
if(NOT CONFIG_64BIT)
# On i386, libfuzzer seems to dynamically relocate the binary, so
# we need to emit PIC code. This limitation is undocumented and

View file

@ -118,40 +118,4 @@ int main(int argc, char *argv[])
return 1; /* LCOV_EXCL_LINE */
}
#else /* CONFIG_ARCH_POSIX_LIBFUZZER */
const uint8_t *posix_fuzz_buf;
size_t posix_fuzz_sz;
/**
* Entry point for fuzzing (when enabled). Works by placing the data
* into two known symbols, triggering an app-visible interrupt, and
* then letting the OS run for a fixed amount of time (intended to be
* "long enough" to handle the event and reach a quiescent state
* again)
*/
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz)
{
static bool posix_initialized;
if (!posix_initialized) {
posix_init(0, NULL);
posix_initialized = true;
}
/* Provide the fuzz data to Zephyr as an interrupt, with
* "DMA-like" data placed into posix_fuzz_buf/sz
*/
posix_fuzz_buf = data;
posix_fuzz_sz = sz;
hw_irq_ctrl_set_irq(CONFIG_ARCH_POSIX_FUZZ_IRQ);
/* Give the OS time to process whatever happened in that
* interrupt and reach an idle state.
*/
posix_exec_for(k_ticks_to_us_ceil64(CONFIG_ARCH_POSIX_FUZZ_TICKS));
return 0;
}
#endif

View file

@ -4,6 +4,19 @@
#include <zephyr/kernel.h>
#include <string.h>
#include <zephyr/irq.h>
#include <irq_ctrl.h>
#if defined(CONFIG_BOARD_NATIVE_SIM)
#include <nsi_cpu_if.h>
#include <nsi_main_semipublic.h>
#elif defined(CONFIG_BOARD_NATIVE_POSIX)
/* Note: native_posix will be deprecated soon */
extern void posix_init(int argc, char *argv[]);
extern void posix_exec_for(uint64_t us);
#define nsi_init posix_init
#define nsi_exec_for posix_exec_for
#else
#error "Platform not supported"
#endif
/* Fuzz testing is coverage-based, so we want to hide a failure case
* (a write through a null pointer in this case) down inside a call
@ -49,8 +62,8 @@ GEN_CHECK(5, 6)
GEN_CHECK(6, 0)
/* Fuzz input received from LLVM via "interrupt" */
extern const uint8_t *posix_fuzz_buf;
extern size_t posix_fuzz_sz;
static const uint8_t *fuzz_buf;
static size_t fuzz_sz;
K_SEM_DEFINE(fuzz_sem, 0, K_SEM_MAX_LIMIT);
@ -76,7 +89,42 @@ int main(void)
/* Execute the fuzz case we got from LLVM and passed
* through an interrupt to this thread.
*/
check0(posix_fuzz_buf, posix_fuzz_sz);
check0(fuzz_buf, fuzz_sz);
}
return 0;
}
/**
* Entry point for fuzzing. Works by placing the data
* into two known symbols, triggering an app-visible interrupt, and
* then letting the simulator run for a fixed amount of time (intended to be
* "long enough" to handle the event and reach a quiescent state
* again)
*/
#if defined(CONFIG_BOARD_NATIVE_SIM)
NATIVE_SIMULATOR_IF /* We expose this function to the final runner link stage*/
#endif
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz)
{
static bool runner_initialized;
if (!runner_initialized) {
nsi_init(0, NULL);
runner_initialized = true;
}
/* Provide the fuzz data to the embedded OS as an interrupt, with
* "DMA-like" data placed into native_fuzz_buf/sz
*/
fuzz_buf = (void *)data;
fuzz_sz = sz;
hw_irq_ctrl_set_irq(CONFIG_ARCH_POSIX_FUZZ_IRQ);
/* Give the OS time to process whatever happened in that
* interrupt and reach an idle state.
*/
nsi_exec_for(k_ticks_to_us_ceil64(CONFIG_ARCH_POSIX_FUZZ_TICKS));
return 0;
}