[PATCH] scsi: lpfc: Add NULL check for vport in lpfc_dev_loss_tmo_callbk

From: Vaibhav Nagare

Date: Mon Jun 29 2026 - 12:12:26 EST


Fix a kernel NULL pointer dereference in lpfc_dev_loss_tmo_callbk()
when ndlp->vport is NULL during FC remote port deletion.

The crash occurs during fc_rport_final_delete() when the vport has
already been cleared on the ndlp structure, but the dev_loss_tmo
callback is still invoked. This is a race condition during port
removal where the vport is destroyed before the rport cleanup completes.

The existing code checks if ndlp is NULL but does not verify that
ndlp->vport is valid before dereferencing it to access vport->phba.

Crash signature observed on RHEL 8.10 (4.18.0-553.125.1.el8_10.x86_64):
BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
RIP: lpfc_dev_loss_tmo_callbk+0x54
Call Trace:
fc_rport_final_delete+0xea/0x1d0 [scsi_transport_fc]
process_one_work+0x1d3/0x390
worker_thread+0x30/0x390

Add a NULL check for vport after retrieving it from ndlp. When vport
is NULL, the port is in a teardown state, so we log the condition,
clear the pnode reference to prevent stale pointers, and return early.

Note: Commit 1cced5779e7a ("scsi: lpfc: Ensure HBA_SETUP flag is used
only for SLI4 in dev_loss_tmo_callbk") addressed a different issue
further down in the function and does not prevent this crash.

Signed-off-by: Vaibhav Nagare <vnagare@xxxxxxxxxx>
---
drivers/scsi/lpfc/lpfc_hbadisc.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index f3a85f6c796e..b8649c40b537 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -168,6 +168,22 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
return;

vport = ndlp->vport;
+ if (!vport) {
+ /*
+ * Vport is NULL - this can happen during teardown when the
+ * vport has been destroyed but the rport final delete is
+ * still processing. Clear the association and return.
+ */
+ pr_err("lpfc: Null vport on ndlp %p, DID x%06x rport %p\n",
+ ndlp, ndlp->nlp_DID, rport);
+
+ spin_lock_irqsave(&ndlp->lock, iflags);
+ ((struct lpfc_rport_data *)rport->dd_data)->pnode = NULL;
+ ndlp->rport = NULL;
+ spin_unlock_irqrestore(&ndlp->lock, iflags);
+ return;
+ }
+
phba = vport->phba;

lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
--
2.54.0