From: sashiko-bot@kernel.org
To: "Taimuraz Kaitmazov" <taimuraz@kaitmazov.com>
Cc: dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v3] accel/amdxdna: use READ_ONCE/WRITE_ONCE on the command header
Date: Wed, 26 Aug 2026 22:27:51 +0000 [thread overview]
Message-ID: <20260826222752.3909C1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260826221334.625974-1-taimuraz@kaitmazov.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] The patch fails to resolve the TOCTOU vulnerability because it issues multiple independent `READ_ONCE(cmd->header)` calls instead of storing a single local snapshot.
Pre-existing issues:
- [High] Undefined behavior caused by passing a `NULL` source pointer to `memcpy()` when parsing an empty command payload.
- [High] Uninitialized kernel stack memory is sent to the hardware mailbox, causing an information leak.
--
commit c8e0faf1355b7f70321f8abedf7d99ec0ac63c46
Author: Taimuraz Kaitmazov <taimuraz@kaitmazov.com>
accel/amdxdna: use READ_ONCE/WRITE_ONCE on the command header
This commit attempts to fix a TOCTOU race condition in the command header
parsing by using READ_ONCE and WRITE_ONCE macros. It aims to read the
user-mapped command header once into a local variable to prevent the
compiler from splitting loads.
> diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c
> index 888e857ec5582..02027522210d9 100644
> --- a/drivers/accel/amdxdna/amdxdna_ctx.c
> +++ b/drivers/accel/amdxdna/amdxdna_ctx.c
> @@ -123,10 +123,11 @@ void *amdxdna_cmd_get_payload(struct amdxdna_gem_obj *abo, u32 *size)
> if (amdxdna_cmd_get_op(abo) == ERT_CMD_CHAIN)
> num_masks = 0;
> else
> - num_masks = 1 + FIELD_GET(AMDXDNA_CMD_EXTRA_CU_MASK, cmd->header);
> + num_masks = 1 + FIELD_GET(AMDXDNA_CMD_EXTRA_CU_MASK,
> + READ_ONCE(cmd->header));
>
> if (size) {
> - count = FIELD_GET(AMDXDNA_CMD_COUNT, cmd->header);
> + count = FIELD_GET(AMDXDNA_CMD_COUNT, READ_ONCE(cmd->header));
[Severity: High]
Does this actually fix the race condition? The commit message explicitly
claims to fix this by reading the header "once into a local with
READ_ONCE()".
Because READ_ONCE() enforces a volatile memory access, the compiler is
forced to issue multiple distinct memory loads for the opcode,
EXTRA_CU_MASK, and COUNT fields.
Could the fields still be fetched from different snapshots of the header,
maintaining the TOCTOU vulnerability?
> if (unlikely(count <= num_masks ||
> count * sizeof(u32) +
> offsetof(struct amdxdna_cmd, data[0]) >
> @@ -151,7 +152,7 @@ u32 amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo)
> if (amdxdna_cmd_get_op(abo) == ERT_CMD_CHAIN)
> return INVALID_CU_IDX;
>
> - num_masks = 1 + FIELD_GET(AMDXDNA_CMD_EXTRA_CU_MASK, cmd->header);
> + num_masks = 1 + FIELD_GET(AMDXDNA_CMD_EXTRA_CU_MASK, READ_ONCE(cmd->header));
[Severity: High]
Does this suffer from the same issue? amdxdna_cmd_get_op() already reads
the header, and here it is read again with a separate READ_ONCE(), rather
than using a single local variable.
[ ... ]
> @@ -169,12 +170,15 @@ int amdxdna_cmd_set_error(struct amdxdna_gem_obj *abo,
> struct amdxdna_client *client = job->hwctx->client;
> struct amdxdna_cmd *cmd = amdxdna_gem_vmap(abo);
> struct amdxdna_cmd_chain *cc = NULL;
> + u32 header;
>
> if (!cmd)
> return -ENOMEM;
>
> - cmd->header &= ~AMDXDNA_CMD_STATE;
> - cmd->header |= FIELD_PREP(AMDXDNA_CMD_STATE, error_state);
> + header = READ_ONCE(cmd->header);
> + header &= ~AMDXDNA_CMD_STATE;
> + header |= FIELD_PREP(AMDXDNA_CMD_STATE, error_state);
> + WRITE_ONCE(cmd->header, header);
>
> if (amdxdna_cmd_get_op(abo) == ERT_CMD_CHAIN) {
[Severity: High]
Does this code read the header again after modifying it?
amdxdna_cmd_get_op() internally does a READ_ONCE(cmd->header), which
happens right after the write. Could it end up reading a newly injected
opcode if userspace modifies the header concurrently?
[Severity: High]
This isn't a bug introduced by this patch, but could this trigger undefined
behavior if a user passes an empty payload?
If a userspace application configures a command buffer with
count <= num_masks, amdxdna_cmd_get_payload() can validly return NULL:
drivers/accel/amdxdna/amdxdna_ctx.c:amdxdna_cmd_get_payload() {
...
if (unlikely(count <= num_masks ||
count * sizeof(u32) +
offsetof(struct amdxdna_cmd, data[0]) >
abo->mem.size)) {
*size = 0;
return NULL;
}
...
}
In drivers/accel/amdxdna/aie2_message.c:aie2_init_exec_cu_req(), the
returned pointer is passed directly to memcpy() without validation:
cmd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
if (cmd_len > sizeof(cu_req->payload))
return -EINVAL;
cu_req->cu_idx = amdxdna_cmd_get_cu_idx(cmd_bo);
if (cu_req->cu_idx == INVALID_CU_IDX)
return -EINVAL;
memcpy(cu_req->payload, cmd, cmd_len);
Passing a NULL pointer to memcpy() triggers undefined behavior according
to the C standard, even if the length is 0. Will this cause a kernel
panic if panic_on_warn is enabled when UBSAN catches this?
[Severity: High]
This is a pre-existing issue, but does this leak uninitialized stack
memory to the hardware mailbox?
In drivers/accel/amdxdna/aie2_message.c:aie2_execbuf(), an uninitialized
union is allocated on the stack:
union exec_req req;
...
ret = aie2_init_exec_req(&req, cmd_abo, &msg.send_size, &msg.opcode);
If aie2_init_exec_cu_req() processes a small payload (e.g. cmd_len = 0),
the remainder of the payload array retains uninitialized stack contents:
memcpy(cu_req->payload, cmd, cmd_len);
*size = sizeof(*cu_req);
Could the remaining 76 bytes of uninitialized kernel stack memory be
transmitted when xdna_mailbox_send_msg() is called?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260826221334.625974-1-taimuraz@kaitmazov.com?part=1
next prev parent reply other threads:[~2026-08-26 22:27 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-26 14:30 [PATCH 0/2] accel/amdxdna: make the shared command header safe to read Taimuraz Kaitmazov
2026-08-26 14:30 ` [PATCH 1/2] accel/amdxdna: check the command chain payload before using it Taimuraz Kaitmazov
2026-08-26 14:43 ` sashiko-bot
2026-08-26 14:30 ` [PATCH 2/2] accel/amdxdna: use READ_ONCE/WRITE_ONCE on the command header Taimuraz Kaitmazov
2026-08-26 14:50 ` sashiko-bot
2026-08-26 15:31 ` [PATCH v2 0/2] accel/amdxdna: make the shared command header safe to read Taimuraz Kaitmazov
2026-08-26 15:31 ` [PATCH v2 1/2] accel/amdxdna: check the command chain payload before using it Taimuraz Kaitmazov
2026-08-26 15:48 ` sashiko-bot
2026-08-26 21:32 ` Lizhi Hou
2026-08-26 22:13 ` [PATCH v3] accel/amdxdna: use READ_ONCE/WRITE_ONCE on the command header Taimuraz Kaitmazov
2026-08-26 22:27 ` sashiko-bot [this message]
2026-08-26 15:31 ` [PATCH v2 2/2] " Taimuraz Kaitmazov
2026-08-26 23:16 ` Lizhi Hou
2026-08-27 0:20 ` Taimuraz Kaitmazov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260826222752.3909C1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=taimuraz@kaitmazov.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).