Skip to content

SoC: SOF: Fix control data bounds checking and TOCTOU vulnerabilities#5772

Open
ujfalusi wants to merge 5 commits into
thesofproject:topic/sof-devfrom
ujfalusi:peter/sof/pr/ipcx-control-fixes
Open

SoC: SOF: Fix control data bounds checking and TOCTOU vulnerabilities#5772
ujfalusi wants to merge 5 commits into
thesofproject:topic/sof-devfrom
ujfalusi:peter/sof/pr/ipcx-control-fixes

Conversation

@ujfalusi
Copy link
Copy Markdown
Collaborator

This series fixes several security issues in the SOF IPC3 and IPC4
control data handling paths, found during a security audit of the
bytes/bytes_ext kcontrol put/get operations.

The most critical issue is a heap buffer overflow reachable from
unprivileged userspace via the ALSA TLV kcontrol interface: bounds
checks in bytes_ext_put/get compared user data lengths against
max_size without accounting for the sizeof(struct sof_ipc_ctrl_data)
offset of the flex array within the allocation.

The remaining patches fix TOCTOU issues where the copy size was derived
from stale buffer contents rather than the incoming data, missing
bounds validation of firmware-provided num_elems against the actual
allocation size, and potential integer overflows in size calculations
on 32-bit platforms.

ujfalusi added 5 commits May 12, 2026 14:53
In sof_ipc4_bytes_put(), the copy size is derived from the old
data->size in the buffer rather than the incoming new data's size
field from ucontrol. If the new data has a different size, the copy
uses the wrong length: it may truncate valid data or copy stale bytes.

Fix by validating and using the incoming data's sof_abi_hdr.size from
ucontrol before copying.

Fixes: a062c88 ("ASoC: SOF: ipc4-control: Add support for bytes control get and put")
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
In sof_ipc3_control_update(), the expected_size calculation uses
firmware-provided cdata->num_elems in arithmetic that could overflow
on 32-bit platforms, wrapping to a small value. This would allow the
cdata->rhdr.hdr.size comparison to pass with mismatched sizes,
potentially leading to out-of-bounds access in snd_sof_update_control.

Use check_mul_overflow() and check_add_overflow() to detect and reject
overflowed size calculations.

Fixes: 10f461d ("ASoC: SOF: Add IPC3 topology control ops")
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
In snd_sof_update_control(), firmware-provided cdata->num_elems is
checked against local_cdata->data->size but never against the actual
allocation size. If local_cdata->data->size was previously set to an
inconsistent value, the memcpy could write past the allocated buffer.

Add a bounds check to ensure num_elems fits within the available space
in the ipc_control_data allocation before copying.

Fixes: 10f461d ("ASoC: SOF: Add IPC3 topology control ops")
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
In sof_ipc3_bytes_put(), the size used for the memcpy is derived from
the old data->size already in the buffer, not the incoming new data's
size field. If the new data has a different size, the copy length is
wrong: it may truncate valid data or copy stale bytes.

Similarly, sof_ipc3_bytes_get() checks data->size against max_size
without accounting for the sizeof(struct sof_ipc_ctrl_data) offset
of the flex array within the allocation.

Fix bytes_put to validate and use the incoming data's sof_abi_hdr.size
from ucontrol before copying. Fix bytes_get to subtract sizeof(*cdata)
from the bounds check to match the actual available space.

Fixes: 544ac88 ("ASoC: SOF: Add bytes_get/put control IPC ops for IPC3")
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
The ipc_control_data buffer is allocated as kzalloc(max_size), where
max_size covers the entire struct sof_ipc_ctrl_data including its
flexible array payload. However, the bounds checks in bytes_ext_put
and _bytes_ext_get compared user data lengths against max_size
directly, ignoring that cdata->data sits at an offset of
sizeof(struct sof_ipc_ctrl_data) bytes into the allocation.

This allowed writing up to sizeof(struct sof_ipc_ctrl_data) bytes past
the end of the heap buffer from unprivileged userspace via the ALSA TLV
kcontrol interface, and similarly allowed over-reading adjacent heap
data on the get path.

Fix all bounds checks to subtract sizeof(*cdata) from max_size so they
reflect the actual space available at the cdata->data offset. Also fix
the error-path restore in bytes_ext_put which wrote to cdata->data
instead of cdata, causing the same overflow.

Fixes: 67ec2a0 ("ASoC: SOF: Add bytes_ext control IPC ops for IPC3")
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Copilot AI review requested due to automatic review settings May 12, 2026 11:59
@ujfalusi
Copy link
Copy Markdown
Collaborator Author

this PR contains the patch from the now closed #5769

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the SOF IPC3 and IPC4 bytes/bytes_ext kcontrol put/get paths by fixing size/bounds validations to prevent heap overflows and TOCTOU-style issues when handling control binary payloads from userspace and firmware notifications.

Changes:

  • Validate incoming userspace ABI header sizes (use the new header, and account for struct sof_ipc_ctrl_data allocation offsets in IPC3).
  • Tighten TLV bytes_ext size checks (including minimum ABI header size) and fix restore-path memcpy destination.
  • Add overflow-safe expected-size computation for IPC3 control notifications and add additional bounds checks for binary updates.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
sound/soc/sof/ipc4-control.c Uses the incoming ABI header for size validation before copying/sending bytes control data (IPC4).
sound/soc/sof/ipc3-control.c Adjusts bounds checks to reflect actual allocations, hardens TLV bytes_ext handling, fixes restore copy target, and adds overflow-aware notification sizing and additional bounds checks (IPC3).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 446 to 450
/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
if (cdata->data->size > scontrol->max_size - sizeof(*cdata) - sizeof(struct sof_abi_hdr)) {
dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n");
goto err_restore;
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I will change the check to this.

Comment on lines +564 to 568
return;
}

/* copy the new binary data */
memcpy(local_cdata->data, cdata->data, cdata->num_elems);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect. In the binary path, cdata->num_elems is the total binary blob size copied from cdata->data (the sof_abi_hdr start). The existing num_elems == local_cdata->data->size check is how the original code has always worked — num_elems includes the ABI header bytes in this context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants