]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
media: venus: don't de-reference NULL pointers at IRQ time
authorMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Sat, 23 Aug 2025 02:50:19 +0000 (22:50 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 28 Aug 2025 14:22:57 +0000 (16:22 +0200)
[ Upstream commit 686ee9b6253f9b6d7f1151e73114698940cc0894 ]

Smatch is warning that:
drivers/media/platform/qcom/venus/hfi_venus.c:1100 venus_isr() warn: variable dereferenced before check 'hdev' (see line 1097)

The logic basically does:
hdev = to_hfi_priv(core);

with is translated to:
hdev = core->priv;

If the IRQ code can receive a NULL pointer for hdev, there's
a bug there, as it will first try to de-reference the pointer,
and then check if it is null.

After looking at the code, it seems that this indeed can happen:
Basically, the venus IRQ thread is started with:
devm_request_threaded_irq()
So, it will only be freed after the driver unbinds.

In order to prevent the IRQ code to work with freed data,
the logic at venus_hfi_destroy() sets core->priv to NULL,
which would make the IRQ code to ignore any pending IRQs.

There is, however a race condition, as core->priv is set
to NULL only after being freed. So, we need also to move the
core->priv = NULL to happen earlier.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Stable-dep-of: 640803003cd9 ("media: venus: hfi: explicitly release IRQ during teardown")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/media/platform/qcom/venus/hfi_venus.c

index df6264d03226ccb06f7ef4dc1b875d76359ea1d8..6f935fc1a55545d3d784147f662b60ea6ca081b1 100644 (file)
@@ -1071,12 +1071,15 @@ static irqreturn_t venus_isr(struct venus_core *core)
 {
        struct venus_hfi_device *hdev = to_hfi_priv(core);
        u32 status;
-       void __iomem *cpu_cs_base = hdev->core->cpu_cs_base;
-       void __iomem *wrapper_base = hdev->core->wrapper_base;
+       void __iomem *cpu_cs_base;
+       void __iomem *wrapper_base;
 
        if (!hdev)
                return IRQ_NONE;
 
+       cpu_cs_base = hdev->core->cpu_cs_base;
+       wrapper_base = hdev->core->wrapper_base;
+
        status = readl(wrapper_base + WRAPPER_INTR_STATUS);
 
        if (status & WRAPPER_INTR_STATUS_A2H_MASK ||
@@ -1613,10 +1616,10 @@ void venus_hfi_destroy(struct venus_core *core)
 {
        struct venus_hfi_device *hdev = to_hfi_priv(core);
 
+       core->priv = NULL;
        venus_interface_queues_release(hdev);
        mutex_destroy(&hdev->lock);
        kfree(hdev);
-       core->priv = NULL;
        core->ops = NULL;
 }