From cb23bc8b4ac119568830f48c5e63a7b37212aeab Mon Sep 17 00:00:00 2001 From: Kamal Agrawal Date: Tue, 13 Apr 2021 22:44:05 +0530 Subject: [PATCH] msm: kgsl: Fix possible NULL pointer dereference Return value of alloc_workqueue is not checked and as a result, a possible NULL pointer dereference could occur. Change-Id: I608d12601227f125625a97c1d0da37e3386cf306 Signed-off-by: Kamal Agrawal --- drivers/gpu/msm/kgsl.c | 39 +++++++++++++++++++++++++++++---- drivers/gpu/msm/kgsl_pwrscale.c | 16 ++++++++++---- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 24f45d62fbda..34fd51be14ac 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -4387,6 +4387,15 @@ int kgsl_device_platform_probe(struct kgsl_device *device) idr_init(&device->timelines); spin_lock_init(&device->timelines_lock); + device->events_wq = alloc_workqueue("kgsl-events", + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS | WQ_HIGHPRI, 0); + + if (!device->events_wq) { + dev_err(device->dev, "Failed to allocate events workqueue\n"); + status = -ENOMEM; + goto error_pwrctrl_close; + } + kgsl_device_debugfs_init(device); dma_set_coherent_mask(&pdev->dev, KGSL_DMA_BIT_MASK); @@ -4394,9 +4403,6 @@ int kgsl_device_platform_probe(struct kgsl_device *device) /* Set up the GPU events for the device */ kgsl_device_events_probe(device); - device->events_wq = alloc_workqueue("kgsl-events", - WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS | WQ_HIGHPRI, 0); - /* Initialize common sysfs entries */ kgsl_pwrctrl_init_sysfs(device); @@ -4411,7 +4417,10 @@ error: void kgsl_device_platform_remove(struct kgsl_device *device) { - destroy_workqueue(device->events_wq); + if (device->events_wq) { + destroy_workqueue(device->events_wq); + device->events_wq = NULL; + } kgsl_device_snapshot_close(device); @@ -4441,6 +4450,16 @@ void kgsl_core_exit(void) { kgsl_exit_page_pools(); + if (kgsl_driver.workqueue) { + destroy_workqueue(kgsl_driver.workqueue); + kgsl_driver.workqueue = NULL; + } + + if (kgsl_driver.mem_workqueue) { + destroy_workqueue(kgsl_driver.mem_workqueue); + kgsl_driver.mem_workqueue = NULL; + } + kgsl_events_exit(); kgsl_core_debugfs_close(); @@ -4540,9 +4559,21 @@ int __init kgsl_core_init(void) kgsl_driver.workqueue = alloc_workqueue("kgsl-workqueue", WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0); + if (!kgsl_driver.workqueue) { + pr_err("kgsl: Failed to allocate kgsl workqueue\n"); + result = -ENOMEM; + goto err; + } + kgsl_driver.mem_workqueue = alloc_workqueue("kgsl-mementry", WQ_UNBOUND | WQ_MEM_RECLAIM, 0); + if (!kgsl_driver.mem_workqueue) { + pr_err("kgsl: Failed to allocate mem workqueue\n"); + result = -ENOMEM; + goto err; + } + kthread_init_worker(&kgsl_driver.worker); kgsl_driver.worker_thread = kthread_run(kthread_worker_fn, diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index 995aa28143c2..44ec592325f4 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2010-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2021, The Linux Foundation. All rights reserved. */ #include @@ -855,6 +855,10 @@ int kgsl_pwrscale_init(struct kgsl_device *device, struct platform_device *pdev, adreno_tz_data.bus.floating = false; } + pwrscale->devfreq_wq = create_freezable_workqueue("kgsl_devfreq_wq"); + if (!pwrscale->devfreq_wq) + return -ENOMEM; + devfreq = devfreq_add_device(&pdev->dev, &gpu_profile->profile, governor, &adreno_tz_data); if (IS_ERR(devfreq)) { @@ -876,7 +880,6 @@ int kgsl_pwrscale_init(struct kgsl_device *device, struct platform_device *pdev, ret = sysfs_create_link(&device->dev->kobj, &devfreq->dev.kobj, "devfreq"); - pwrscale->devfreq_wq = create_freezable_workqueue("kgsl_devfreq_wq"); INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend); INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume); INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify); @@ -923,8 +926,13 @@ void kgsl_pwrscale_close(struct kgsl_device *device) devfreq_cooling_unregister(pwrscale->cooling_dev); kgsl_pwrscale_midframe_timer_cancel(device); - flush_workqueue(pwrscale->devfreq_wq); - destroy_workqueue(pwrscale->devfreq_wq); + + if (pwrscale->devfreq_wq) { + flush_workqueue(pwrscale->devfreq_wq); + destroy_workqueue(pwrscale->devfreq_wq); + pwrscale->devfreq_wq = NULL; + } + devfreq_remove_device(device->pwrscale.devfreqptr); kfree(kgsl_midframe); kgsl_midframe = NULL;