* [PATCH v2 0/5] media: iris: Fix issues in the driver unbind path
@ 2026-11-10 14:09 Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 1/5] media: iris: Fix runtime PM reference imbalance on failed resume Vishnu Reddy
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Vishnu Reddy @ 2026-11-10 14:09 UTC (permalink / raw)
To: Vikash Garodia, Dikshita Agarwal, Abhinav Kumar,
Bryan O'Donoghue, Mauro Carvalho Chehab, Hans Verkuil,
Stefan Schmidt, Dmitry Baryshkov, Vishnu Reddy, Hungyu Lin
Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue,
stable, sashiko-bot
The driver unbind can be triggered through sysfs while a client has a
video session running. The devm resources are freed when the unbind
completes. That leads to use after free for the running sessions.
The core and its device are now kept allocated until the last file
descriptor is closed. New sessions are stopped as soon as the removal
starts. The interrupt is freed before the core, so the interrupt thread
cannot run on freed memory.
The system error work was only cancelled during the removal. An
interrupt could still arrive afterwards and queue the work again. The
work is now disabled.
The runtime PM usage count was dropped twice when a resume failed. This
happens for a command written after runtime PM is disabled. The count
underflowed. The reference is no longer dropped a second time.
Signed-off-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
---
Changes in v2:
- Updated the commit description of patch 3 (Bryan)
- Split the interrupt freeing into a separate patch (Bryan)
- Added a new patch to wake up clients blocked on open sessions at removal.
- Link to v1: https://lore.kernel.org/r/20261017-iris-handle-unbind-v1-0-7809148eb90f@oss.qualcomm.com
---
Vishnu Reddy (5):
media: iris: Fix runtime PM reference imbalance on failed resume
media: iris: Disable the system error work on removal
media: iris: Fix use-after-free on unbind with open sessions
media: iris: Wake up blocked clients when the driver is removed
media: iris: Free the interrupt in iris_remove()
drivers/media/platform/qcom/iris/iris_core.c | 10 +++-
drivers/media/platform/qcom/iris/iris_core.h | 2 +
drivers/media/platform/qcom/iris/iris_hfi_queue.c | 17 +++++-
drivers/media/platform/qcom/iris/iris_instance.h | 2 +
drivers/media/platform/qcom/iris/iris_power.c | 13 +++++
drivers/media/platform/qcom/iris/iris_probe.c | 64 +++++++++++++++++++----
drivers/media/platform/qcom/iris/iris_vidc.c | 8 +++
7 files changed, 103 insertions(+), 13 deletions(-)
---
base-commit: 630059a5a632377b9b7b487baccde92b7ae1dd47
change-id: 20261013-iris-handle-unbind-fe09689e6696
Best regards,
--
Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/5] media: iris: Fix runtime PM reference imbalance on failed resume
2026-11-10 14:09 [PATCH v2 0/5] media: iris: Fix issues in the driver unbind path Vishnu Reddy
@ 2026-11-10 14:09 ` Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 2/5] media: iris: Disable the system error work on removal Vishnu Reddy
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Vishnu Reddy @ 2026-11-10 14:09 UTC (permalink / raw)
To: Vikash Garodia, Dikshita Agarwal, Abhinav Kumar,
Bryan O'Donoghue, Mauro Carvalho Chehab, Hans Verkuil,
Stefan Schmidt, Dmitry Baryshkov, Vishnu Reddy, Hungyu Lin
Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue, stable
pm_runtime_resume_and_get() drops its usage count when the resume
fails. iris_hfi_queue_cmd_write() dropped it a second time on that
path, resulting in a runtime PM usage count underflow warning:
qcom-iris aa00000.video-codec: Runtime PM usage count underflow!
Fixes: bb8a95aa038e ("media: iris: implement power management")
Cc: stable@vger.kernel.org
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_hfi_queue.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_queue.c b/drivers/media/platform/qcom/iris/iris_hfi_queue.c
index bf6db23b53e21..545bbe75e1740 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_queue.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_queue.c
@@ -132,7 +132,7 @@ int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt, u32 pkt_size)
ret = pm_runtime_resume_and_get(core->dev);
if (ret < 0)
- goto exit;
+ return ret;
mutex_lock(&core->lock);
ret = iris_hfi_queue_cmd_write_locked(core, pkt, pkt_size);
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 2/5] media: iris: Disable the system error work on removal
2026-11-10 14:09 [PATCH v2 0/5] media: iris: Fix issues in the driver unbind path Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 1/5] media: iris: Fix runtime PM reference imbalance on failed resume Vishnu Reddy
@ 2026-11-10 14:09 ` Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 3/5] media: iris: Fix use-after-free on unbind with open sessions Vishnu Reddy
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Vishnu Reddy @ 2026-11-10 14:09 UTC (permalink / raw)
To: Vikash Garodia, Dikshita Agarwal, Abhinav Kumar,
Bryan O'Donoghue, Mauro Carvalho Chehab, Hans Verkuil,
Stefan Schmidt, Dmitry Baryshkov, Vishnu Reddy, Hungyu Lin
Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue, stable
iris_remove() calls cancel_delayed_work_sync() to stop the system error
work. This cancels a pending work and waits for a running one. It does
not stop the work from being queued again afterwards.
A system error interrupt can still arrive after that call. The
interrupt handler queues the work again. The work then runs after the
removal and uses resources that are already freed.
Use disable_delayed_work_sync() instead. Once it returns no new work
can be queued. The work cannot run again during or after the removal.
Fixes: 452480931648 ("media: iris: cancel sys error work on driver removal")
Cc: stable@vger.kernel.org
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_probe.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c
index 343e44c6b9c4..6f02bb629867 100644
--- a/drivers/media/platform/qcom/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/iris/iris_probe.c
@@ -251,7 +251,7 @@ static void iris_remove(struct platform_device *pdev)
if (!core)
return;
- cancel_delayed_work_sync(&core->sys_error_handler);
+ disable_delayed_work_sync(&core->sys_error_handler);
iris_core_deinit(core);
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 3/5] media: iris: Fix use-after-free on unbind with open sessions
2026-11-10 14:09 [PATCH v2 0/5] media: iris: Fix issues in the driver unbind path Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 1/5] media: iris: Fix runtime PM reference imbalance on failed resume Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 2/5] media: iris: Disable the system error work on removal Vishnu Reddy
@ 2026-11-10 14:09 ` Vishnu Reddy
2026-11-10 14:42 ` Bryan O'Donoghue
2026-11-10 14:09 ` [PATCH v2 4/5] media: iris: Wake up blocked clients when the driver is removed Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 5/5] media: iris: Free the interrupt in iris_remove() Vishnu Reddy
4 siblings, 1 reply; 7+ messages in thread
From: Vishnu Reddy @ 2026-11-10 14:09 UTC (permalink / raw)
To: Vikash Garodia, Dikshita Agarwal, Abhinav Kumar,
Bryan O'Donoghue, Mauro Carvalho Chehab, Hans Verkuil,
Stefan Schmidt, Dmitry Baryshkov, Vishnu Reddy, Hungyu Lin
Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue,
sashiko-bot, stable
The driver can be unbound through sysfs while a client has a video
session open. The core is devm allocated and freed when remove()
returns, so the open sessions then use freed memory.
Only the core structure needs to outlive remove(), because it is the
only thing the file operations of an open session still use. Allocate
it with kzalloc and tie it to the reference count of its v4l2_device,
which every registered video device holds. It is freed when the last
file descriptor is closed. The other devm resources (register mapping,
response packet, clocks, power domains, interconnects) are only used by
the power on/off sequence, the clock and bandwidth votes and the
interrupt handler. All of them are released with the unbind, after the
core is shut down.
To make sure nothing uses them afterwards, set a removing flag at the
start of iris_remove(). It makes core init, new sessions, command
writes and the clock and interconnect votes fail with -ENODEV, so a
client still holding a file descriptor cannot power the hardware on or
vote for resources that are gone. A client waiting for the firmware
only times out and returns an error without touching them. Runtime PM
is also disabled explicitly in iris_remove() instead of with devm,
because its callbacks use the core.
Fixes: 38506cb7e8d2 ("media: iris: add platform driver for iris video device")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260926064921.976721F000FF@smtp.kernel.org
Cc: stable@vger.kernel.org
Signed-off-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_core.c | 10 +++++-
drivers/media/platform/qcom/iris/iris_core.h | 2 ++
drivers/media/platform/qcom/iris/iris_hfi_queue.c | 15 +++++++-
drivers/media/platform/qcom/iris/iris_power.c | 13 +++++++
drivers/media/platform/qcom/iris/iris_probe.c | 44 ++++++++++++++++++-----
drivers/media/platform/qcom/iris/iris_vidc.c | 3 ++
6 files changed, 76 insertions(+), 11 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c
index d558475986ff0..bdac6b8c98e44 100644
--- a/drivers/media/platform/qcom/iris/iris_core.c
+++ b/drivers/media/platform/qcom/iris/iris_core.c
@@ -43,7 +43,10 @@ static int iris_wait_for_system_response(struct iris_core *core)
ret = wait_for_completion_timeout(&core->core_init_done,
msecs_to_jiffies(HW_RESPONSE_TIMEOUT_VALUE));
if (!ret) {
- core->state = IRIS_CORE_ERROR;
+ mutex_lock(&core->lock);
+ if (!core->removing)
+ core->state = IRIS_CORE_ERROR;
+ mutex_unlock(&core->lock);
return -ETIMEDOUT;
}
@@ -56,6 +59,11 @@ int iris_core_init(struct iris_core *core)
int ret;
mutex_lock(&core->lock);
+ if (core->removing) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
if (core->state == IRIS_CORE_INIT) {
ret = 0;
goto exit;
diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h
index 3e4cf652bf39a..379f0666a42cb 100644
--- a/drivers/media/platform/qcom/iris/iris_core.h
+++ b/drivers/media/platform/qcom/iris/iris_core.h
@@ -62,6 +62,7 @@ struct qcom_ubwc_cfg_data;
* @iris_firmware_desc: a pointer to the firmware-specific descriptive data
* @ubwc_cfg: UBWC configuration for the platform
* @state: current state of core
+ * @removing: set when driver removal starts, blocks core init and resource votes
* @iface_q_table_daddr: device address for interface queue table memory
* @sfr_daddr: device address for SFR (Sub System Failure Reason) register memory
* @iface_q_table_vaddr: virtual address for interface queue table memory
@@ -108,6 +109,7 @@ struct iris_core {
const struct iris_firmware_desc *iris_firmware_desc;
const struct qcom_ubwc_cfg_data *ubwc_cfg;
enum iris_core_state state;
+ bool removing;
dma_addr_t iface_q_table_daddr;
dma_addr_t sfr_daddr;
void *iface_q_table_vaddr;
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_queue.c b/drivers/media/platform/qcom/iris/iris_hfi_queue.c
index 545bbe75e1740..e0cfa5107d1d9 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_queue.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_queue.c
@@ -128,13 +128,26 @@ int iris_hfi_queue_cmd_write_locked(struct iris_core *core, void *pkt, u32 pkt_s
int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt, u32 pkt_size)
{
- int ret;
+ int ret = 0;
+
+ mutex_lock(&core->lock);
+ if (core->removing)
+ ret = -ENODEV;
+ mutex_unlock(&core->lock);
+ if (ret)
+ return ret;
ret = pm_runtime_resume_and_get(core->dev);
if (ret < 0)
return ret;
mutex_lock(&core->lock);
+ if (core->removing) {
+ mutex_unlock(&core->lock);
+ ret = -ENODEV;
+ goto exit;
+ }
+
ret = iris_hfi_queue_cmd_write_locked(core, pkt, pkt_size);
if (ret) {
mutex_unlock(&core->lock);
diff --git a/drivers/media/platform/qcom/iris/iris_power.c b/drivers/media/platform/qcom/iris/iris_power.c
index 91aa21d4070eb..1f2a7e1bb9e1f 100644
--- a/drivers/media/platform/qcom/iris/iris_power.c
+++ b/drivers/media/platform/qcom/iris/iris_power.c
@@ -47,6 +47,11 @@ static int iris_set_interconnects(struct iris_inst *inst)
int ret;
mutex_lock(&core->lock);
+ if (core->removing) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
list_for_each_entry(instance, &core->instances, list) {
if (!instance->max_input_data_size)
continue;
@@ -56,6 +61,7 @@ static int iris_set_interconnects(struct iris_inst *inst)
ret = iris_set_icc_bw(core, total_bw_ddr);
+exit:
mutex_unlock(&core->lock);
return ret;
@@ -83,6 +89,11 @@ static int iris_set_clocks(struct iris_inst *inst)
int ret;
mutex_lock(&core->lock);
+ if (core->removing) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
list_for_each_entry(instance, &core->instances, list) {
if (!instance->max_input_data_size)
continue;
@@ -92,6 +103,8 @@ static int iris_set_clocks(struct iris_inst *inst)
core->power.clk_freq = freq;
ret = iris_opp_set_rate(core->dev, freq);
+
+exit:
mutex_unlock(&core->lock);
return ret;
diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c
index 6f02bb629867b..dc83daccea5f7 100644
--- a/drivers/media/platform/qcom/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/iris/iris_probe.c
@@ -243,6 +243,22 @@ static int iris_register_video_device(struct iris_core *core, enum domain_type t
return ret;
}
+static void iris_core_release(struct v4l2_device *v4l2_dev)
+{
+ struct iris_core *core = container_of(v4l2_dev, struct iris_core, v4l2_dev);
+
+ mutex_destroy(&core->lock);
+ put_device(core->dev);
+ kfree(core);
+}
+
+static void iris_core_put(void *data)
+{
+ struct iris_core *core = data;
+
+ v4l2_device_put(&core->v4l2_dev);
+}
+
static void iris_remove(struct platform_device *pdev)
{
struct iris_core *core;
@@ -251,18 +267,23 @@ static void iris_remove(struct platform_device *pdev)
if (!core)
return;
+ mutex_lock(&core->lock);
+ core->removing = true;
+ mutex_unlock(&core->lock);
+
+ video_unregister_device(core->vdev_dec);
+ video_unregister_device(core->vdev_enc);
+
disable_delayed_work_sync(&core->sys_error_handler);
iris_core_deinit(core);
- video_unregister_device(core->vdev_dec);
- video_unregister_device(core->vdev_enc);
+ pm_runtime_dont_use_autosuspend(core->dev);
+ pm_runtime_disable(core->dev);
v4l2_device_unregister(&core->v4l2_dev);
iris_unreserve_iova_region(core->dev, core->iova_state);
-
- mutex_destroy(&core->lock);
}
static void iris_sys_error_handler(struct work_struct *work)
@@ -281,15 +302,22 @@ static int iris_probe(struct platform_device *pdev)
u64 dma_mask;
int ret;
- core = devm_kzalloc_obj(&pdev->dev, *core);
+ core = kzalloc_obj(*core);
if (!core)
return -ENOMEM;
- core->dev = dev;
+ core->dev = get_device(dev);
+
+ core->v4l2_dev.release = iris_core_release;
+ kref_init(&core->v4l2_dev.ref);
core->state = IRIS_CORE_DEINIT;
mutex_init(&core->lock);
init_completion(&core->core_init_done);
+ ret = devm_add_action_or_reset(dev, iris_core_put, core);
+ if (ret)
+ return ret;
+
core->response_packet = devm_kzalloc(core->dev, IFACEQ_CORE_PKT_SIZE, GFP_KERNEL);
if (!core->response_packet)
return -ENOMEM;
@@ -354,9 +382,7 @@ static int iris_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(core->dev, AUTOSUSPEND_DELAY_VALUE);
pm_runtime_use_autosuspend(core->dev);
- ret = devm_pm_runtime_enable(core->dev);
- if (ret)
- goto err_vdev_unreg_enc;
+ pm_runtime_enable(core->dev);
return 0;
diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c
index 05aab6e3005d5..04bd37b934457 100644
--- a/drivers/media/platform/qcom/iris/iris_vidc.c
+++ b/drivers/media/platform/qcom/iris/iris_vidc.c
@@ -64,6 +64,9 @@ static int iris_add_session(struct iris_inst *inst)
guard(mutex)(&core->lock);
+ if (core->removing)
+ return -ENODEV;
+
list_for_each_entry(iter, &core->instances, list)
count++;
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 4/5] media: iris: Wake up blocked clients when the driver is removed
2026-11-10 14:09 [PATCH v2 0/5] media: iris: Fix issues in the driver unbind path Vishnu Reddy
` (2 preceding siblings ...)
2026-11-10 14:09 ` [PATCH v2 3/5] media: iris: Fix use-after-free on unbind with open sessions Vishnu Reddy
@ 2026-11-10 14:09 ` Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 5/5] media: iris: Free the interrupt in iris_remove() Vishnu Reddy
4 siblings, 0 replies; 7+ messages in thread
From: Vishnu Reddy @ 2026-11-10 14:09 UTC (permalink / raw)
To: Vikash Garodia, Dikshita Agarwal, Abhinav Kumar,
Bryan O'Donoghue, Mauro Carvalho Chehab, Hans Verkuil,
Stefan Schmidt, Dmitry Baryshkov, Vishnu Reddy, Hungyu Lin
Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue, stable
iris_remove() does not wake up a client that is blocked in
VIDIOC_DQBUF or poll() on an open session. The client stays blocked and
keeps its file descriptor open.
Flag the vb2 queues of all open instances as errored after the core is
shut down. This wakes up the blocked clients, which fail with an error
and can close the file descriptor. Skip the instances that are already
closing, as iris_close() releases their queues.
Fixes: 38506cb7e8d2 ("media: iris: add platform driver for iris video device")
Cc: stable@vger.kernel.org
Signed-off-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_instance.h | 2 ++
drivers/media/platform/qcom/iris/iris_probe.c | 16 ++++++++++++++++
drivers/media/platform/qcom/iris/iris_vidc.c | 5 +++++
3 files changed, 23 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h
index 771269e705d9..cb84753e4f91 100644
--- a/drivers/media/platform/qcom/iris/iris_instance.h
+++ b/drivers/media/platform/qcom/iris/iris_instance.h
@@ -50,6 +50,7 @@ struct iris_hfi_session_ops;
* @icc_data: structure of interconnect data
* @m2m_dev: a reference to m2m device structure
* @m2m_ctx: a reference to m2m context structure
+ * @closing: set on close, skips the queue error during removal
* @sequence_cap: a sequence counter for capture queue
* @sequence_out: a sequence counter for output queue
* @tss: timestamp metadata
@@ -98,6 +99,7 @@ struct iris_inst {
struct icc_vote_data icc_data;
struct v4l2_m2m_dev *m2m_dev;
struct v4l2_m2m_ctx *m2m_ctx;
+ bool closing;
u32 sequence_cap;
u32 sequence_out;
struct iris_ts_metadata tss[VIDEO_MAX_FRAME];
diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c
index dc83daccea5f..51054862bc64 100644
--- a/drivers/media/platform/qcom/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/iris/iris_probe.c
@@ -12,8 +12,10 @@
#include <linux/reset.h>
#include <linux/soc/qcom/ubwc.h>
+#include "iris_buffer.h"
#include "iris_core.h"
#include "iris_ctrls.h"
+#include "iris_instance.h"
#include "iris_vidc.h"
static int iris_init_icc(struct iris_core *core)
@@ -259,6 +261,18 @@ static void iris_core_put(void *data)
v4l2_device_put(&core->v4l2_dev);
}
+static void iris_instances_vb2_queue_error(struct iris_core *core)
+{
+ struct iris_inst *inst;
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ if (!inst->closing)
+ iris_vb2_queue_error(inst);
+ }
+ mutex_unlock(&core->lock);
+}
+
static void iris_remove(struct platform_device *pdev)
{
struct iris_core *core;
@@ -278,6 +292,8 @@ static void iris_remove(struct platform_device *pdev)
iris_core_deinit(core);
+ iris_instances_vb2_queue_error(core);
+
pm_runtime_dont_use_autosuspend(core->dev);
pm_runtime_disable(core->dev);
diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c
index 04bd37b93445..bb3519eff3b1 100644
--- a/drivers/media/platform/qcom/iris/iris_vidc.c
+++ b/drivers/media/platform/qcom/iris/iris_vidc.c
@@ -312,6 +312,11 @@ static void iris_check_num_queued_internal_buffers(struct iris_inst *inst, u32 p
int iris_close(struct file *filp)
{
struct iris_inst *inst = iris_get_inst(filp);
+ struct iris_core *core = inst->core;
+
+ mutex_lock(&core->lock);
+ inst->closing = true;
+ mutex_unlock(&core->lock);
v4l2_ctrl_handler_free(&inst->ctrl_handler);
v4l2_m2m_ctx_release(inst->m2m_ctx);
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 5/5] media: iris: Free the interrupt in iris_remove()
2026-11-10 14:09 [PATCH v2 0/5] media: iris: Fix issues in the driver unbind path Vishnu Reddy
` (3 preceding siblings ...)
2026-11-10 14:09 ` [PATCH v2 4/5] media: iris: Wake up blocked clients when the driver is removed Vishnu Reddy
@ 2026-11-10 14:09 ` Vishnu Reddy
4 siblings, 0 replies; 7+ messages in thread
From: Vishnu Reddy @ 2026-11-10 14:09 UTC (permalink / raw)
To: Vikash Garodia, Dikshita Agarwal, Abhinav Kumar,
Bryan O'Donoghue, Mauro Carvalho Chehab, Hans Verkuil,
Stefan Schmidt, Dmitry Baryshkov, Vishnu Reddy, Hungyu Lin
Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue, stable
The interrupt is requested with devm_request_threaded_irq(), so it is
only freed after iris_remove() returns. Until then the threaded handler
can still run while the rest of the removal is in progress.
Free the interrupt explicitly in iris_remove(), right after the core is
shut down.
Fixes: fb583a214337 ("media: iris: introduce host firmware interface with necessary hooks")
Cc: stable@vger.kernel.org
Signed-off-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_probe.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c
index 51054862bc64..925a450a8597 100644
--- a/drivers/media/platform/qcom/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/iris/iris_probe.c
@@ -292,6 +292,8 @@ static void iris_remove(struct platform_device *pdev)
iris_core_deinit(core);
+ devm_free_irq(core->dev, core->irq, core);
+
iris_instances_vb2_queue_error(core);
pm_runtime_dont_use_autosuspend(core->dev);
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 3/5] media: iris: Fix use-after-free on unbind with open sessions
2026-11-10 14:09 ` [PATCH v2 3/5] media: iris: Fix use-after-free on unbind with open sessions Vishnu Reddy
@ 2026-11-10 14:42 ` Bryan O'Donoghue
0 siblings, 0 replies; 7+ messages in thread
From: Bryan O'Donoghue @ 2026-11-10 14:42 UTC (permalink / raw)
To: Vishnu Reddy, Vikash Garodia, Dikshita Agarwal, Abhinav Kumar,
Bryan O'Donoghue, Mauro Carvalho Chehab, Hans Verkuil,
Stefan Schmidt, Dmitry Baryshkov, Hungyu Lin
Cc: linux-media, linux-arm-msm, linux-kernel, sashiko-bot, stable
On 10/11/2026 14:09, Vishnu Reddy wrote:
> The driver can be unbound through sysfs while a client has a video
> session open. The core is devm allocated and freed when remove()
> returns, so the open sessions then use freed memory.
>
> Only the core structure needs to outlive remove(), because it is the
> only thing the file operations of an open session still use. Allocate
> it with kzalloc and tie it to the reference count of its v4l2_device,
> which every registered video device holds. It is freed when the last
> file descriptor is closed. The other devm resources (register mapping,
> response packet, clocks, power domains, interconnects) are only used by
> the power on/off sequence, the clock and bandwidth votes and the
> interrupt handler. All of them are released with the unbind, after the
> core is shut down.
>
> To make sure nothing uses them afterwards, set a removing flag at the
> start of iris_remove(). It makes core init, new sessions, command
> writes and the clock and interconnect votes fail with -ENODEV, so a
> client still holding a file descriptor cannot power the hardware on or
> vote for resources that are gone. A client waiting for the firmware
> only times out and returns an error without touching them. Runtime PM
> is also disabled explicitly in iris_remove() instead of with devm,
> because its callbacks use the core.
>
> Fixes: 38506cb7e8d2 ("media: iris: add platform driver for iris video device")
> Reported-by: sashiko-bot <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/all/20260926064921.976721F000FF@smtp.kernel.org
> Cc: stable@vger.kernel.org
> Signed-off-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
> ---
> drivers/media/platform/qcom/iris/iris_core.c | 10 +++++-
> drivers/media/platform/qcom/iris/iris_core.h | 2 ++
> drivers/media/platform/qcom/iris/iris_hfi_queue.c | 15 +++++++-
> drivers/media/platform/qcom/iris/iris_power.c | 13 +++++++
> drivers/media/platform/qcom/iris/iris_probe.c | 44 ++++++++++++++++++-----
> drivers/media/platform/qcom/iris/iris_vidc.c | 3 ++
> 6 files changed, 76 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c
> index d558475986ff0..bdac6b8c98e44 100644
> --- a/drivers/media/platform/qcom/iris/iris_core.c
> +++ b/drivers/media/platform/qcom/iris/iris_core.c
> @@ -43,7 +43,10 @@ static int iris_wait_for_system_response(struct iris_core *core)
> ret = wait_for_completion_timeout(&core->core_init_done,
> msecs_to_jiffies(HW_RESPONSE_TIMEOUT_VALUE));
> if (!ret) {
> - core->state = IRIS_CORE_ERROR;
> + mutex_lock(&core->lock);
> + if (!core->removing)
> + core->state = IRIS_CORE_ERROR;
> + mutex_unlock(&core->lock);
> return -ETIMEDOUT;
> }
>
> @@ -56,6 +59,11 @@ int iris_core_init(struct iris_core *core)
> int ret;
>
> mutex_lock(&core->lock);
> + if (core->removing) {
> + ret = -ENODEV;
> + goto exit;
> + }
> +
> if (core->state == IRIS_CORE_INIT) {
> ret = 0;
> goto exit;
> diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h
> index 3e4cf652bf39a..379f0666a42cb 100644
> --- a/drivers/media/platform/qcom/iris/iris_core.h
> +++ b/drivers/media/platform/qcom/iris/iris_core.h
> @@ -62,6 +62,7 @@ struct qcom_ubwc_cfg_data;
> * @iris_firmware_desc: a pointer to the firmware-specific descriptive data
> * @ubwc_cfg: UBWC configuration for the platform
> * @state: current state of core
> + * @removing: set when driver removal starts, blocks core init and resource votes
> * @iface_q_table_daddr: device address for interface queue table memory
> * @sfr_daddr: device address for SFR (Sub System Failure Reason) register memory
> * @iface_q_table_vaddr: virtual address for interface queue table memory
> @@ -108,6 +109,7 @@ struct iris_core {
> const struct iris_firmware_desc *iris_firmware_desc;
> const struct qcom_ubwc_cfg_data *ubwc_cfg;
> enum iris_core_state state;
> + bool removing;
> dma_addr_t iface_q_table_daddr;
> dma_addr_t sfr_daddr;
> void *iface_q_table_vaddr;
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_queue.c b/drivers/media/platform/qcom/iris/iris_hfi_queue.c
> index 545bbe75e1740..e0cfa5107d1d9 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_queue.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_queue.c
> @@ -128,13 +128,26 @@ int iris_hfi_queue_cmd_write_locked(struct iris_core *core, void *pkt, u32 pkt_s
>
> int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt, u32 pkt_size)
> {
> - int ret;
> + int ret = 0;
> +
> + mutex_lock(&core->lock);
> + if (core->removing)
> + ret = -ENODEV;
> + mutex_unlock(&core->lock);
> + if (ret)
> + return ret;
>
> ret = pm_runtime_resume_and_get(core->dev);
> if (ret < 0)
> return ret;
>
> mutex_lock(&core->lock);
> + if (core->removing) {
> + mutex_unlock(&core->lock);
> + ret = -ENODEV;
> + goto exit;
> + }
> +
This locking scheme is looks racy, what's the point of this granularity ?
---
bod
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-11-10 14:42 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-10 14:09 [PATCH v2 0/5] media: iris: Fix issues in the driver unbind path Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 1/5] media: iris: Fix runtime PM reference imbalance on failed resume Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 2/5] media: iris: Disable the system error work on removal Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 3/5] media: iris: Fix use-after-free on unbind with open sessions Vishnu Reddy
2026-11-10 14:42 ` Bryan O'Donoghue
2026-11-10 14:09 ` [PATCH v2 4/5] media: iris: Wake up blocked clients when the driver is removed Vishnu Reddy
2026-11-10 14:09 ` [PATCH v2 5/5] media: iris: Free the interrupt in iris_remove() Vishnu Reddy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®