fuzzing: small improvements for ipc3 and ipc4#10819
Open
tmleman wants to merge 6 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves the native POSIX IPC fuzzing harness for SOF (IPC3 and IPC4) to increase coverage and avoid masking firmware bugs, and it includes two IPC4-side bounds checks uncovered by fuzzing.
Changes:
- POSIX fuzz harness: fix fuzz buffer extern typing, align hostbox sizing with
SOF_IPC_MSG_MAX_SIZE, and correct mailbox base macros to use byte-pointer arithmetic. - POSIX fuzz harness: mirror fuzz input into
MAILBOX_HOSTBOXso IPC handlers that read directly from the hostbox see fuzzed payload bytes. - IPC4 firmware hardening: reject oversized pipeline extension payloads and bound-check multi-pipeline
SET_PIPELINE_STATEcounts.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/platform/posix/ipc.c | Updates fuzz externs and mirrors fuzz data into the hostbox for better IPC3/IPC4 handler coverage. |
| src/platform/posix/include/platform/lib/memory.h | Sizes MAILBOX_HOSTBOX from SOF_IPC_MSG_MAX_SIZE and fixes mailbox base macros to be byte-addressed. |
| src/platform/posix/fuzz.c | Aligns fuzz buffer assignment/comment with the updated extern typing. |
| src/ipc/ipc4/helper.c | Adds an early return to reject pipeline ext payload larger than the hostbox. |
| src/ipc/ipc4/handler-user.c | Adds a mailbox-size-based cap on multi-pipeline pipelines_count to prevent OOB reads. |
lgirdwood
approved these changes
May 28, 2026
softwarecki
approved these changes
May 28, 2026
The fuzzer entry point in src/platform/posix/fuzz.c defines the shared staging symbols as: const uint8_t *posix_fuzz_buf; size_t posix_fuzz_sz; but src/platform/posix/ipc.c forward-declared them as extern uint8_t *posix_fuzz_buf, posix_fuzz_sz; Match the definitions in ipc.c and drop the now-unnecessary cast in fuzz.c. Also fix the stale 'native_fuzz_buf' reference in the doc comment - the symbol was renamed long ago. No functional change is intended on testcases whose size happens to fit in 8 bits; longer inputs (the common case for IPC4 large_config payloads) were previously being silently truncated. Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
The POSIX fuzzing platform hard-codes MAILBOX_HOSTBOX_SIZE to 1024 bytes, which is smaller than the IPC4 maximum message size (SOF_IPC_MSG_MAX_SIZE = 0x1000 = 4096 bytes). This is too small to hold the full IPC4 message envelope and blocks the harness from populating the hostbox with realistic fuzz payload for IPC4 paths that read from MAILBOX_HOSTBOX_BASE. It is also a latent overflow: ipc_platform_do_cmd() in posix/ipc.c calls memcpy(posix_hostbox, comp_data, SOF_IPC_MSG_MAX_SIZE) on the IPC3 path. Today this is safe only because IPC3 SOF_IPC_MSG_MAX_SIZE is 384, but any Kconfig change that grows that value would write past the end of the 1024-byte posix_hostbox array. Derive MAILBOX_HOSTBOX_SIZE from SOF_IPC_MSG_MAX_SIZE so the storage always matches the maximum framed message. The posix_hostbox array declaration in posix.c is sized via the same macro and tracks automatically. No behaviour change for existing IPC3 flows. Prepares the harness for a follow-up commit that copies IPC4 fuzz payload into the hostbox so large_config / set_dx / pipeline-state-data handlers see meaningful input. Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
c9e2c27 to
0998622
Compare
On real hardware (and in the IPC3 harness path) the host kernel deposits the IPC payload into the hostbox shared-memory region before the DSP firmware is signalled. Many IPC4 handlers consume their payload by reading from MAILBOX_HOSTBOX_BASE directly -- for example LARGE_CONFIG_SET / LARGE_CONFIG_GET, vendor config, SET_DX and SET_PIPELINE_STATE in sof/src/ipc/ipc4/handler-user.c and ipc/ipc4/handler-kernel.c. Until now the posix fuzz harness only populated the IPC3 hostbox; in IPC4 builds the region stayed zero-filled, so those handlers either rejected the message early or operated on uninitialised data instead of on the fuzzer-controlled bytes. Lift the existing mailbox mirror copy out of the IPC3-only branch so it runs for both major versions. posix_hostbox is sized to SOF_IPC_MSG_MAX_SIZE (see Commit "fuzz: posix: size MAILBOX_HOSTBOX from SOF_IPC_MSG_MAX_SIZE"), so the copy length is correct for both targets. Update the function comment to record the new contract. This immediately exposes additional reachable code in the IPC4 build (payload decoders that previously saw only zeros) without affecting IPC3 behaviour. Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
On every other SOF platform, MAILBOX_HOSTBOX_BASE, MAILBOX_DSPBOX_BASE, MAILBOX_STREAM_BASE and MAILBOX_TRACE_BASE expand to a byte address (an integer literal or SRAM_INBOX_BASE), so the generic mailbox API in sof/src/include/sof/lib/mailbox.h can do plain byte arithmetic -- `MAILBOX_HOSTBOX_BASE + offset` and `memcpy(_s)(..., bytes)` -- and land on the intended byte. On POSIX, the bases were defined as `(&posix_hostbox[0])` etc., i.e. plain `uint32_t *` expressions. Pointer arithmetic on a `uint32_t *` scales the addend by `sizeof(uint32_t) == 4`, so `MAILBOX_HOSTBOX_BASE + offset` silently addressed byte `offset * 4`, four times further into the buffer than the API contract. This was latent for years because MAILBOX_HOSTBOX_SIZE was hard-coded to 1024 on POSIX while the largest byte offset used through mailbox_hostbox_read() in IPC3 mailbox_validate() (offset = 8, bytes = SOF_IPC_MSG_MAX_SIZE - 8 = 376) stays within 32 + 376 = 408 bytes, comfortably under 1024. After commit "fuzz: posix: size MAILBOX_HOSTBOX from SOF_IPC_MSG_MAX_SIZE" (384 in IPC3 builds, 4096 in IPC4 builds), the scaled IPC3 read overruns the now exactly right-sized backing buffer by 24 bytes, which AddressSanitizer catches as a global-buffer-overflow inside libc memcpy called from mailbox_hostbox_read() -> memcpy_s(). Reproducer (with the new 2-byte framing): two-byte fuzz input "\x80\x01" (msgsz=384, header-only message). Cast each base to `(uint8_t *)` so byte-offset arithmetic is honoured and the macro semantics match every other platform. The `uint32_t[]` backing storage is kept for natural alignment; only how the macro exposes that storage changes. Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
ipc4_create_pipeline_payload_decode() reads pipeline extension objects out of the hostbox region. The function already validates that `size = hdr->payload_words * 4` is at least `sizeof(*hdr)`, but the symmetric upper bound check against MAILBOX_HOSTBOX_SIZE was emitting tr_err() and continuing. Once the loop is entered, every per-object bounds check at lines 290 and 299 is expressed relative to the attacker-controlled `size`, so a payload header that claims `payload_words` significantly larger than the mailbox lets the decoder walk `obj` arbitrarily far past the end of MAILBOX_HOSTBOX_BASE while dereferencing `obj->object_words` and `obj->object_id`. This was unreachable on real hardware because the host kernel is trusted to bound the payload, and unreachable in the SOF fuzz harness until commit "fuzz: posix: mirror IPC4 payload into MAILBOX_HOSTBOX" wired the fuzz-controlled bytes into the hostbox. A 60 s libFuzzer/ASan campaign with the IPC4 dictionary then surfaced a reproducible global-buffer-overflow at helper.c:298 (READ of size 4 at `posix_hostbox + 4096`). Convert the existing warning into a hard rejection so the decoder returns -EINVAL before entering the object-walk loop. Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
For multi_ppl=1, ipc4_set_pipeline_state() takes pipelines_count straight from the host mailbox and uses it as the ppl_id[] loop bound, with no validation against the mailbox size. The IPC4 fuzzer reached this path with a 6-byte input that decodes to type=SOF_IPC4_GLB_SET_PIPELINE_STATE, multi_ppl=1 and a count field that easily exceeds MAILBOX_HOSTBOX. Once an earlier testcase had created a matching pipeline, the ppl_id[i] read walked past the end of the hostbox and AddressSanitizer reported a heap-buffer overflow. Cap pipelines_count at what the hostbox can actually hold and reject oversized requests with IPC4_ERROR_INVALID_PARAM, logging the offending count via ipc_cmd_err() for parity with the surrounding handlers. Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fuzzer improvements – part 1
First batch of improvements to the SOF IPC fuzzer harness, together with the SOF-side fixes that fuzzing uncovered along the way. The goal of this part is to land the least invasive changes that immediately improve coverage and stop the harness from hiding real bugs, before any of the larger refactors that will follow in later parts.
A tracking issue with the full roadmap will be opened separately.
Changes
Harness / coverage:
platform: posix: fix extern type mismatch for posix_fuzz_buf/szfuzz: posix: size MAILBOX_HOSTBOX from SOF_IPC_MSG_MAX_SIZEfuzz: posix: mirror IPC4 payload into MAILBOX_HOSTBOXplatform: posix: fix MAILBOX_*_BASE byte-pointer unitsSOF fixes surfaced by the fuzzer:
ipc4: helper: reject pipeline ext payload larger than hostboxipc4: handler: bounds-check multi-pipeline SET_PIPELINE_STATE countSee individual commit messages for rationale and reproduction details.