Skip to content

Commit 033ccdc

Browse files
committed
platform/posix: Port fuzzer to upstream "native_sim" board
The older native_posix board is being deprecated, use native_sim, which is the future-proof API. In theory this should be as simple as just swapping the board name at the west level, but there are a few changes: The C API is broadly identical between the two, modulo some prefix renaming. Unfortunately linkage is more of a hassle, as the fuzzing framework inverts the sense of "entry point" and causes some trouble with the way native_sim does its two-stage link. We have to add some hackery: 1. Make sure the fuzz entry point doesn't get dropped during the initial zephyr.elf link, as it calls OS/sim layer and not the reverse. 2. Force it to be a global symbol in the final stage, so it can be seen by the code in libfuzzer that needs to call it (normally all Zephyr-side symbols are forced to be library-private to prevent collisions with the global Linux/glibc namespace environment) Signed-off-by: Andy Ross <andyross@google.com>
1 parent 2aaee2e commit 033ccdc

File tree

4 files changed

+28
-7
lines changed

4 files changed

+28
-7
lines changed

scripts/fuzz.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ with the -b option.
3434
3535
Simple wrapper around a libfuzzer test run, as much for
3636
documentation as direct use. The idea here is really simple: build
37-
for the Zephyr "native_posix" board (which is a just a x86
37+
for the Zephyr "native_sim" board (which is a just a x86
3838
executable for the build host, not an emulated device) and run the
3939
resulting zephyr.exe file. This specifies a "fuzz_corpus" directory
4040
to save the seeds that produce useful coverage output for use in
@@ -124,7 +124,7 @@ main()
124124
(set -x
125125
# When passing conflicting -DVAR='VAL UE1' -DVAR='VAL UE2' to CMake,
126126
# the last 'VAL UE2' wins. Previous ones are silently ignored.
127-
west build -d build-fuzz -b native_posix "$SOF_TOP"/app/ -- \
127+
west build -d build-fuzz -b native_sim "$SOF_TOP"/app/ -- \
128128
"${fuzz_configs[@]}" "$@"
129129
)
130130

src/platform/posix/fuzz.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
#include <irq_ctrl.h>
1010
#include <zephyr/sys/time_units.h>
1111

12-
/* Zephyr arch APIs, not in a header (native_sim has them though) */
13-
void posix_init(int argc, char *argv[]);
14-
void posix_exec_for(uint64_t us);
12+
/* Zephyr arch APIs, not in a header */
13+
void nsi_init(int argc, char *argv[]);
14+
void nsi_exec_for(uint64_t us);
1515

1616
const uint8_t *posix_fuzz_buf;
1717
size_t posix_fuzz_sz;
@@ -28,7 +28,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz)
2828
static bool runner_initialized;
2929

3030
if (!runner_initialized) {
31-
posix_init(0, NULL);
31+
nsi_init(0, NULL);
3232
runner_initialized = true;
3333
}
3434

@@ -42,6 +42,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz)
4242
/* Give the OS time to process whatever happened in that
4343
* interrupt and reach an idle state.
4444
*/
45-
posix_exec_for(k_ticks_to_us_ceil64(CONFIG_ZEPHYR_POSIX_FUZZ_TICKS));
45+
nsi_exec_for(k_ticks_to_us_ceil64(CONFIG_ZEPHYR_POSIX_FUZZ_TICKS));
4646
return 0;
4747
}

src/platform/posix/posix.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ __asm__(".globl _trace_ctx_start\n"
3333
".globl _trace_ctx_end\n"
3434
"_trace_ctx_end:\n");
3535

36+
/* Sort of a kluge: this is an app-provided symbol, Zephyr doesn't
37+
* know about it. But it's the ENTRY POINT of the binary, so SOF
38+
* doesn't ever reference or call it either. It therefore gets
39+
* dropped by the initial link of zephyr.elf, so isn't present anymore
40+
* in the final link vs. the native_sim runner to link vs. the
41+
* framework code in libfuzzer. Stash its address meaninglessly just
42+
* to be sure the symbol gets referenced.
43+
*/
44+
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz);
45+
void *native_sim_ptr_save;
46+
3647
struct ipc_data_host_buffer *ipc_platform_get_host_buffer(struct ipc *ipc)
3748
{
3849
return NULL;
@@ -81,6 +92,8 @@ int platform_init(struct sof *sof)
8192
posix_dma_init(sof);
8293
ipc_init(sof);
8394

95+
native_sim_ptr_save = LLVMFuzzerTestOneInput;
96+
8497
return 0;
8598
}
8699

zephyr/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,14 @@ zephyr_library_sources_ifdef(CONFIG_ZEPHYR_POSIX
401401
${SOF_PLATFORM_PATH}/posix/fuzz.c
402402
)
403403

404+
# When building the fuzzer, the LLVMFuzzerTestOneInput() entry point
405+
# (which is defined here in the app) must be exposed to the secondary
406+
# native_sim "runner" linkage step, which normally hides all
407+
# Zephyr-side symbols to protect against collisions. Somewhat opaque
408+
# cmake interface to this, alas.
409+
set_property(TARGET native_simulator APPEND PROPERTY
410+
LOCALIZE_EXTRA_OPTIONS "--globalize-symbol=LLVMFuzzerTestOneInput")
411+
404412
zephyr_library_sources_ifdef(CONFIG_LIBRARY
405413
${SOF_PLATFORM_PATH}/library/platform.c
406414
${SOF_PLATFORM_PATH}/library/lib/dai.c

0 commit comments

Comments
 (0)