Re: [PATCH v2 3/5] scsi: elx: efct: free the request tag when the send frame WQE fails

[email protected] Thu, 06 Aug 2026 20:41:27 +0000
Newsgroups gmane.linux.scsi
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

New issues:
- [Medium] The patch adds cleanup code to a mathematically unreachable error path, completely failing to address the actual root cause of the reqtag exhaustion.

Pre-existing issues:
- [Critical] Unconditional freeing of a reused sequence buffer (`seq`) leads to a catastrophic Use-After-Free, Double-Free, and hardware DMA corruption when sending a task set full/busy response.
- [High] Guaranteed NULL pointer dereference when sending a task set full/busy response.
- [High] `efct_hw_reqtag_free()` detects a double-free but incorrectly proceeds to corrupt the freelist.
- [High] `efct_hw_init()` fails to handle `efct_hw_io_alloc()` failure, leading to a NULL pointer dereference.
--

--- Patch [3]: [PATCH v2 3/5] scsi: elx: efct: free the request tag when the send frame WQE fails ---
commit 415b71fb97ba10c30ffb204dfd40acdb37bb24d1
Author: Ali Ahmet Memis <[email protected]>

scsi: elx: efct: free the request tag when the send frame WQE fails

efct_hw_send_frame() takes a request tag from the pool and then builds the
WQE. When sli_send_frame_wqe() fails it returns without giving the tag
back.

> diff --git a/drivers/scsi/elx/efct/efct_hw.c b/drivers/scsi/elx/efct/efct_hw.c
> index 6cc48fa3e656a..db68516e80750 100644
> --- a/drivers/scsi/elx/efct/efct_hw.c
> +++ b/drivers/scsi/elx/efct/efct_hw.c
> @@ -3009,6 +3009,7 @@ efct_hw_send_frame(struct efct_hw *hw, struct fc_frame_header *hdr,
>  				ctx->wqcb->instance_index);
>  	if (rc) {
>  		efc_log_err(hw->os, "sli_send_frame_wqe failed: %d\n", rc);
> +		efct_hw_reqtag_free(hw, ctx->wqcb);
>  		return -EIO;
>  	}

[Severity: Medium]
Does this error path actually ever execute?

Looking at sli_send_frame_wqe(), it appears to unconditionally return 0:

libefc_sli/sli4.c:sli_send_frame_wqe() {
    ...
    return 0;
}

Since sli_send_frame_wqe() always returns 0, this error handling block seems
unreachable. Is there a different root cause for the reqtag exhaustion?


While reviewing this change, I also noticed a few other areas in the driver
that might need attention.

[Severity: Critical]
This isn't a bug introduced by this patch, but does efct_dispatch_frame()
unconditionally free a reused sequence buffer, causing a use-after-free?

When efct_scsi_io_alloc() fails, the driver sends a task set full/busy
response via efct_sframe_common_send(). It allocates the async transmission
context directly inside the incoming sequence's DMA buffer:

efct_unsol.c:efct_sframe_common_send() {
    ctx = (void *)(heap_virt_base + heap_offset);
    ...
    ctx->seq = seq;
}

However, efct_dispatch_frame() ignores the return value of
efct_dispatch_fcp_cmd() and unconditionally frees the sequence:

efct_unsol.c:efct_dispatch_frame() {
    kref_put(&node->ref, node->release);
    efct_hw_sequence_free(&efct->hw, seq);
    return 0;
}

When transmission completes, efct_sframe_common_send_cb() double-frees the
sequence:

efct_unsol.c:efct_sframe_common_send_cb() {
    /* Free sequence */
    efct_hw_sequence_free(hw, ctx->seq);
}

Could this cause memory corruption and hardware DMA issues if the buffer is
returned to the hardware receive ring before the async send completes?


[Severity: High]
This is a pre-existing issue, but does sending a task set full/busy response
result in a NULL pointer dereference?

In efct_sframe_common_send(), the context is zeroed out, leaving wqebuf as
NULL:

efct_unsol.c:efct_sframe_common_send() {
    memset(ctx, 0, sizeof(*ctx));
    ...
}

This uninitialized context is passed to efct_hw_send_frame(), which passes
the NULL wqe->wqebuf to sli_send_frame_wqe():

efct_hw.c:efct_hw_send_frame() {
    rc = sli_send_frame_wqe(&hw->sli, wqe->wqebuf, ...);
}

sli_send_frame_wqe() immediately calls memset() on this NULL buffer:

libefc_sli/sli4.c:sli_send_frame_wqe() {
    memset(buf, 0, sli->wqe_size);
}

Will this guarantee a kernel panic when triggered?


[Severity: High]
This isn't a bug introduced by this patch, but does efct_hw_reqtag_free()
corrupt the freelist if it detects a double-free?

If a tag is already freed, the function logs an error but doesn't return
early:

efct_hw.c:efct_hw_reqtag_free() {
    if (!wqcb->callback)
        efc_log_err(hw->os, "WQCB is already freed\n");

    spin_lock_irqsave(&reqtag_pool->lock, flags);
    wqcb->callback = NULL;
    ...
    INIT_LIST_HEAD(&wqcb->list_entry);
    list_add(&wqcb->list_entry, &hw->wq_reqtag_pool->freelist);
    spin_unlock_irqrestore(&reqtag_pool->lock, flags);
}

If the tag is already in the freelist, doesn't continuing with
INIT_LIST_HEAD() and list_add() completely corrupt the list pointers?


[Severity: High]
This is a pre-existing issue, but does an allocation failure in
efct_hw_init() lead to a NULL pointer dereference later?

If efct_hw_io_alloc() fails, it logs an error but returns success:

efct_hw.c:efct_hw_init() {
    hw->hw_wq[0]->send_frame_io = efct_hw_io_alloc(hw);
    if (!hw->hw_wq[0]->send_frame_io)
        efc_log_err(hw->os, "alloc for send_frame_io failed\n");

    /* Initialize send frame sequence id */
    atomic_set(&hw->send_frame_seq_id, 0);

    return 0;
}

Later, efct_hw_send_frame() unconditionally dereferences it:

efct_hw.c:efct_hw_send_frame() {
    xri = wq->send_frame_io->indicator;
}

Should efct_hw_init() return an error code instead of 0 when this
allocation fails?

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=3