| From 85bc1f778753e67b75deca2c9997700c9d977945 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 27 May 2021 17:06:26 +0200 |
| Subject: media: stm32: Potential NULL pointer dereference in dcmi_irq_thread() |
| |
| From: Dmitriy Ulitin <ulitin@ispras.ru> |
| |
| [ Upstream commit 548fa43a58696450c15b8f5564e99589c5144664 ] |
| |
| At the moment of enabling irq handling: |
| |
| 1922 ret = devm_request_threaded_irq(&pdev->dev, irq, dcmi_irq_callback, |
| 1923 dcmi_irq_thread, IRQF_ONESHOT, |
| 1924 dev_name(&pdev->dev), dcmi); |
| |
| there is still uninitialized field sd_format of struct stm32_dcmi *dcmi. |
| If an interrupt occurs in the interval between the installation of the |
| interrupt handler and the initialization of this field, NULL pointer |
| dereference happens. |
| |
| This field is dereferenced in the handler function without any check: |
| |
| 457 if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG && |
| 458 dcmi->misr & IT_FRAME) { |
| |
| The patch moves interrupt handler installation |
| after initialization of the sd_format field that happens in |
| dcmi_graph_notify_complete() via dcmi_set_default_fmt(). |
| |
| Found by Linux Driver Verification project (linuxtesting.org). |
| |
| Signed-off-by: Dmitriy Ulitin <ulitin@ispras.ru> |
| Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru> |
| Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> |
| Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/media/platform/stm32/stm32-dcmi.c | 19 +++++++++++-------- |
| 1 file changed, 11 insertions(+), 8 deletions(-) |
| |
| diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c |
| index d41475f56ab54..72798aae7a628 100644 |
| --- a/drivers/media/platform/stm32/stm32-dcmi.c |
| +++ b/drivers/media/platform/stm32/stm32-dcmi.c |
| @@ -135,6 +135,7 @@ struct stm32_dcmi { |
| int sequence; |
| struct list_head buffers; |
| struct dcmi_buf *active; |
| + int irq; |
| |
| struct v4l2_device v4l2_dev; |
| struct video_device *vdev; |
| @@ -1720,6 +1721,14 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier) |
| return ret; |
| } |
| |
| + ret = devm_request_threaded_irq(dcmi->dev, dcmi->irq, dcmi_irq_callback, |
| + dcmi_irq_thread, IRQF_ONESHOT, |
| + dev_name(dcmi->dev), dcmi); |
| + if (ret) { |
| + dev_err(dcmi->dev, "Unable to request irq %d\n", dcmi->irq); |
| + return ret; |
| + } |
| + |
| return 0; |
| } |
| |
| @@ -1881,6 +1890,8 @@ static int dcmi_probe(struct platform_device *pdev) |
| if (irq <= 0) |
| return irq ? irq : -ENXIO; |
| |
| + dcmi->irq = irq; |
| + |
| dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| if (!dcmi->res) { |
| dev_err(&pdev->dev, "Could not get resource\n"); |
| @@ -1893,14 +1904,6 @@ static int dcmi_probe(struct platform_device *pdev) |
| return PTR_ERR(dcmi->regs); |
| } |
| |
| - ret = devm_request_threaded_irq(&pdev->dev, irq, dcmi_irq_callback, |
| - dcmi_irq_thread, IRQF_ONESHOT, |
| - dev_name(&pdev->dev), dcmi); |
| - if (ret) { |
| - dev_err(&pdev->dev, "Unable to request irq %d\n", irq); |
| - return ret; |
| - } |
| - |
| mclk = devm_clk_get(&pdev->dev, "mclk"); |
| if (IS_ERR(mclk)) { |
| if (PTR_ERR(mclk) != -EPROBE_DEFER) |
| -- |
| 2.33.0 |
| |