Commit 686ee9b6 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

media: venus: don't de-reference NULL pointers at IRQ time



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: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent b6f13994
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -1094,12 +1094,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 (IS_V6(core)) {
		if (status & WRAPPER_INTR_STATUS_A2H_MASK ||
@@ -1650,10 +1653,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;
}