Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af59f7fd authored by Chad Dupuis's avatar Chad Dupuis Committed by Greg Kroah-Hartman
Browse files

scsi: qedf: Fix crash when MFW calls for protocol stats while function is still probing

[ Upstream commit ad40f5256095c68dc17c991eb976261d5ea2daaa ]

The MFW may make a call to qed and then to qedf for protocol statistics
while the function is still probing.  If this happens it's possible that
some members of the struct qedf_ctx may not be fully initialized which can
result in a NULL pointer dereference or general protection fault.

To prevent this, add a new flag call QEDF_PROBING and set it when the
__qedf_probe() function is active. Then in the qedf_get_protocol_tlv_data()
function we can check if the function is still probing and return
immediantely before any uninitialized structures can be touched.

Link: https://lore.kernel.org/r/20200416084314.18851-9-skashyap@marvell.com


Signed-off-by: default avatarChad Dupuis <cdupuis@marvell.com>
Signed-off-by: default avatarSaurav Kashyap <skashyap@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent e81df5b3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -335,6 +335,7 @@ struct qedf_ctx {
#define QEDF_GRCDUMP_CAPTURE		4
#define QEDF_IN_RECOVERY		5
#define QEDF_DBG_STOP_IO		6
#define QEDF_PROBING			8
	unsigned long flags; /* Miscellaneous state flags */
	int fipvlan_retries;
	u8 num_queues;
+31 −4
Original line number Diff line number Diff line
@@ -2961,7 +2961,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
{
	int rc = -EINVAL;
	struct fc_lport *lport;
	struct qedf_ctx *qedf;
	struct qedf_ctx *qedf = NULL;
	struct Scsi_Host *host;
	bool is_vf = false;
	struct qed_ll2_params params;
@@ -2989,6 +2989,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)

		/* Initialize qedf_ctx */
		qedf = lport_priv(lport);
		set_bit(QEDF_PROBING, &qedf->flags);
		qedf->lport = lport;
		qedf->ctlr.lp = lport;
		qedf->pdev = pdev;
@@ -3011,9 +3012,12 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
	} else {
		/* Init pointers during recovery */
		qedf = pci_get_drvdata(pdev);
		set_bit(QEDF_PROBING, &qedf->flags);
		lport = qedf->lport;
	}

	QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe started.\n");

	host = lport->host;

	/* Allocate mempool for qedf_io_work structs */
@@ -3312,6 +3316,10 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
	else
		fc_fabric_login(lport);

	QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe done.\n");

	clear_bit(QEDF_PROBING, &qedf->flags);

	/* All good */
	return 0;

@@ -3337,6 +3345,11 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
err1:
	scsi_host_put(lport->host);
err0:
	if (qedf) {
		QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe done.\n");

		clear_bit(QEDF_PROBING, &qedf->flags);
	}
	return rc;
}

@@ -3484,11 +3497,25 @@ void qedf_get_protocol_tlv_data(void *dev, void *data)
{
	struct qedf_ctx *qedf = dev;
	struct qed_mfw_tlv_fcoe *fcoe = data;
	struct fc_lport *lport = qedf->lport;
	struct Scsi_Host *host = lport->host;
	struct fc_host_attrs *fc_host = shost_to_fc_host(host);
	struct fc_lport *lport;
	struct Scsi_Host *host;
	struct fc_host_attrs *fc_host;
	struct fc_host_statistics *hst;

	if (!qedf) {
		QEDF_ERR(NULL, "qedf is null.\n");
		return;
	}

	if (test_bit(QEDF_PROBING, &qedf->flags)) {
		QEDF_ERR(&qedf->dbg_ctx, "Function is still probing.\n");
		return;
	}

	lport = qedf->lport;
	host = lport->host;
	fc_host = shost_to_fc_host(host);

	/* Force a refresh of the fc_host stats including offload stats */
	hst = qedf_fc_get_host_stats(host);