There are multiple points in the Linux Kernel where alloc_workqueue is
not getting checked for errors and as a result, a potential NULL
dereference could occur.

I'm attaching a patch for some of them.
There are two cases I left untouched that requires a bit more refactoring:
https://github.com/torvalds/linux/blob/master/drivers/net/wireless/intel/iwlwifi/pcie/trans.c#L3656
https://github.com/torvalds/linux/blob/master/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c#L4508

Regards,
Semmle security team
diff --git a/linux/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c 
b/b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
index c56ac47..252c57e 100644
--- a/linux/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
+++ b/b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
@@ -62,6 +62,11 @@ int kfd_interrupt_init(struct kfd_dev *kfd)
        }
 
        kfd->ih_wq = alloc_workqueue("KFD IH", WQ_HIGHPRI, 1);
+       if( !kfd->ih_wq ) {
+               kfifo_free(&kfd->ih_fifo);
+               dev_err(kfd_chardev(), "Failed to allocate KFD IH workqueue\n");
+               return kfd->ih_wq;
+       }
        spin_lock_init(&kfd->interrupt_lock);
 
        INIT_WORK(&kfd->interrupt_work, interrupt_wq);
diff --git a/linux/drivers/gpu/drm/radeon/radeon_display.c 
b/b/drivers/gpu/drm/radeon/radeon_display.c
index bd52f15..1a49030 100644
--- a/linux/drivers/gpu/drm/radeon/radeon_display.c
+++ b/b/drivers/gpu/drm/radeon/radeon_display.c
@@ -683,6 +683,11 @@ static void radeon_crtc_init(struct drm_device *dev, int 
index)
        drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);
        radeon_crtc->crtc_id = index;
        radeon_crtc->flip_queue = alloc_workqueue("radeon-crtc", WQ_HIGHPRI, 0);
+       if( !radeon_crtc->flip_queue) {
+               kfree(radeon_crtc);
+               return;
+
+       }
        rdev->mode_info.crtcs[index] = radeon_crtc;
 
        if (rdev->family >= CHIP_BONAIRE) {
diff --git a/linux/drivers/net/fjes/fjes_main.c b/b/drivers/net/fjes/fjes_main.c
index bbbc1dc..d850b17 100644
--- a/linux/drivers/net/fjes/fjes_main.c
+++ b/b/drivers/net/fjes/fjes_main.c
@@ -1237,8 +1237,15 @@ static int fjes_probe(struct platform_device *plat_dev)
        adapter->open_guard = false;
 
        adapter->txrx_wq = alloc_workqueue(DRV_NAME "/txrx", WQ_MEM_RECLAIM, 0);
+       if(!adapter->txrx_wq) {
+                goto err_free_netdev;          
+       }
        adapter->control_wq = alloc_workqueue(DRV_NAME "/control",
                                              WQ_MEM_RECLAIM, 0);
+       if(!adapter->control_wq) {
+                destroy_workqueue(adapter->txrx_wq);
+                goto err_free_netdev;
+       }
 
        INIT_WORK(&adapter->tx_stall_task, fjes_tx_stall_task);
        INIT_WORK(&adapter->raise_intr_rxdata_task,
diff --git a/linux/drivers/net/wireless/marvell/libertas/if_sdio.c 
b/b/drivers/net/wireless/marvell/libertas/if_sdio.c
index 242d884..03083eb 100644
--- a/linux/drivers/net/wireless/marvell/libertas/if_sdio.c
+++ b/b/drivers/net/wireless/marvell/libertas/if_sdio.c
@@ -1179,6 +1179,10 @@ static int if_sdio_probe(struct sdio_func *func,
 
        spin_lock_init(&card->lock);
        card->workqueue = alloc_workqueue("libertas_sdio", WQ_MEM_RECLAIM, 0);
+       if(!card->workqueue) {
+               ret = -ENOMEM;
+               goto free_before_queue:;
+       }
        INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
        init_waitqueue_head(&card->pwron_waitq);
 
@@ -1230,6 +1234,7 @@ err_activate_card:
        lbs_remove_card(priv);
 free:
        destroy_workqueue(card->workqueue);
+free_before_queue:
        while (card->packets) {
                packet = card->packets;
                card->packets = card->packets->next;
diff --git a/linux/drivers/scsi/qla2xxx/qla_os.c 
b/b/drivers/scsi/qla2xxx/qla_os.c
index 98e60a3..8f285c5 100644
--- a/linux/drivers/scsi/qla2xxx/qla_os.c
+++ b/b/drivers/scsi/qla2xxx/qla_os.c
@@ -3232,6 +3232,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct 
pci_device_id *id)
            req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out);
 
        ha->wq = alloc_workqueue("qla2xxx_wq", 0, 0);
+       if(!ha->wq) { 
+               ret = -ENOMEM;
+               goto probe_failed;
+       }
 
        if (ha->isp_ops->initialize_adapter(base_vha)) {
                ql_log(ql_log_fatal, base_vha, 0x00d6,

Reply via email to