Commit ffda587
platform: posix: run fuzz teardown in thread context
The IPC fuzzer aborts partway through a run with:
programming error: nsif_cpu0_irq_raised_from_sw called from a HW
model thread
The between-testcase topology teardown (posix_ipc_teardown(), added in
commit d53a762 "platform: posix: tear down IPC topology between fuzz
testcases") was invoked from posix_fuzz_case_begin(), which executes on
the libFuzzer driver thread. On native_sim that thread is a "HW model"
context: the simulated CPU is halted (posix_is_cpu_running() == false)
whenever execution is outside nsi_exec_for(). The teardown frees
pipelines and cancels scheduler tasks, taking Zephyr spinlocks (and the
LL scheduler's k_mutex). Releasing a spinlock reaches arch_irq_unlock()
-> hw_irq_ctrl_change_lock(); if a HW interrupt is pending there it is
vectored synchronously via nsif_cpu0_irq_raised_from_sw(), which aborts
because the CPU is not running.
gdb confirms the pending interrupt is the system tick (irq_status == 0x1,
IRQ 0 = TIMER_TICK_IRQ), delivered from pipeline_posn_unlock() ->
k_spin_unlock() inside pipeline_free().
Running the teardown on the driver thread was always unsafe, but only
became reproducible after a Zephyr update that converted the native_sim
system timer from a periodic tick to a one-shot, fully tickless model
(drivers/timer/native_sim_timer.c "use the generic timer core", plus the
native_simulator hwtimer_set_tick_one_shot() addition). hwtimer_enable()
previously armed a periodic tick on a fixed grid and no tick happened to
be pending at the between-testcase boundary; the one-shot core now arms
the tick at the exact next timeout deadline, which lands at/after an
nsi_exec_for() quantum boundary. nsi_exec_for() stops on its time budget,
so it returns after the tick fires but before the CPU services it,
leaving TIMER_TICK_IRQ pending exactly when the teardown runs.
Fix this by running the teardown where SOF frees pipelines during normal
operation: the EDF workqueue thread. posix_fuzz_case_begin() now only
sets a flag; ipc_platform_do_cmd() consumes it and runs
posix_ipc_teardown() before this testcase's first command. There the CPU
is running (a pending tick is delivered legitimately) and blocking
primitives such as k_mutex are valid.
Clearing the pending interrupt on the driver thread was rejected as an
alternative: dropping the tick leaves the one-shot timer with no armed
deadline (next_timer_time == NSI_NEVER), so the simulator exits via
nsi_exit() and libFuzzer reports "fuzz target exited".
Validated with the IPC4 seed corpus (342142 runs) and the IPC3 seed
corpus (111135 runs); both complete cleanly with no crash artifacts.
Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>1 parent 43e40ff commit ffda587
1 file changed
Lines changed: 25 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
42 | 47 | | |
43 | 48 | | |
44 | 49 | | |
| |||
194 | 199 | | |
195 | 200 | | |
196 | 201 | | |
197 | | - | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
198 | 211 | | |
199 | 212 | | |
200 | 213 | | |
| |||
362 | 375 | | |
363 | 376 | | |
364 | 377 | | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
365 | 389 | | |
366 | 390 | | |
367 | 391 | | |
| |||
0 commit comments