Skip to content

SWSPLAT-30708 xrt_kernel validate arg offset/size against execbuf payload#9895

Open
stsoe wants to merge 1 commit into
Xilinx:masterfrom
stsoe:SWSPLAT-30708
Open

SWSPLAT-30708 xrt_kernel validate arg offset/size against execbuf payload#9895
stsoe wants to merge 1 commit into
Xilinx:masterfrom
stsoe:SWSPLAT-30708

Conversation

@stsoe

@stsoe stsoe commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator

Problem solved by the commit

hs_arg_setter::set_arg_value() and set_offset_value() write caller-supplied bytes into data + arg.offset() where data points into the 4096-byte exec BO payload. arg.offset() and arg.size() are parsed from the xclbin EMBEDDED_METADATA XML with no upper bound. A malicious xclbin with offset=0x10000 causes every set_arg() call to write past the mapped BO into adjacent heap memory (CWE-787, CVSS 7.1). fa_arg_setter has the same defect via fa_desc_offset().

Bug / issue (if any) fixed, which PR introduced the bug, how it was discovered

SWSPLAT-30708. Identified by Mythos AI security audit (MYTHOS-RyzenAI-XRT-H2). Parent finding: SWSPLAT-30705.

How problem was solved, alternative solutions (if any) and why they were rejected

Added payload_size() to run_impl that computes the true number of bytes available for kernel arguments in the command buffer:

reserved = bytes consumed by ert header + cu masks (computed from data ptr)
payload = kernel_command::allocation_size - reserved (physical ceiling)

if regmap_size > 0: cap to regmap_size bytes (validates it fits in physical)
if regmap_size == 0: unlimited args — use physical ceiling

This handles kernels where regmap_size is not set (unlimited arguments) while still bounding writes to the actual buffer.

The resulting payload_size is passed to each arg_setter at construction time as m_payload_size. Overflow-safe bounds checks are added before every copy_n in hs_arg_setter (set_arg_value, set_offset_value, get_arg_value) and before the fa_desc_offset pointer arithmetic in fa_arg_setter.

bo_cache.h is amended to expose bo_size as a public constexpr so kernel_command::allocation_size can reference it without a magic number.

All four make_arg_setter() sites (pl/ps/dpu kernels and mailbox_impl) updated.

Risks (if any) associated the changes in the commit

Low. The bounds check fires only when arg.offset() + count exceeds the payload — impossible for a well-formed xclbin. Malformed inputs that previously caused silent heap corruption now throw xrt_core::error(-EINVAL).

What has been tested and how, request additional testing if necessary

Code review against the SWSPLAT-30708 finding. Existing kernel argument tests exercise the nominal path. The AFL++ harness from the ticket (feed xclbin bytes to xrt::kernel + run.set_arg) is recommended to confirm the OOB write is closed.

…load

hs_arg_setter::set_arg_value() and set_offset_value() write caller-supplied
bytes into data + arg.offset() where data points into the 4096-byte exec BO
payload.  arg.offset() and arg.size() are parsed from the xclbin
EMBEDDED_METADATA XML with no upper bound.  A malicious xclbin with
offset=0x10000 causes every set_arg() call to write past the mapped BO into
adjacent heap memory (CWE-787, CVSS 7.1).  fa_arg_setter has the same defect
via fa_desc_offset().

SWSPLAT-30708. Identified by Mythos AI security audit (MYTHOS-RyzenAI-XRT-H2).
Parent finding: SWSPLAT-30705.

Added payload_size() to run_impl that computes the true number of bytes
available for kernel arguments in the command buffer:

  reserved = bytes consumed by ert header + cu masks (computed from data ptr)
  payload  = kernel_command::allocation_size - reserved   (physical ceiling)

  if regmap_size > 0: cap to regmap_size bytes (validates it fits in physical)
  if regmap_size == 0: unlimited args — use physical ceiling

This handles kernels where regmap_size is not set (unlimited arguments) while
still bounding writes to the actual buffer.

The resulting payload_size is passed to each arg_setter at construction time
as m_payload_size.  Overflow-safe bounds checks are added before every
copy_n in hs_arg_setter (set_arg_value, set_offset_value, get_arg_value) and
before the fa_desc_offset pointer arithmetic in fa_arg_setter.

bo_cache.h is amended to expose bo_size as a public constexpr so
kernel_command::allocation_size can reference it without a magic number.

All four make_arg_setter() sites (pl/ps/dpu kernels and mailbox_impl) updated.

Low. The bounds check fires only when arg.offset() + count exceeds the
payload — impossible for a well-formed xclbin. Malformed inputs that
previously caused silent heap corruption now throw xrt_core::error(-EINVAL).

Code review against the SWSPLAT-30708 finding. Existing kernel argument
tests exercise the nominal path. The AFL++ harness from the ticket
(feed xclbin bytes to xrt::kernel + run.set_arg) is recommended to
confirm the OOB write is closed.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Soren Soe <2106410+stsoe@users.noreply.github.com>
@stsoe stsoe requested a review from rbramand-xilinx as a code owner July 4, 2026 22:00

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

// the overhead of BO life cycle management.
template <size_t BoSize>
class bo_cache_t {
class bo_cache_t

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: class 'bo_cache_t' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

class bo_cache_t
      ^

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.

1 participant