In ibmvfc_send_event(), the non-H_CLOSED error path uses a bare else
clause to handle the case where evt->cmnd is NULL, assuming the event
must be a MAD and reassigning evt->done = evt->_done before calling it.

However, SCSI Task Management Function (TMF) events created by
ibmvfc_init_tmf() are initialised with IBMVFC_CMD_FORMAT, not
IBMVFC_MAD_FORMAT. ibmvfc_init_event() only populates evt->_done for
IBMVFC_MAD_FORMAT events; for IBMVFC_CMD_FORMAT events evt->_done is
never set. Since TMF events also have evt->cmnd == NULL (cleared by
ibmvfc_init_event()), they fall through to the bare else branch,
copying the uninitialised evt->_done into evt->done and immediately
calling it — a wild function-pointer dereference that results in a
kernel panic during SCSI error recovery under SAN error conditions.

Fix this by replacing the bare else with
'else if (evt->crq.format == IBMVFC_MAD_FORMAT)', gating the _done
reassignment strictly on the MAD format where evt->_done is guaranteed
to be valid. TMF events (IBMVFC_CMD_FORMAT, cmnd==NULL) no longer reach
this branch; their evt->done (ibmvfc_locked_done wrapping
ibmvfc_sync_completion) remains correct as initialised, allowing the
waiting ibmvfc_cancel_all_sq/mq paths to receive the completion
normally.

Fixes: 848c70852e3f ("ibmvfc: split NVMe support into separate source file and 
add transport stubs")
Signed-off-by: Tyrel Datwyler <[email protected]>
---
 drivers/scsi/ibmvscsi/ibmvfc-core.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c 
b/drivers/scsi/ibmvscsi/ibmvfc-core.c
index 728529155ded..e4a21ca6815d 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc-core.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c
@@ -1859,9 +1859,12 @@ int ibmvfc_send_event(struct ibmvfc_event *evt,
                        evt->done = ibmvfc_vfc_eh_done;
                } else if (evt->fcp_req || evt->ls_req) {
                        evt->done = ibmvfc_vfc_eh_done;
-               } else {
+               } else if (evt->crq.format == IBMVFC_MAD_FORMAT) {
                        evt->xfer_iu->mad_common.status = 
cpu_to_be16(IBMVFC_MAD_CRQ_ERROR);
                        evt->done = evt->_done;
+               } else {
+                       evt->xfer_iu->cmd.status = 
cpu_to_be16(IBMVFC_VIOS_FAILURE);
+                       evt->xfer_iu->cmd.error = 
cpu_to_be16(IBMVFC_CRQ_FAILURE);
                }
 
                evt->done(evt);
-- 
2.55.0


Reply via email to