Crash exec_result_code can be overwritten by the normal sync page_not_found path before host samling, causing real crashes to be reported as regular
- Dominant language
- Makefile
- Stars
- 814
- Forks
- 109
- PR merge metrics
- No merged PRs in 30d
Description
Hi,
I observed a real crash misclassification in `kafl.qemu` that appears to come from the upstream result handoff logic.
This is not only a source-level concern: I instrumented the QEMU/Nyx paths locally and directly observed a real `rc_crash` result being overwritten with `rc_success` before the host fuzzer sampled it.
## Observed behavior
A target reliably triggered a real panic/crash path, but the input was sometimes reported to the fuzzer as `regular` instead of `crash`.
After adding tracing around the aux-buffer result flow, I observed this sequence:
1. panic path entered
2. `exec_result_code` set to `rc_crash`
3. reload completed
4. before the next host-visible sync point, `exec_result_code` was overwritten from `rc_crash` to `rc_success`
5. the Python worker then sampled `success` and classified the input as `regular`
## Directly observed overwrite path
The overwrite I observed was:
- terminal result written in the panic/crash path
- then overwritten in the next normal sync path by `page_not_found` handling
In other words, this was not a hypothetical overwrite candidate.
I directly observed:
- `crash -> success`
- at the `synchronization_lock()/page_not_found` path
- before host sampling
## Why this happens
### 1. Host sampling is delayed
In `kafl.fuzzer`, the host does not continuously observe the aux buffer.
It only reads the result when QEMU reaches the next control-socket sync boundary.
Relevant logic is in:
- `kafl_fuzzer/worker/qemu.py`
- `run_qemu()`
- `send_payload()`
So once a terminal result is written, it must remain stable until the next host-visible sync point.
### 2. Crash path writes the result before host sampling
In upstream `kafl.qemu`:
- `handle_hypercall_kafl_panic()`
- `synchronization_lock_crash_found()`
The panic path writes `rc_crash`, performs reload, and returns.
The host does not sample the aux buffer at that exact point.
### 3. The aux result uses a single mutable `exec_result_code` slot
Multiple paths write directly into the same `exec_result_code` byte, including:
- `set_crash_auxiliary_result_buffer()`
- `set_timeout_auxiliary_result_buffer()`
- `set_asan_auxiliary_result_buffer()`
- `set_success_auxiliary_result_buffer()`
So the crash result is not latched.
### 4. The next normal sync path can overwrite it
In the run I traced, the overwrite happened in:
- `synchronization_lock()`
- specifically the `synchronization_check_page_not_found()` / `page_not_found` handling path
That path wrote `success` before the host sampled the earlier crash result.
## Why I think this is an upstream bug
The implementation relies on the assumption that once a terminal result is written, it will still be present when the host reads it later.
But in the current structure:
- terminal result is written first
- host sampling happens later
- normal sync code can still write into the same result slot
That makes the crash-report handoff non-atomic with respect to host observation.
## Expected behavior
If the current execution has already been classified as `crash`, the host should not later observe that same execution as `regular`.
Once `exec_result_code` becomes terminal for an execution, later non-terminal sync logic should not downgrade it before host sampling.
## Suggested fix direction
A robust fix would be:
1. give terminal results (`crash`, `timeout`, `asan`, etc.) a dedicated handoff path,
2. record `exec_done` / runtime / dirty-page metadata there,
3. perform the host `PING`/wait handshake immediately for that terminal result,
4. only reset the result slot after host ACK,
5. prevent normal sync paths from overwriting an already-terminal `exec_result_code`.
## Practical impact
This can cause real crashes to be misclassified as `regular`, depending on the post-reload sync flow.
If useful, I can also provide a minimal patch that fixes this by preserving terminal results until host handoff and guarding the normal sync overwrite path.
Thank you for reading ! :)
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.