On Tue Sep 29 15:37:30 2026 +0100, David Carlier wrote:
> ipu6_isys_fwcom_cfg_init() runs on every first stream start and allocates
> the firmware config and queue configs with devm, so each STREAMON/STREAMOFF
> cycle leaks them. They are only needed until ipu6_fw_com_prepare() has
> copied them, so free them right after. Also check the return value, an
> allocation failure would otherwise make ipu6_fw_com_prepare() dereference
> a NULL queue config.
> 
> Fixes: f625e8d7ffc1 ("media: intel/ipu6: input system ABI between firmware 
> and driver")
> Cc: [email protected]
> Signed-off-by: David Carlier <[email protected]>
> Signed-off-by: Sakari Ailus <[email protected]>

Patch committed.

Thanks,
Sakari Ailus

 drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 34 ++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 10 deletions(-)

---

diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c 
b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index f4f1cf7c86d2..56bb67869bdd 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -208,7 +208,6 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
        unsigned int max_send_queues, max_sram_blocks, max_devq_size;
        struct ipu6_fw_syscom_queue_config *input_queue_cfg;
        struct ipu6_fw_syscom_queue_config *output_queue_cfg;
-       struct device *dev = &isys->adev->auxdev.dev;
        int type_proxy = IPU6_FW_ISYS_QUEUE_TYPE_PROXY;
        int type_dev = IPU6_FW_ISYS_QUEUE_TYPE_DEV;
        int type_msg = IPU6_FW_ISYS_QUEUE_TYPE_MSG;
@@ -218,7 +217,6 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
        struct ipu6_fw_isys_fw_config *isys_fw_cfg;
        u32 num_in_message_queues;
        unsigned int max_streams;
-       unsigned int size;
        unsigned int i;
 
        max_streams = isys->pdata->ipdata->max_streams;
@@ -226,7 +224,7 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
        max_sram_blocks = isys->pdata->ipdata->max_sram_blocks;
        max_devq_size = isys->pdata->ipdata->max_devq_size;
        num_in_message_queues = clamp(num_streams, 1U, max_streams);
-       isys_fw_cfg = devm_kzalloc(dev, sizeof(*isys_fw_cfg), GFP_KERNEL);
+       isys_fw_cfg = kzalloc_obj(*isys_fw_cfg);
        if (!isys_fw_cfg)
                return -ENOMEM;
 
@@ -238,15 +236,14 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys 
*isys,
        isys_fw_cfg->num_recv_queues[type_dev] = 0;
        isys_fw_cfg->num_recv_queues[type_msg] = 1;
 
-       size = sizeof(*input_queue_cfg) * max_send_queues;
-       input_queue_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
+       input_queue_cfg = kzalloc_objs(*input_queue_cfg, max_send_queues);
        if (!input_queue_cfg)
-               return -ENOMEM;
+               goto err_free_fw_cfg;
 
-       size = sizeof(*output_queue_cfg) * IPU6_N_MAX_RECV_QUEUES;
-       output_queue_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
+       output_queue_cfg = kzalloc_objs(*output_queue_cfg,
+                                       IPU6_N_MAX_RECV_QUEUES);
        if (!output_queue_cfg)
-               return -ENOMEM;
+               goto err_free_input_queue_cfg;
 
        fwcom_cfg->input = input_queue_cfg;
        fwcom_cfg->output = output_queue_cfg;
@@ -311,6 +308,20 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
        fwcom_cfg->specific_size = sizeof(*isys_fw_cfg);
 
        return 0;
+
+err_free_input_queue_cfg:
+       kfree(input_queue_cfg);
+err_free_fw_cfg:
+       kfree(isys_fw_cfg);
+
+       return -ENOMEM;
+}
+
+static void ipu6_isys_fwcom_cfg_free(struct ipu6_fw_com_cfg *fwcom_cfg)
+{
+       kfree(fwcom_cfg->specific_addr);
+       kfree(fwcom_cfg->output);
+       kfree(fwcom_cfg->input);
 }
 
 static int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
@@ -324,10 +335,13 @@ static int ipu6_fw_isys_init(struct ipu6_isys *isys, 
unsigned int num_streams)
        };
        int ret;
 
-       ipu6_isys_fwcom_cfg_init(isys, &fwcom_cfg, num_streams);
+       ret = ipu6_isys_fwcom_cfg_init(isys, &fwcom_cfg, num_streams);
+       if (ret)
+               return ret;
 
        isys->fwctx = ipu6_fw_com_prepare(&fwcom_cfg, isys->adev,
                                          isys->pdata->base);
+       ipu6_isys_fwcom_cfg_free(&fwcom_cfg);
        if (!isys->fwctx) {
                dev_err(dev, "isys fw com prepare failed\n");
                return -EIO;
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to