* [PATCH 0/2] accel/ivpu: Harden parsing of firmware-shared buffers
@ 2026-08-27 10:23 Dawid Osuchowski
2026-08-27 10:23 ` [PATCH 1/2] accel/ivpu: Validate full buffer range in ivpu_to_cpu_addr Dawid Osuchowski
2026-08-27 10:23 ` [PATCH 2/2] accel/ivpu: Validate firmware log buffer metadata Dawid Osuchowski
0 siblings, 2 replies; 4+ messages in thread
From: Dawid Osuchowski @ 2026-08-27 10:23 UTC (permalink / raw)
To: dri-devel
Cc: oded.gabbay, jeff.hugo, karol.wachowski, lizhi.hou,
andrzej.kacprowski, Dawid Osuchowski
The IPC and firmware tracing buffers live in memory shared with the NPU
firmware, so every field the host reads from them is untrusted input.
This series fixes two places where the host trusted such input and could
end up dereferencing addresses outside the underlying BO.
Both patches are tagged for stable.
Magdalena Schulfer (2):
accel/ivpu: Validate full buffer range in ivpu_to_cpu_addr
accel/ivpu: Validate firmware log buffer metadata
drivers/accel/ivpu/ivpu_fw_log.c | 76 +++++++++++++++++++-------------
drivers/accel/ivpu/ivpu_gem.h | 14 ++++--
drivers/accel/ivpu/ivpu_ipc.c | 7 +--
3 files changed, 60 insertions(+), 37 deletions(-)
base-commit: 4d4be202165e832d74849b4a68e289a2a377039c
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/2] accel/ivpu: Validate full buffer range in ivpu_to_cpu_addr
2026-08-27 10:23 [PATCH 0/2] accel/ivpu: Harden parsing of firmware-shared buffers Dawid Osuchowski
@ 2026-08-27 10:23 ` Dawid Osuchowski
2026-08-27 10:23 ` [PATCH 2/2] accel/ivpu: Validate firmware log buffer metadata Dawid Osuchowski
1 sibling, 0 replies; 4+ messages in thread
From: Dawid Osuchowski @ 2026-08-27 10:23 UTC (permalink / raw)
To: dri-devel
Cc: oded.gabbay, jeff.hugo, karol.wachowski, lizhi.hou,
andrzej.kacprowski, Magdalena Schulfer, stable, Dawid Osuchowski
From: Magdalena Schulfer <magdalena.schulfer@intel.com>
Add a size parameter to ivpu_to_cpu_addr() and validate that the
whole [vpu_addr, vpu_addr + size) range stays within the BO.
Cc: stable@vger.kernel.org
Fixes: 647371a6609d ("accel/ivpu: Add GEM buffer object management")
Signed-off-by: Magdalena Schulfer <magdalena.schulfer@intel.com>
Signed-off-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com>
---
drivers/accel/ivpu/ivpu_gem.h | 14 +++++++++++---
drivers/accel/ivpu/ivpu_ipc.c | 7 ++++---
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h
index 0c3350f22b55..b1ae020a4fc2 100644
--- a/drivers/accel/ivpu/ivpu_gem.h
+++ b/drivers/accel/ivpu/ivpu_gem.h
@@ -87,15 +87,23 @@ static inline bool ivpu_bo_is_resident(struct ivpu_bo *bo)
return !!bo->base.pages;
}
-static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u32 vpu_addr)
+static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u64 vpu_addr, u64 size)
{
+ u64 bo_size = ivpu_bo_size(bo);
+ u64 offset;
+
if (vpu_addr < bo->vpu_addr)
return NULL;
- if (vpu_addr >= (bo->vpu_addr + ivpu_bo_size(bo)))
+ if (size > bo_size)
+ return NULL;
+
+ offset = vpu_addr - bo->vpu_addr;
+
+ if (offset > bo_size - size)
return NULL;
- return ivpu_bo_vaddr(bo) + (vpu_addr - bo->vpu_addr);
+ return ivpu_bo_vaddr(bo) + offset;
}
static inline u32 cpu_to_vpu_addr(struct ivpu_bo *bo, void *cpu_addr)
diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c
index 978bc3d8704f..8f69fb133e2e 100644
--- a/drivers/accel/ivpu/ivpu_ipc.c
+++ b/drivers/accel/ivpu/ivpu_ipc.c
@@ -79,7 +79,7 @@ ivpu_ipc_tx_prepare(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
return -ENOMEM;
}
- tx_buf = ivpu_to_cpu_addr(ipc->mem_tx, tx_buf_vpu_addr);
+ tx_buf = ivpu_to_cpu_addr(ipc->mem_tx, tx_buf_vpu_addr, sizeof(*tx_buf));
if (drm_WARN_ON(&vdev->drm, !tx_buf)) {
gen_pool_free(ipc->mm_tx, tx_buf_vpu_addr, sizeof(*tx_buf));
return -EIO;
@@ -420,7 +420,7 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev)
return;
}
- ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr);
+ ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr, sizeof(*ipc_hdr));
if (!ipc_hdr) {
ivpu_warn_ratelimited(vdev, "IPC msg 0x%x out of range\n", vpu_addr);
continue;
@@ -429,7 +429,8 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev)
jsm_msg = NULL;
if (ipc_hdr->channel != IVPU_IPC_CHAN_BOOT_MSG) {
- jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr);
+ jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr,
+ sizeof(*jsm_msg));
if (!jsm_msg) {
ivpu_warn_ratelimited(vdev, "JSM msg 0x%x out of range\n",
ipc_hdr->data_addr);
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] accel/ivpu: Validate firmware log buffer metadata
2026-08-27 10:23 [PATCH 0/2] accel/ivpu: Harden parsing of firmware-shared buffers Dawid Osuchowski
2026-08-27 10:23 ` [PATCH 1/2] accel/ivpu: Validate full buffer range in ivpu_to_cpu_addr Dawid Osuchowski
@ 2026-08-27 10:23 ` Dawid Osuchowski
2026-08-27 10:38 ` sashiko-bot
1 sibling, 1 reply; 4+ messages in thread
From: Dawid Osuchowski @ 2026-08-27 10:23 UTC (permalink / raw)
To: dri-devel
Cc: oded.gabbay, jeff.hugo, karol.wachowski, lizhi.hou,
andrzej.kacprowski, Magdalena Schulfer, stable, Dawid Osuchowski
From: Magdalena Schulfer <magdalena.schulfer@intel.com>
The tracing log headers parsed by fw_log_print_buffer() reside in
DMA-shared BOs that the NPU firmware can write to.
fw_log_from_bo() validated log->header_size and log->size, but
fw_log_print_buffer() re-read those same fields from shared memory
afterwards, allowing a TOCTOU where firmware changes them between the
check and the use, and making the host dereference out-of-bounds
addresses while printing logs.
Snapshot the validated values once with READ_ONCE() and pass them down
explicitly in a new struct ivpu_fw_log_desc instead of re-reading them
from the shared struct.
Cc: stable@vger.kernel.org
Fixes: d4e4257afa6e ("accel/ivpu: Add firmware tracing support")
Signed-off-by: Magdalena Schulfer <magdalena.schulfer@intel.com>
Signed-off-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com>
---
drivers/accel/ivpu/ivpu_fw_log.c | 76 +++++++++++++++++++-------------
1 file changed, 45 insertions(+), 31 deletions(-)
diff --git a/drivers/accel/ivpu/ivpu_fw_log.c b/drivers/accel/ivpu/ivpu_fw_log.c
index 716467aa3156..4f9055aa9d33 100644
--- a/drivers/accel/ivpu/ivpu_fw_log.c
+++ b/drivers/accel/ivpu/ivpu_fw_log.c
@@ -26,10 +26,17 @@ MODULE_PARM_DESC(fw_log_level,
" error=" __stringify(IVPU_FW_LOG_ERROR)
" fatal=" __stringify(IVPU_FW_LOG_FATAL));
+struct ivpu_fw_log_desc {
+ struct vpu_tracing_buffer_header *log;
+ u32 header_size;
+ u32 size;
+};
+
static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *offset,
- struct vpu_tracing_buffer_header **out_log)
+ struct ivpu_fw_log_desc *desc)
{
struct vpu_tracing_buffer_header *log;
+ u32 header_size, size;
if ((*offset + sizeof(*log)) > ivpu_bo_size(bo))
return -EINVAL;
@@ -39,26 +46,32 @@ static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *off
if (log->vpu_canary_start != VPU_TRACING_BUFFER_CANARY)
return -EINVAL;
- if (log->header_size < sizeof(*log) || log->header_size > 1024) {
- ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", log->header_size);
+ header_size = READ_ONCE(log->header_size);
+ size = READ_ONCE(log->size);
+
+ if (header_size < sizeof(*log) || header_size > 1024) {
+ ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", header_size);
return -EINVAL;
}
- if (log->size < log->header_size) {
- ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
+ if ((char *)log + size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) {
+ ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", size);
return -EINVAL;
}
- if ((char *)log + log->size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) {
- ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
+ if (size < header_size) {
+ ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x < header size 0x%x\n",
+ size, header_size);
return -EINVAL;
}
- *out_log = log;
- *offset += log->size;
+ desc->log = log;
+ desc->header_size = header_size;
+ desc->size = size;
+ *offset += size;
ivpu_dbg(vdev, FW_BOOT,
"FW log name \"%s\", write offset 0x%x size 0x%x, wrap count %d, hdr version %d size %d format %d, alignment %d",
- log->name, log->write_index, log->size, log->wrap_count, log->header_version,
- log->header_size, log->format, log->alignment);
+ log->name, log->write_index, size, log->wrap_count, log->header_version,
+ header_size, log->format, log->alignment);
return 0;
}
@@ -94,11 +107,12 @@ static void fw_log_print_lines(char *buffer, u32 size, struct drm_printer *p)
drm_printf(p, "%s", line);
}
-static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const char *prefix,
+static void fw_log_print_buffer(struct ivpu_fw_log_desc *desc, const char *prefix,
bool only_new_msgs, struct drm_printer *p)
{
- char *log_data = (void *)log + log->header_size;
- u32 data_size = log->size - log->header_size;
+ struct vpu_tracing_buffer_header *log = desc->log;
+ char *log_data = (void *)log + desc->header_size;
+ u32 data_size = desc->size - desc->header_size;
u32 log_start = only_new_msgs ? READ_ONCE(log->read_index) : 0;
u32 log_end = READ_ONCE(log->write_index);
@@ -134,11 +148,11 @@ static void
fw_log_print_all_in_bo(struct ivpu_device *vdev, const char *name,
struct ivpu_bo *bo, bool only_new_msgs, struct drm_printer *p)
{
- struct vpu_tracing_buffer_header *log;
+ struct ivpu_fw_log_desc desc;
u32 next = 0;
- while (fw_log_from_bo(vdev, bo, &next, &log) == 0)
- fw_log_print_buffer(log, name, only_new_msgs, p);
+ while (fw_log_from_bo(vdev, bo, &next, &desc) == 0)
+ fw_log_print_buffer(&desc, name, only_new_msgs, p);
}
void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_printer *p)
@@ -149,36 +163,36 @@ void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_
void ivpu_fw_log_mark_read(struct ivpu_device *vdev)
{
- struct vpu_tracing_buffer_header *log;
+ struct ivpu_fw_log_desc desc;
u32 next;
next = 0;
- while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &log) == 0) {
- log->read_index = READ_ONCE(log->write_index);
- log->read_wrap_count = READ_ONCE(log->wrap_count);
+ while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &desc) == 0) {
+ desc.log->read_index = READ_ONCE(desc.log->write_index);
+ desc.log->read_wrap_count = READ_ONCE(desc.log->wrap_count);
}
next = 0;
- while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &log) == 0) {
- log->read_index = READ_ONCE(log->write_index);
- log->read_wrap_count = READ_ONCE(log->wrap_count);
+ while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &desc) == 0) {
+ desc.log->read_index = READ_ONCE(desc.log->write_index);
+ desc.log->read_wrap_count = READ_ONCE(desc.log->wrap_count);
}
}
void ivpu_fw_log_reset(struct ivpu_device *vdev)
{
- struct vpu_tracing_buffer_header *log;
+ struct ivpu_fw_log_desc desc;
u32 next;
next = 0;
- while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &log) == 0) {
- log->read_index = 0;
- log->read_wrap_count = 0;
+ while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &desc) == 0) {
+ desc.log->read_index = 0;
+ desc.log->read_wrap_count = 0;
}
next = 0;
- while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &log) == 0) {
- log->read_index = 0;
- log->read_wrap_count = 0;
+ while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &desc) == 0) {
+ desc.log->read_index = 0;
+ desc.log->read_wrap_count = 0;
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] accel/ivpu: Validate firmware log buffer metadata
2026-08-27 10:23 ` [PATCH 2/2] accel/ivpu: Validate firmware log buffer metadata Dawid Osuchowski
@ 2026-08-27 10:38 ` sashiko-bot
0 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-08-27 10:38 UTC (permalink / raw)
To: Dawid Osuchowski; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Unsafe printing of firmware-controlled string without length bounds could lead to out-of-bounds read.
--
commit fd0e38bea76a0e3e0f409139f3cf70f7ae5a79ea
Author: Magdalena Schulfer <magdalena.schulfer@intel.com>
accel/ivpu: Validate firmware log buffer metadata
The tracing log headers parsed by fw_log_print_buffer() reside in
DMA-shared BOs that the NPU firmware can write to. This commit mitigates
a TOCTOU vulnerability by snapshotting the header size and size fields
before validating them.
> diff --git a/drivers/accel/ivpu/ivpu_fw_log.c b/drivers/accel/ivpu/ivpu_fw_log.c
> index 716467aa31567..4f9055aa9d33f 100644
> --- a/drivers/accel/ivpu/ivpu_fw_log.c
> +++ b/drivers/accel/ivpu/ivpu_fw_log.c
[ ... ]
> @@ -39,26 +46,32 @@ static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *off
[ ... ]
> - *out_log = log;
> - *offset += log->size;
> + desc->log = log;
> + desc->header_size = header_size;
> + desc->size = size;
> + *offset += size;
>
> ivpu_dbg(vdev, FW_BOOT,
> "FW log name \"%s\", write offset 0x%x size 0x%x, wrap count %d, hdr version %d size %d format %d, alignment %d",
> - log->name, log->write_index, log->size, log->wrap_count, log->header_version,
> - log->header_size, log->format, log->alignment);
> + log->name, log->write_index, size, log->wrap_count, log->header_version,
> + header_size, log->format, log->alignment);
[Severity: High]
This isn't a bug introduced by this patch, but since this commit aims to
secure the untrusted log header, is it safe to print log->name using %s?
The name array (16 bytes) in struct vpu_tracing_buffer_header is controlled by
the firmware. If the firmware fails to null-terminate it, printing it with %s
in ivpu_dbg() will cause an out-of-bounds read. This could leak adjacent
memory into the kernel log or trigger a panic if the read crosses into
an unmapped page.
Could we bound the length by using %.16s instead?
A similar issue also exists in fw_log_print_buffer(), where log->name is
repeatedly passed to drm_printf() using %s without length limits.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260827102339.281799-1-dawid.osuchowski@linux.intel.com?part=2
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-27 10:38 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-27 10:23 [PATCH 0/2] accel/ivpu: Harden parsing of firmware-shared buffers Dawid Osuchowski
2026-08-27 10:23 ` [PATCH 1/2] accel/ivpu: Validate full buffer range in ivpu_to_cpu_addr Dawid Osuchowski
2026-08-27 10:23 ` [PATCH 2/2] accel/ivpu: Validate firmware log buffer metadata Dawid Osuchowski
2026-08-27 10:38 ` sashiko-bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.