Commit b1b3440f authored by James Smart's avatar James Smart Committed by Martin K. Petersen
Browse files

scsi: lpfc: Resolve NULL ptr dereference after an ELS LOGO is aborted

A use-after-free crash can occur after an ELS LOGO is aborted.

Specifically, a nodelist structure is freed and then
ndlp->vport->cfg_log_verbose is dereferenced in lpfc_nlp_get() when the
discovery state machine is mistakenly called a second time with
NLP_EVT_DEVICE_RM argument.

Rework lpfc_cmpl_els_logo() to prevent the duplicate calls to release a
nodelist structure.

Link: https://lore.kernel.org/r/20220603174329.63777-6-jsmart2021@gmail.com


Co-developed-by: default avatarJustin Tee <justin.tee@broadcom.com>
Signed-off-by: default avatarJustin Tee <justin.tee@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 6f808bd7
Loading
Loading
Loading
Loading
+9 −12
Original line number Diff line number Diff line
@@ -2998,10 +2998,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
				 ndlp->nlp_DID, ulp_status,
				 ulp_word4);

		/* Call NLP_EVT_DEVICE_RM if link is down or LOGO is aborted */
		if (lpfc_error_lost_link(ulp_status, ulp_word4)) {
			lpfc_disc_state_machine(vport, ndlp, cmdiocb,
						NLP_EVT_DEVICE_RM);
			skip_recovery = 1;
			goto out;
		}
@@ -3021,18 +3018,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		spin_unlock_irq(&ndlp->lock);
		lpfc_disc_state_machine(vport, ndlp, cmdiocb,
					NLP_EVT_DEVICE_RM);
		lpfc_els_free_iocb(phba, cmdiocb);
		lpfc_nlp_put(ndlp);

		/* Presume the node was released. */
		return;
		goto out_rsrc_free;
	}

out:
	/* Driver is done with the IO.  */
	lpfc_els_free_iocb(phba, cmdiocb);
	lpfc_nlp_put(ndlp);

	/* At this point, the LOGO processing is complete. NOTE: For a
	 * pt2pt topology, we are assuming the NPortID will only change
	 * on link up processing. For a LOGO / PLOGI initiated by the
@@ -3059,6 +3048,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
				 ndlp->nlp_DID, ulp_status,
				 ulp_word4, tmo,
				 vport->num_disc_nodes);

		lpfc_els_free_iocb(phba, cmdiocb);
		lpfc_nlp_put(ndlp);

		lpfc_disc_start(vport);
		return;
	}
@@ -3075,6 +3068,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		lpfc_disc_state_machine(vport, ndlp, cmdiocb,
					NLP_EVT_DEVICE_RM);
	}
out_rsrc_free:
	/* Driver is done with the I/O. */
	lpfc_els_free_iocb(phba, cmdiocb);
	lpfc_nlp_put(ndlp);
}

/**