media: rockchip/rga: fix error handling in probe
authorDan Carpenter <dan.carpenter@oracle.com>
Tue, 13 Jul 2021 09:24:10 +0000 (11:24 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Thu, 22 Jul 2021 12:01:55 +0000 (14:01 +0200)
There are a few bugs in this code.  1)  No checks for whether
dma_alloc_attrs() or __get_free_pages() failed.  2)  If
video_register_device() fails it doesn't clean up the dma attrs or the
free pages.  3)  The video_device_release() function frees "vfd" which
leads to a use after free on the next line.  The call to
video_unregister_device() is not required so I have just removed that.

Fixes: f7e7b48e6d79 ("[media] rockchip/rga: v4l2 m2m support")
Reported-by: Dongliang Mu <mudongliangabcd@gmail.com>
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/platform/rockchip/rga/rga.c

index bf3fd71..6759091 100644 (file)
@@ -863,12 +863,12 @@ static int rga_probe(struct platform_device *pdev)
        if (IS_ERR(rga->m2m_dev)) {
                v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n");
                ret = PTR_ERR(rga->m2m_dev);
-               goto unreg_video_dev;
+               goto rel_vdev;
        }
 
        ret = pm_runtime_resume_and_get(rga->dev);
        if (ret < 0)
-               goto unreg_video_dev;
+               goto rel_vdev;
 
        rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
        rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
@@ -882,11 +882,23 @@ static int rga_probe(struct platform_device *pdev)
        rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
                                           &rga->cmdbuf_phy, GFP_KERNEL,
                                           DMA_ATTR_WRITE_COMBINE);
+       if (!rga->cmdbuf_virt) {
+               ret = -ENOMEM;
+               goto rel_vdev;
+       }
 
        rga->src_mmu_pages =
                (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
+       if (!rga->src_mmu_pages) {
+               ret = -ENOMEM;
+               goto free_dma;
+       }
        rga->dst_mmu_pages =
                (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
+       if (rga->dst_mmu_pages) {
+               ret = -ENOMEM;
+               goto free_src_pages;
+       }
 
        def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
        def_frame.size = def_frame.stride * def_frame.height;
@@ -894,7 +906,7 @@ static int rga_probe(struct platform_device *pdev)
        ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
        if (ret) {
                v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
-               goto rel_vdev;
+               goto free_dst_pages;
        }
 
        v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
@@ -902,10 +914,15 @@ static int rga_probe(struct platform_device *pdev)
 
        return 0;
 
+free_dst_pages:
+       free_pages((unsigned long)rga->dst_mmu_pages, 3);
+free_src_pages:
+       free_pages((unsigned long)rga->src_mmu_pages, 3);
+free_dma:
+       dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
+                      rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
 rel_vdev:
        video_device_release(vfd);
-unreg_video_dev:
-       video_unregister_device(rga->vfd);
 unreg_v4l2_dev:
        v4l2_device_unregister(&rga->v4l2_dev);
 err_put_clk: