* [PATCH v1 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths
@ 2026-09-28 11:56 Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 1/4] media: ipu6: Free boot config on queue memory alloc failure Manik Bajpai
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Manik Bajpai @ 2026-09-28 11:56 UTC (permalink / raw)
To: linux-media; +Cc: sakari.ailus, antti.laakso, sarang.sapre
This series fixes several bugs found while reviewing the ipu7 buttress
power on/off, fw-com and mmu paths: a boot-config leak on a queue memory
allocation failure, a skipped cleanup step on a buttress power on/off
timeout, unchecked firmware-supplied queue indices used in pointer
arithmetic in ipu7_fw_com_get_token(), and a missing "is this iova mapped"
check in ipu6_mmu_iova_to_phys() that could dereference an invalid pointer
for an unmapped iova.
A related fix for a missing NULL check on the output pin queue in the ipu7
isr was dropped from this series, since an equivalent patch is already on
the list:
https://lore.kernel.org/linux-media/20260927201631.153126-2-devnexen@gmail.com/
Manik Bajpai (4):
media: ipu6: Free boot config on queue memory alloc failure
media: ipu6: Always run cleanup in ipu7 power on/off on timeout
media: ipu6: Validate fw-com queue indices before use
media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys()
drivers/media/pci/intel/ipu6/ipu6-buttress.c | 24 ++++++++++++--------
drivers/media/pci/intel/ipu6/ipu6-mmu.c | 11 ++++++++-
drivers/media/pci/intel/ipu6/ipu7-boot.c | 1 +
drivers/media/pci/intel/ipu6/ipu7-fw-com.c | 14 +++++++++++-
drivers/media/pci/intel/ipu6/ipu7-fw-com.h | 5 +++-
drivers/media/pci/intel/ipu6/ipu7-fw-isys.c | 7 +++---
6 files changed, 47 insertions(+), 15 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v1 1/4] media: ipu6: Free boot config on queue memory alloc failure
2026-09-28 11:56 [PATCH v1 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
@ 2026-09-28 11:56 ` Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 2/4] media: ipu6: Always run cleanup in ipu7 power on/off on timeout Manik Bajpai
` (2 subsequent siblings)
3 siblings, 0 replies; 13+ messages in thread
From: Manik Bajpai @ 2026-09-28 11:56 UTC (permalink / raw)
To: linux-media; +Cc: sakari.ailus, antti.laakso, sarang.sapre
If the queue_mem allocation in ipu7_init_boot_config() fails, the
function returned -ENOMEM without freeing the boot_config buffer it
had already allocated. The current caller happens to clean up via
ipu7_fw_isys_cleanup() -> ipu7_release_boot_config() on any failure
from this function, so this is not an active leak today, but
ipu7_init_boot_config() should not rely on a specific caller undoing
its partial allocations.
Call the existing ipu7_release_boot_config() helper before returning,
so the function cleans up after itself on its own error path,
independent of what the caller does.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Manik Bajpai <manik.bajpai@intel.com>
---
drivers/media/pci/intel/ipu6/ipu7-boot.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/media/pci/intel/ipu6/ipu7-boot.c b/drivers/media/pci/intel/ipu6/ipu7-boot.c
index 5bd5281ec107..225f802cfd1c 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-boot.c
+++ b/drivers/media/pci/intel/ipu6/ipu7-boot.c
@@ -246,6 +246,7 @@ int ipu7_init_boot_config(struct ipu6_bus_device *adev,
GFP_KERNEL, 0);
if (!fwctx->queue_mem) {
dev_err(dev, "Failed to allocate queue memory.\n");
+ ipu7_release_boot_config(adev);
return -ENOMEM;
}
fwctx->queue_mem_size = total_queue_size_aligned;
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 2/4] media: ipu6: Always run cleanup in ipu7 power on/off on timeout
2026-09-28 11:56 [PATCH v1 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 1/4] media: ipu6: Free boot config on queue memory alloc failure Manik Bajpai
@ 2026-09-28 11:56 ` Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 3/4] media: ipu6: Validate fw-com queue indices before use Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 4/4] media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys() Manik Bajpai
3 siblings, 0 replies; 13+ messages in thread
From: Manik Bajpai @ 2026-09-28 11:56 UTC (permalink / raw)
To: linux-media; +Cc: sakari.ailus, antti.laakso, sarang.sapre
__ipu7_power_on() and __ipu7_power_off() both return early when the
pwr_status readl_poll_timeout() call times out, skipping cleanup that
was previously done only on the success path:
- __ipu7_power_on() left the clock-ownership override bit set in
SLEEP_LEVEL_CFG instead of clearing it, which could break
subsequent power transitions.
- __ipu7_power_off() skipped D2D power-down and NDE-disable, leaving
those subsystems powered despite reporting a failure.
- Additionally, the return value of ipu7_isys_d2d_power() in
__ipu7_power_off() was discarded, silently masking D2D power-down
failures.
Always run the clock-override clear / D2D-NDE teardown regardless of
whether the status poll timed out, and propagate a D2D power-down
failure through the return value when the poll itself succeeded.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Manik Bajpai <manik.bajpai@intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-buttress.c | 24 ++++++++++++--------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index 105de1744dff..06a773b5b66b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -530,16 +530,15 @@ static int __ipu7_power_on(struct device *dev,
ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
val, (val & ctrl->pwr_sts_mask) == pwr_sts,
100, BUTTRESS_POWER_TIMEOUT_US);
- if (ret) {
+ if (ret)
dev_err(&isp->pdev->dev,
"Change power status timeout with 0x%x\n", val);
- return ret;
- }
+ /* Always drop the clock override, even if the poll above timed out. */
slp = readl(isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
writel(slp & ~ovrd_clk, isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
- return 0;
+ return ret;
}
static int __ipu7_power_off(struct device *dev,
@@ -555,18 +554,25 @@ static int __ipu7_power_off(struct device *dev,
ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
val, (val & ctrl->pwr_sts_mask) == pwr_sts,
100, BUTTRESS_POWER_TIMEOUT_US);
- if (ret) {
+ if (ret)
dev_err(&isp->pdev->dev,
"Change power status timeout with 0x%x\n", val);
- return ret;
- }
+ /* Always release D2D/NDE, even if the power status poll timed out. */
if (ctrl->subsys_id == IPU_ISYS) {
- ipu7_isys_d2d_power(isp, false);
+ int d2d_ret;
+
+ d2d_ret = ipu7_isys_d2d_power(isp, false);
+ if (d2d_ret) {
+ dev_err(&isp->pdev->dev,
+ "D2D power down failed (%d)\n", d2d_ret);
+ if (!ret)
+ ret = d2d_ret;
+ }
ipu7_nde_control(isp, false);
}
- return 0;
+ return ret;
}
static int __ipu6_power(struct device *dev,
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 3/4] media: ipu6: Validate fw-com queue indices before use
2026-09-28 11:56 [PATCH v1 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 1/4] media: ipu6: Free boot config on queue memory alloc failure Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 2/4] media: ipu6: Always run cleanup in ipu7 power on/off on timeout Manik Bajpai
@ 2026-09-28 11:56 ` Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 4/4] media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys() Manik Bajpai
3 siblings, 0 replies; 13+ messages in thread
From: Manik Bajpai @ 2026-09-28 11:56 UTC (permalink / raw)
To: linux-media; +Cc: sakari.ailus, antti.laakso, sarang.sapre
ipu7_fw_com_get_token() reads read_index/write_index directly from
firmware-shared memory and uses them unchecked in pointer arithmetic
to compute a token address:
token = queue_params->token_array_mem +
read_index * queue_params->token_size_in_bytes;
If firmware ever writes a corrupted or out-of-range index into that
shared memory, this computes a pointer outside token_array_mem.
Reject indices that are not smaller than max_capacity before doing any
pointer arithmetic.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Manik Bajpai <manik.bajpai@intel.com>
---
drivers/media/pci/intel/ipu6/ipu7-fw-com.c | 14 +++++++++++++-
drivers/media/pci/intel/ipu6/ipu7-fw-com.h | 5 ++++-
drivers/media/pci/intel/ipu6/ipu7-fw-isys.c | 7 ++++---
3 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.c b/drivers/media/pci/intel/ipu6/ipu7-fw-com.c
index 7dd1e683aa92..3d0a8fcac15e 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-com.c
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.c
@@ -3,6 +3,7 @@
* Copyright (C) 2026 Intel Corporation
*/
+#include <linux/device.h>
#include <linux/io.h>
#include "ipu7-fw-com.h"
@@ -13,7 +14,8 @@ static void __iomem *ipu7_fw_com_get_indices(struct ipu7_fw_com_context *ctx,
return ctx->queue_indices + (q * sizeof(struct ipu7_fw_com_queue_indices));
}
-void *ipu7_fw_com_get_token(struct ipu7_fw_com_context *ctx, int q)
+void *ipu7_fw_com_get_token(struct device *dev, struct ipu7_fw_com_context *ctx,
+ int q)
{
struct ipu7_fw_com_queue_config *queue_params = &ctx->queue_configs[q];
void __iomem *queue_indices = ipu7_fw_com_get_indices(ctx, q);
@@ -25,6 +27,16 @@ void *ipu7_fw_com_get_token(struct ipu7_fw_com_context *ctx, int q)
read_index));
void *token = NULL;
+ /* Indices come from firmware-shared memory; don't trust them blindly. */
+ if (read_index >= queue_params->max_capacity ||
+ write_index >= queue_params->max_capacity) {
+ dev_err_once(dev,
+ "ipu7-fw-com: bad queue %d index (r=%u w=%u cap=%u)\n",
+ q, read_index, write_index,
+ queue_params->max_capacity);
+ return NULL;
+ }
+
if (q < ctx->num_output_queues) {
/* Output queue */
bool empty = (write_index == read_index);
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
index 097eaab99547..2921d097e580 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
@@ -6,6 +6,8 @@
#include <linux/types.h>
+struct device;
+
struct ipu7_fw_com_queue_config {
void *token_array_mem;
u32 queue_size;
@@ -46,7 +48,8 @@ struct ipu7_fw_com_queue_indices {
};
void ipu7_fw_com_put_token(struct ipu7_fw_com_context *ctx, int q);
-void *ipu7_fw_com_get_token(struct ipu7_fw_com_context *ctx, int q);
+void *ipu7_fw_com_get_token(struct device *dev, struct ipu7_fw_com_context *ctx,
+ int q);
struct ipu7_fw_com_queue_params_config *
ipu7_fw_com_get_queue_config(struct ipu7_fw_com_config *config);
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
index e74e2b2566aa..60e29e2d63a7 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
@@ -147,7 +147,8 @@ static int ipu7_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
static struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu6_isys *isys)
{
- return ipu7_fw_com_get_token(isys->fwctx, IPU7_INSYS_OUTPUT_MSG_QUEUE);
+ return ipu7_fw_com_get_token(&isys->adev->auxdev.dev, isys->fwctx,
+ IPU7_INSYS_OUTPUT_MSG_QUEUE);
}
static void ipu7_fw_isys_put_resp(struct ipu6_isys *isys)
@@ -219,7 +220,6 @@ ipu7_fw_isys_send_cmd(struct ipu6_isys *isys, const unsigned int stream_handle,
size_t size, u16 send_type)
{
struct ipu7_fw_com_context *ctx = isys->fwctx;
- /*struct device *dev = &isys->adev->auxdev.dev;*/
struct ipu7_insys_send_queue_token *token;
if (send_type >= N_IPU7_INSYS_SEND_TYPE)
@@ -228,7 +228,8 @@ ipu7_fw_isys_send_cmd(struct ipu6_isys *isys, const unsigned int stream_handle,
if (cpu_mapped_buf)
clflush_cache_range(cpu_mapped_buf, size);
- token = ipu7_fw_com_get_token(ctx, stream_handle +
+ token = ipu7_fw_com_get_token(&isys->adev->auxdev.dev, ctx,
+ stream_handle +
IPU7_INSYS_INPUT_MSG_QUEUE);
if (!token)
return -EBUSY;
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 4/4] media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys()
2026-09-28 11:56 [PATCH v1 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
` (2 preceding siblings ...)
2026-09-28 11:56 ` [PATCH v1 3/4] media: ipu6: Validate fw-com queue indices before use Manik Bajpai
@ 2026-09-28 11:56 ` Manik Bajpai
2026-09-28 12:08 ` Sakari Ailus
3 siblings, 1 reply; 13+ messages in thread
From: Manik Bajpai @ 2026-09-28 11:56 UTC (permalink / raw)
To: linux-media; +Cc: sakari.ailus, antti.laakso, sarang.sapre
ipu6_mmu_iova_to_phys() looked up the L2 page table for the given iova
and dereferenced it immediately, without checking whether the
corresponding L1 entry is actually mapped. l2_map() and l2_unmap()
already guard the equivalent lookup by checking the L1 entry against
mmu_info->dummy_l2_pteval before touching l2_pts[].
An unmapped iova (e.g. a stale address passed from a debug path)
would dereference an invalid pointer and crash.
Add the same "is this L1 entry mapped" check used by l2_map()/
l2_unmap(), returning 0 for an unmapped iova instead of crashing.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Manik Bajpai <manik.bajpai@intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-mmu.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
index 243d438786ba..b8a8ed622b8d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
@@ -566,10 +566,19 @@ phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info,
{
phys_addr_t phy_addr;
unsigned long flags;
+ u32 l1_idx = iova >> ISP_L1PT_SHIFT;
u32 *l2_pt;
spin_lock_irqsave(&mmu_info->lock, flags);
- l2_pt = mmu_info->l2_pts[iova >> ISP_L1PT_SHIFT];
+ if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) {
+ spin_unlock_irqrestore(&mmu_info->lock, flags);
+ dev_err(mmu_info->dev,
+ "iova_to_phys: no mapping for iova %pad\n",
+ &iova);
+ return 0;
+ }
+
+ l2_pt = mmu_info->l2_pts[l1_idx];
phy_addr = (phys_addr_t)l2_pt[(iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT];
phy_addr <<= ISP_PAGE_SHIFT;
spin_unlock_irqrestore(&mmu_info->lock, flags);
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v1 4/4] media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys()
2026-09-28 11:56 ` [PATCH v1 4/4] media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys() Manik Bajpai
@ 2026-09-28 12:08 ` Sakari Ailus
2026-09-29 8:31 ` [PATCH v2 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
0 siblings, 1 reply; 13+ messages in thread
From: Sakari Ailus @ 2026-09-28 12:08 UTC (permalink / raw)
To: Manik Bajpai; +Cc: linux-media, antti.laakso, sarang.sapre
Hi Manik,
On Mon, Sep 28, 2026 at 05:26:46PM +0530, Manik Bajpai wrote:
> ipu6_mmu_iova_to_phys() looked up the L2 page table for the given iova
> and dereferenced it immediately, without checking whether the
> corresponding L1 entry is actually mapped. l2_map() and l2_unmap()
> already guard the equivalent lookup by checking the L1 entry against
> mmu_info->dummy_l2_pteval before touching l2_pts[].
>
> An unmapped iova (e.g. a stale address passed from a debug path)
> would dereference an invalid pointer and crash.
>
> Add the same "is this L1 entry mapped" check used by l2_map()/
> l2_unmap(), returning 0 for an unmapped iova instead of crashing.
Have you observed this somewhere? I guess it shouldn't happen, but if it
has happened, I think we should add a Fixes: tag and Cc: stable here.
--
Regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths
2026-09-28 12:08 ` Sakari Ailus
@ 2026-09-29 8:31 ` Manik Bajpai
2026-09-29 8:31 ` [PATCH v2 1/4] media: ipu6: Free boot config on queue memory alloc failure Manik Bajpai
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Manik Bajpai @ 2026-09-29 8:31 UTC (permalink / raw)
To: sakari.ailus; +Cc: linux-media, antti.laakso, sarang.sapre
This series fixes several bugs found while reviewing the ipu7 buttress
power on/off, fw-com and mmu paths: a boot-config leak on a queue memory
allocation failure, a skipped cleanup step on a buttress power on/off
timeout, unchecked firmware-supplied queue indices used in pointer
arithmetic in ipu7_fw_com_get_token(), and a missing "is this iova mapped"
check in ipu6_mmu_iova_to_phys() that could dereference an invalid pointer
for an unmapped iova.
A related fix for a missing NULL check on the output pin queue in the ipu7
isr was dropped from this series, since an equivalent patch is already on
the list:
https://lore.kernel.org/linux-media/20260927201631.153126-2-devnexen@gmail.com/
v2:
- ipu6_mmu_iova_to_phys(): this was found via code review, not from an
observed crash (comparing against l2_map()/l2_unmap(), which already
guard the equivalent lookup). Added a Fixes: tag pointing at the
commit that introduced the unguarded lookup, but skipped a
stable-tree backport since there's no confirmed real-world trigger
(Sakari).
Manik Bajpai (4):
media: ipu6: Free boot config on queue memory alloc failure
media: ipu6: Always run cleanup in ipu7 power on/off on timeout
media: ipu6: Validate fw-com queue indices before use
media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys()
drivers/media/pci/intel/ipu6/ipu6-buttress.c | 24 ++++++++++++--------
drivers/media/pci/intel/ipu6/ipu6-mmu.c | 11 ++++++++-
drivers/media/pci/intel/ipu6/ipu7-boot.c | 1 +
drivers/media/pci/intel/ipu6/ipu7-fw-com.c | 14 +++++++++++-
drivers/media/pci/intel/ipu6/ipu7-fw-com.h | 5 +++-
drivers/media/pci/intel/ipu6/ipu7-fw-isys.c | 7 +++---
6 files changed, 47 insertions(+), 15 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 1/4] media: ipu6: Free boot config on queue memory alloc failure
2026-09-29 8:31 ` [PATCH v2 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
@ 2026-09-29 8:31 ` Manik Bajpai
2026-09-30 8:53 ` Sakari Ailus
2026-09-29 8:31 ` [PATCH v2 2/4] media: ipu6: Always run cleanup in ipu7 power on/off on timeout Manik Bajpai
` (2 subsequent siblings)
3 siblings, 1 reply; 13+ messages in thread
From: Manik Bajpai @ 2026-09-29 8:31 UTC (permalink / raw)
To: sakari.ailus; +Cc: linux-media, antti.laakso, sarang.sapre
If the queue_mem allocation in ipu7_init_boot_config() fails, the
function returned -ENOMEM without freeing the boot_config buffer it
had already allocated. The current caller happens to clean up via
ipu7_fw_isys_cleanup() -> ipu7_release_boot_config() on any failure
from this function, so this is not an active leak today, but
ipu7_init_boot_config() should not rely on a specific caller undoing
its partial allocations.
Call the existing ipu7_release_boot_config() helper before returning,
so the function cleans up after itself on its own error path,
independent of what the caller does.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Manik Bajpai <manik.bajpai@intel.com>
---
drivers/media/pci/intel/ipu6/ipu7-boot.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/media/pci/intel/ipu6/ipu7-boot.c b/drivers/media/pci/intel/ipu6/ipu7-boot.c
index 5bd5281ec107..225f802cfd1c 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-boot.c
+++ b/drivers/media/pci/intel/ipu6/ipu7-boot.c
@@ -246,6 +246,7 @@ int ipu7_init_boot_config(struct ipu6_bus_device *adev,
GFP_KERNEL, 0);
if (!fwctx->queue_mem) {
dev_err(dev, "Failed to allocate queue memory.\n");
+ ipu7_release_boot_config(adev);
return -ENOMEM;
}
fwctx->queue_mem_size = total_queue_size_aligned;
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v2 2/4] media: ipu6: Always run cleanup in ipu7 power on/off on timeout
2026-09-29 8:31 ` [PATCH v2 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
2026-09-29 8:31 ` [PATCH v2 1/4] media: ipu6: Free boot config on queue memory alloc failure Manik Bajpai
@ 2026-09-29 8:31 ` Manik Bajpai
2026-09-30 13:17 ` Antti Laakso
2026-09-29 8:31 ` [PATCH v2 3/4] media: ipu6: Validate fw-com queue indices before use Manik Bajpai
2026-09-29 8:31 ` [PATCH v2 4/4] media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys() Manik Bajpai
3 siblings, 1 reply; 13+ messages in thread
From: Manik Bajpai @ 2026-09-29 8:31 UTC (permalink / raw)
To: sakari.ailus; +Cc: linux-media, antti.laakso, sarang.sapre
__ipu7_power_on() and __ipu7_power_off() both return early when the
pwr_status readl_poll_timeout() call times out, skipping cleanup that
was previously done only on the success path:
- __ipu7_power_on() left the clock-ownership override bit set in
SLEEP_LEVEL_CFG instead of clearing it, which could break
subsequent power transitions.
- __ipu7_power_off() skipped D2D power-down and NDE-disable, leaving
those subsystems powered despite reporting a failure.
- Additionally, the return value of ipu7_isys_d2d_power() in
__ipu7_power_off() was discarded, silently masking D2D power-down
failures.
Always run the clock-override clear / D2D-NDE teardown regardless of
whether the status poll timed out, and propagate a D2D power-down
failure through the return value when the poll itself succeeded.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Manik Bajpai <manik.bajpai@intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-buttress.c | 24 ++++++++++++--------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index 105de1744dff..06a773b5b66b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -530,16 +530,15 @@ static int __ipu7_power_on(struct device *dev,
ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
val, (val & ctrl->pwr_sts_mask) == pwr_sts,
100, BUTTRESS_POWER_TIMEOUT_US);
- if (ret) {
+ if (ret)
dev_err(&isp->pdev->dev,
"Change power status timeout with 0x%x\n", val);
- return ret;
- }
+ /* Always drop the clock override, even if the poll above timed out. */
slp = readl(isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
writel(slp & ~ovrd_clk, isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
- return 0;
+ return ret;
}
static int __ipu7_power_off(struct device *dev,
@@ -555,18 +554,25 @@ static int __ipu7_power_off(struct device *dev,
ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
val, (val & ctrl->pwr_sts_mask) == pwr_sts,
100, BUTTRESS_POWER_TIMEOUT_US);
- if (ret) {
+ if (ret)
dev_err(&isp->pdev->dev,
"Change power status timeout with 0x%x\n", val);
- return ret;
- }
+ /* Always release D2D/NDE, even if the power status poll timed out. */
if (ctrl->subsys_id == IPU_ISYS) {
- ipu7_isys_d2d_power(isp, false);
+ int d2d_ret;
+
+ d2d_ret = ipu7_isys_d2d_power(isp, false);
+ if (d2d_ret) {
+ dev_err(&isp->pdev->dev,
+ "D2D power down failed (%d)\n", d2d_ret);
+ if (!ret)
+ ret = d2d_ret;
+ }
ipu7_nde_control(isp, false);
}
- return 0;
+ return ret;
}
static int __ipu6_power(struct device *dev,
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v2 3/4] media: ipu6: Validate fw-com queue indices before use
2026-09-29 8:31 ` [PATCH v2 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
2026-09-29 8:31 ` [PATCH v2 1/4] media: ipu6: Free boot config on queue memory alloc failure Manik Bajpai
2026-09-29 8:31 ` [PATCH v2 2/4] media: ipu6: Always run cleanup in ipu7 power on/off on timeout Manik Bajpai
@ 2026-09-29 8:31 ` Manik Bajpai
2026-09-29 8:31 ` [PATCH v2 4/4] media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys() Manik Bajpai
3 siblings, 0 replies; 13+ messages in thread
From: Manik Bajpai @ 2026-09-29 8:31 UTC (permalink / raw)
To: sakari.ailus; +Cc: linux-media, antti.laakso, sarang.sapre
ipu7_fw_com_get_token() reads read_index/write_index directly from
firmware-shared memory and uses them unchecked in pointer arithmetic
to compute a token address:
token = queue_params->token_array_mem +
read_index * queue_params->token_size_in_bytes;
If firmware ever writes a corrupted or out-of-range index into that
shared memory, this computes a pointer outside token_array_mem.
Reject indices that are not smaller than max_capacity before doing any
pointer arithmetic.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Manik Bajpai <manik.bajpai@intel.com>
---
drivers/media/pci/intel/ipu6/ipu7-fw-com.c | 14 +++++++++++++-
drivers/media/pci/intel/ipu6/ipu7-fw-com.h | 5 ++++-
drivers/media/pci/intel/ipu6/ipu7-fw-isys.c | 7 ++++---
3 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.c b/drivers/media/pci/intel/ipu6/ipu7-fw-com.c
index 7dd1e683aa92..3d0a8fcac15e 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-com.c
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.c
@@ -3,6 +3,7 @@
* Copyright (C) 2026 Intel Corporation
*/
+#include <linux/device.h>
#include <linux/io.h>
#include "ipu7-fw-com.h"
@@ -13,7 +14,8 @@ static void __iomem *ipu7_fw_com_get_indices(struct ipu7_fw_com_context *ctx,
return ctx->queue_indices + (q * sizeof(struct ipu7_fw_com_queue_indices));
}
-void *ipu7_fw_com_get_token(struct ipu7_fw_com_context *ctx, int q)
+void *ipu7_fw_com_get_token(struct device *dev, struct ipu7_fw_com_context *ctx,
+ int q)
{
struct ipu7_fw_com_queue_config *queue_params = &ctx->queue_configs[q];
void __iomem *queue_indices = ipu7_fw_com_get_indices(ctx, q);
@@ -25,6 +27,16 @@ void *ipu7_fw_com_get_token(struct ipu7_fw_com_context *ctx, int q)
read_index));
void *token = NULL;
+ /* Indices come from firmware-shared memory; don't trust them blindly. */
+ if (read_index >= queue_params->max_capacity ||
+ write_index >= queue_params->max_capacity) {
+ dev_err_once(dev,
+ "ipu7-fw-com: bad queue %d index (r=%u w=%u cap=%u)\n",
+ q, read_index, write_index,
+ queue_params->max_capacity);
+ return NULL;
+ }
+
if (q < ctx->num_output_queues) {
/* Output queue */
bool empty = (write_index == read_index);
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
index 097eaab99547..2921d097e580 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
@@ -6,6 +6,8 @@
#include <linux/types.h>
+struct device;
+
struct ipu7_fw_com_queue_config {
void *token_array_mem;
u32 queue_size;
@@ -46,7 +48,8 @@ struct ipu7_fw_com_queue_indices {
};
void ipu7_fw_com_put_token(struct ipu7_fw_com_context *ctx, int q);
-void *ipu7_fw_com_get_token(struct ipu7_fw_com_context *ctx, int q);
+void *ipu7_fw_com_get_token(struct device *dev, struct ipu7_fw_com_context *ctx,
+ int q);
struct ipu7_fw_com_queue_params_config *
ipu7_fw_com_get_queue_config(struct ipu7_fw_com_config *config);
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
index e74e2b2566aa..60e29e2d63a7 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
@@ -147,7 +147,8 @@ static int ipu7_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
static struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu6_isys *isys)
{
- return ipu7_fw_com_get_token(isys->fwctx, IPU7_INSYS_OUTPUT_MSG_QUEUE);
+ return ipu7_fw_com_get_token(&isys->adev->auxdev.dev, isys->fwctx,
+ IPU7_INSYS_OUTPUT_MSG_QUEUE);
}
static void ipu7_fw_isys_put_resp(struct ipu6_isys *isys)
@@ -219,7 +220,6 @@ ipu7_fw_isys_send_cmd(struct ipu6_isys *isys, const unsigned int stream_handle,
size_t size, u16 send_type)
{
struct ipu7_fw_com_context *ctx = isys->fwctx;
- /*struct device *dev = &isys->adev->auxdev.dev;*/
struct ipu7_insys_send_queue_token *token;
if (send_type >= N_IPU7_INSYS_SEND_TYPE)
@@ -228,7 +228,8 @@ ipu7_fw_isys_send_cmd(struct ipu6_isys *isys, const unsigned int stream_handle,
if (cpu_mapped_buf)
clflush_cache_range(cpu_mapped_buf, size);
- token = ipu7_fw_com_get_token(ctx, stream_handle +
+ token = ipu7_fw_com_get_token(&isys->adev->auxdev.dev, ctx,
+ stream_handle +
IPU7_INSYS_INPUT_MSG_QUEUE);
if (!token)
return -EBUSY;
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v2 4/4] media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys()
2026-09-29 8:31 ` [PATCH v2 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
` (2 preceding siblings ...)
2026-09-29 8:31 ` [PATCH v2 3/4] media: ipu6: Validate fw-com queue indices before use Manik Bajpai
@ 2026-09-29 8:31 ` Manik Bajpai
3 siblings, 0 replies; 13+ messages in thread
From: Manik Bajpai @ 2026-09-29 8:31 UTC (permalink / raw)
To: sakari.ailus; +Cc: linux-media, antti.laakso, sarang.sapre
ipu6_mmu_iova_to_phys() looked up the L2 page table for the given iova
and dereferenced it immediately, without checking whether the
corresponding L1 entry is actually mapped. l2_map() and l2_unmap()
already guard the equivalent lookup by checking the L1 entry against
mmu_info->dummy_l2_pteval before touching l2_pts[].
An unmapped iova (e.g. a stale address passed from a debug path)
would dereference an invalid pointer and crash.
Add the same "is this L1 entry mapped" check used by l2_map()/
l2_unmap(), returning 0 for an unmapped iova instead of crashing.
Fixes: 9163d83573e4 ("media: intel/ipu6: add IPU6 DMA mapping API and MMU table")
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Manik Bajpai <manik.bajpai@intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-mmu.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
index 243d438786ba..b8a8ed622b8d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
@@ -566,10 +566,19 @@ phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info,
{
phys_addr_t phy_addr;
unsigned long flags;
+ u32 l1_idx = iova >> ISP_L1PT_SHIFT;
u32 *l2_pt;
spin_lock_irqsave(&mmu_info->lock, flags);
- l2_pt = mmu_info->l2_pts[iova >> ISP_L1PT_SHIFT];
+ if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) {
+ spin_unlock_irqrestore(&mmu_info->lock, flags);
+ dev_err(mmu_info->dev,
+ "iova_to_phys: no mapping for iova %pad\n",
+ &iova);
+ return 0;
+ }
+
+ l2_pt = mmu_info->l2_pts[l1_idx];
phy_addr = (phys_addr_t)l2_pt[(iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT];
phy_addr <<= ISP_PAGE_SHIFT;
spin_unlock_irqrestore(&mmu_info->lock, flags);
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v2 1/4] media: ipu6: Free boot config on queue memory alloc failure
2026-09-29 8:31 ` [PATCH v2 1/4] media: ipu6: Free boot config on queue memory alloc failure Manik Bajpai
@ 2026-09-30 8:53 ` Sakari Ailus
0 siblings, 0 replies; 13+ messages in thread
From: Sakari Ailus @ 2026-09-30 8:53 UTC (permalink / raw)
To: Manik Bajpai; +Cc: linux-media, antti.laakso, sarang.sapre
Hi Manik,
On Tue, Sep 29, 2026 at 02:01:27PM +0530, Manik Bajpai wrote:
> If the queue_mem allocation in ipu7_init_boot_config() fails, the
> function returned -ENOMEM without freeing the boot_config buffer it
> had already allocated. The current caller happens to clean up via
> ipu7_fw_isys_cleanup() -> ipu7_release_boot_config() on any failure
> from this function, so this is not an active leak today, but
> ipu7_init_boot_config() should not rely on a specific caller undoing
> its partial allocations.
>
> Call the existing ipu7_release_boot_config() helper before returning,
> so the function cleans up after itself on its own error path,
> independent of what the caller does.
>
> Assisted-by: Claude:claude-sonnet-5
> Signed-off-by: Manik Bajpai <manik.bajpai@intel.com>
> ---
> drivers/media/pci/intel/ipu6/ipu7-boot.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/media/pci/intel/ipu6/ipu7-boot.c b/drivers/media/pci/intel/ipu6/ipu7-boot.c
> index 5bd5281ec107..225f802cfd1c 100644
> --- a/drivers/media/pci/intel/ipu6/ipu7-boot.c
> +++ b/drivers/media/pci/intel/ipu6/ipu7-boot.c
> @@ -246,6 +246,7 @@ int ipu7_init_boot_config(struct ipu6_bus_device *adev,
> GFP_KERNEL, 0);
> if (!fwctx->queue_mem) {
> dev_err(dev, "Failed to allocate queue memory.\n");
> + ipu7_release_boot_config(adev);
I believe on error, the caller already calls ipu7_fw_isys_cleanup() that
includes a call to ipu7_release_boot_config().
The rest of the patches seem fine to me.
> return -ENOMEM;
> }
> fwctx->queue_mem_size = total_queue_size_aligned;
--
Kind regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2 2/4] media: ipu6: Always run cleanup in ipu7 power on/off on timeout
2026-09-29 8:31 ` [PATCH v2 2/4] media: ipu6: Always run cleanup in ipu7 power on/off on timeout Manik Bajpai
@ 2026-09-30 13:17 ` Antti Laakso
0 siblings, 0 replies; 13+ messages in thread
From: Antti Laakso @ 2026-09-30 13:17 UTC (permalink / raw)
To: Manik Bajpai; +Cc: sakari.ailus, linux-media, sarang.sapre
Hi Manik,
On Tue, Sep 29, 2026 at 02:01:28PM +0530, Manik Bajpai wrote:
> __ipu7_power_on() and __ipu7_power_off() both return early when the
> pwr_status readl_poll_timeout() call times out, skipping cleanup that
> was previously done only on the success path:
>
> - __ipu7_power_on() left the clock-ownership override bit set in
> SLEEP_LEVEL_CFG instead of clearing it, which could break
> subsequent power transitions.
>
> - __ipu7_power_off() skipped D2D power-down and NDE-disable, leaving
> those subsystems powered despite reporting a failure.
>
> - Additionally, the return value of ipu7_isys_d2d_power() in
> __ipu7_power_off() was discarded, silently masking D2D power-down
> failures.
>
> Always run the clock-override clear / D2D-NDE teardown regardless of
> whether the status poll timed out, and propagate a D2D power-down
> failure through the return value when the poll itself succeeded.
>
> Assisted-by: Claude:claude-sonnet-5
> Signed-off-by: Manik Bajpai <manik.bajpai@intel.com>
> ---
> drivers/media/pci/intel/ipu6/ipu6-buttress.c | 24 ++++++++++++--------
> 1 file changed, 15 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
> index 105de1744dff..06a773b5b66b 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
> +++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
> @@ -530,16 +530,15 @@ static int __ipu7_power_on(struct device *dev,
> ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
> val, (val & ctrl->pwr_sts_mask) == pwr_sts,
> 100, BUTTRESS_POWER_TIMEOUT_US);
> - if (ret) {
> + if (ret)
> dev_err(&isp->pdev->dev,
> "Change power status timeout with 0x%x\n", val);
> - return ret;
> - }
>
> + /* Always drop the clock override, even if the poll above timed out. */
> slp = readl(isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
> writel(slp & ~ovrd_clk, isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
>
> - return 0;
> + return ret;
> }
>
> static int __ipu7_power_off(struct device *dev,
> @@ -555,18 +554,25 @@ static int __ipu7_power_off(struct device *dev,
> ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
> val, (val & ctrl->pwr_sts_mask) == pwr_sts,
> 100, BUTTRESS_POWER_TIMEOUT_US);
> - if (ret) {
> + if (ret)
> dev_err(&isp->pdev->dev,
> "Change power status timeout with 0x%x\n", val);
> - return ret;
> - }
>
I wonder if powering down D2D/NDE is right thing to do. In a caller,
bus_pm_runtime_suspend(), we try to recover from error and call
isys_runtime_pm_resume(). But after this change the D2D and NDE
would be powered off and recovery would not make sense.
> + /* Always release D2D/NDE, even if the power status poll timed out. */
> if (ctrl->subsys_id == IPU_ISYS) {
> - ipu7_isys_d2d_power(isp, false);
> + int d2d_ret;
> +
> + d2d_ret = ipu7_isys_d2d_power(isp, false);
> + if (d2d_ret) {
> + dev_err(&isp->pdev->dev,
> + "D2D power down failed (%d)\n", d2d_ret);
> + if (!ret)
> + ret = d2d_ret;
> + }
> ipu7_nde_control(isp, false);
> }
>
> - return 0;
> + return ret;
> }
>
> static int __ipu6_power(struct device *dev,
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-09-30 13:17 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-28 11:56 [PATCH v1 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 1/4] media: ipu6: Free boot config on queue memory alloc failure Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 2/4] media: ipu6: Always run cleanup in ipu7 power on/off on timeout Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 3/4] media: ipu6: Validate fw-com queue indices before use Manik Bajpai
2026-09-28 11:56 ` [PATCH v1 4/4] media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys() Manik Bajpai
2026-09-28 12:08 ` Sakari Ailus
2026-09-29 8:31 ` [PATCH v2 0/4] media: ipu6: A few defensive fixes for ipu7 buttress, fw-com and mmu paths Manik Bajpai
2026-09-29 8:31 ` [PATCH v2 1/4] media: ipu6: Free boot config on queue memory alloc failure Manik Bajpai
2026-09-30 8:53 ` Sakari Ailus
2026-09-29 8:31 ` [PATCH v2 2/4] media: ipu6: Always run cleanup in ipu7 power on/off on timeout Manik Bajpai
2026-09-30 13:17 ` Antti Laakso
2026-09-29 8:31 ` [PATCH v2 3/4] media: ipu6: Validate fw-com queue indices before use Manik Bajpai
2026-09-29 8:31 ` [PATCH v2 4/4] media: ipu6: Fix NULL deref in ipu6_mmu_iova_to_phys() Manik Bajpai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox