Re: [PATCH v2 4/5] scsi: elx: efct: free the RQ buffers already allocated when one fails
[email protected] Thu, 06 Aug 2026 20:38:10 +0000
| Newsgroups | gmane.linux.scsi |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: Pre-existing issues: - [High] Extensive memory and DMA buffer leaks on device probe and initialization error paths. - [High] Double-free and use-after-free vulnerability on the error path of efct_hw_new_rq_set(). - [High] Unsafe teardown of stats_timer leading to Use-After-Free and timer wheel corruption. - [High] Invalid use of `timer_setup()` within the timer callback. - [High] Error path in efct_hw_setup_io() leaks successfully allocated hw->io[i] inner objects. -- --- Patch [4]: [PATCH v2 4/5] scsi: elx: efct: free the RQ buffers already allocated when one fails --- commit be8b053b462b939279de3cc82f2caf1d37ac0767 Author: Ali Ahmet Memis <[email protected]> scsi: elx: efct: free the RQ buffers already allocated when one fails efct_hw_rx_buffer_alloc() allocates an array of descriptors and then a coherent DMA buffer for each entry. When one of those allocations fails it frees the array and returns NULL, leaving every buffer allocated before it mapped. This commit uses efct_hw_rx_buffer_free() for the entries that were filled in to fix the leak. > diff --git a/drivers/scsi/elx/efct/efct_hw.c b/drivers/scsi/elx/efct/efct_hw.c > index db68516e80750..d645ce256b8aa 100644 > --- a/drivers/scsi/elx/efct/efct_hw.c > +++ b/drivers/scsi/elx/efct/efct_hw.c > @@ -1170,6 +1170,10 @@ efct_get_wwpn(struct efct_hw *hw) > return get_unaligned_be64(p); > } > > +static void > +efct_hw_rx_buffer_free(struct efct_hw *hw, struct efc_hw_rq_buffer *rq_buf, > + u32 count); > + > static struct efc_hw_rq_buffer * > efct_hw_rx_buffer_alloc(struct efct_hw *hw, u32 rqindex, u32 count, > u32 size) > @@ -1196,7 +1200,7 @@ efct_hw_rx_buffer_alloc(struct efct_hw *hw, u32 rqindex, u32 count, > GFP_KERNEL); > if (!prq->dma.virt) { > efc_log_err(hw->os, "DMA allocation failed\n"); > - kfree(rq_buf); > + efct_hw_rx_buffer_free(hw, rq_buf, i); > return NULL; > } > } [Severity: High] This is a pre-existing issue, but does this error path still leak memory? In efct_hw_rx_allocate(): if (!rq->hdr_buf) { efc_log_err(efct, "rx_buffer_alloc hdr_buf failed\n"); rc = -EIO; break; } If efct_hw_rx_buffer_alloc() fails for any queue index, it breaks the loop and returns -EIO, but it appears to leak all hdr_buf and payload_buf DMA buffer arrays that were successfully allocated in previous iterations. Furthermore, in efct_hw_init(): rc = efct_hw_rx_allocate(hw); if (rc) { efc_log_err(hw->os, "rx_allocate failed\n"); return rc; } It returns early on nested allocation failures without cleaning up its own previous local allocations. Finally, in efct_xport_initialize(): rc = efct_hw_init(&efct->hw); if (rc) { efc_log_err(efct, "efct_hw_init failure\n"); goto out; } It jumps directly to out: on efct_hw_init() failure, skipping the hw_init_out: label where efct_hw_teardown() is called. This seems to leak hardware resources initialized during efct_hw_setup() and efct_hw_init() when the probe fails. [Severity: High] This is a pre-existing issue, but can this error path lead to a double-free? In efct_hw_new_rq_set(): list_add_tail(&rqs[i]->list_entry, &cqs[i]->q_list); size = sizeof(struct efc_hw_sequence *) * rqs[i]->entry_count; rqs[i]->rq_tracker = kzalloc(size, GFP_KERNEL); if (!rqs[i]->rq_tracker) goto error; If kzalloc() fails, it jumps to the error label: error: for (i = 0; i < num_rq_pairs; i++) { if (rqs[i]) { kfree(rqs[i]->rq_tracker); kfree(rqs[i]); } } This frees rqs[i] but does not remove it from the cqs[i]->q_list. The function then returns -EIO, triggering efct_hw_queue_teardown(hw), which calls efct_hw_del_rq(): list_del(&rq->list_entry); hw = rq->cq->eq->hw; hw->hw_rq[rq->instance] = NULL; kfree(rq); The teardown iterates over the list, dereferences the already freed rq object, calls list_del() on it, and then calls kfree(rq) again. Does this double-free the object and corrupt the list? [Severity: High] This is a pre-existing issue, but is the teardown of stats_timer safe here? In efct_xport_detach(): if (timer_pending(&xport->stats_timer)) timer_delete(&xport->stats_timer); If the timer callback efct_xport_stats_timer_cb() is actively running on another CPU, timer_pending() might return false. Even if timer_delete() is called, it does not wait for the concurrent callback to finish. This could allow efct_xport_detach() to proceed and eventually free the xport object while the timer callback is still executing. The callback would then access the freed xport memory and call mod_timer(), inserting a freed timer structure back into the kernel's active timer wheel. Should this unconditionally use timer_delete_sync() without the timer_pending() check? [Severity: High] This is a pre-existing issue, but is it correct to call timer_setup() here? In efct_xport_config_stats_timer(): timer_setup(&xport->stats_timer, &efct_xport_stats_timer_cb, 0); mod_timer(&xport->stats_timer, jiffies + msecs_to_jiffies(timeout)); This function is called both for initial setup and from within the timer callback itself (efct_xport_stats_timer_cb()) to re-arm the timer. Calling timer_setup() on a timer that is actively being processed by the timer subsystem resets the structure, clearing list pointers and lock-related fields. Does this destroy the active timer structure and lead to kernel state corruption? [Severity: High] This is a pre-existing issue, but does this error path leak the inner IO objects? In efct_hw_setup_io(): hw->wqe_buffs = kzalloc((hw->config.n_io * hw->sli.wqe_size), GFP_KERNEL); if (!hw->wqe_buffs) { kfree(hw->io); return -ENOMEM; } If the allocation for hw->wqe_buffs fails, the code frees the outer hw->io array and returns -ENOMEM. However, it appears to completely skip the loop in the error block that frees the individual hw->io[i] objects allocated prior to this, which would permanently leak them. -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=4