diff mbox series

[v3,22/24] mpi3mr: add support of DSN secure fw check

Message ID 20210419110156.1786882-23-kashyap.desai@broadcom.com
State Superseded
Headers show
Series Introducing mpi3mr driver | expand

Commit Message

Kashyap Desai April 19, 2021, 11:01 a.m. UTC
Read PCI_EXT_CAP_ID_DSN to know security status.

Driver will throw an warning message when a non-secure type controller
is detected. Purpose of this interface is to avoid interacting with
any firmware which is not secured/signed by Broadcom.
Any tampering on Firmware component will be detected by hardware
and it will be communicated to the driver to avoid any further
interaction with that component.

Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Tomas Henzl <thenzl@redhat.com>

Cc: sathya.prakash@broadcom.com
---
 drivers/scsi/mpi3mr/mpi3mr.h    |  9 ++++
 drivers/scsi/mpi3mr/mpi3mr_os.c | 80 +++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+)

Comments

Himanshu Madhani April 22, 2021, 5:27 p.m. UTC | #1
> On Apr 19, 2021, at 6:01 AM, Kashyap Desai <kashyap.desai@broadcom.com> wrote:

> 

> Read PCI_EXT_CAP_ID_DSN to know security status.

> 

> Driver will throw an warning message when a non-secure type controller

> is detected. Purpose of this interface is to avoid interacting with

> any firmware which is not secured/signed by Broadcom.

> Any tampering on Firmware component will be detected by hardware

> and it will be communicated to the driver to avoid any further

> interaction with that component.

> 

> Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>

> Reviewed-by: Hannes Reinecke <hare@suse.de>

> Reviewed-by: Tomas Henzl <thenzl@redhat.com>

> 

> Cc: sathya.prakash@broadcom.com

> ---

> drivers/scsi/mpi3mr/mpi3mr.h    |  9 ++++

> drivers/scsi/mpi3mr/mpi3mr_os.c | 80 +++++++++++++++++++++++++++++++++

> 2 files changed, 89 insertions(+)

> 

> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h

> index 505df0e7b852..db9cb11db3bf 100644

> --- a/drivers/scsi/mpi3mr/mpi3mr.h

> +++ b/drivers/scsi/mpi3mr/mpi3mr.h

> @@ -149,6 +149,15 @@ extern struct list_head mrioc_list;

> #define MPI3MR_IRQ_POLL_SLEEP			2

> #define MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT		8

> 

> +/* Definitions for the controller security status*/

> +#define MPI3MR_CTLR_SECURITY_STATUS_MASK	0x0C

> +#define MPI3MR_CTLR_SECURE_DBG_STATUS_MASK	0x02

> +

> +#define MPI3MR_INVALID_DEVICE			0x00

> +#define MPI3MR_CONFIG_SECURE_DEVICE		0x04

> +#define MPI3MR_HARD_SECURE_DEVICE		0x08

> +#define MPI3MR_TAMPERED_DEVICE			0x0C

> +

> /* SGE Flag definition */

> #define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \

> 	(MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \

> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c

> index 05473b0f3c9e..836005ce6999 100644

> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c

> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c

> @@ -3206,6 +3206,75 @@ static inline void mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd *cmdptr,

> 	cmdptr->host_tag = host_tag;

> }

> 

> +/**

> + * osintfc_mrioc_security_status -Check controller secure status

> + * @pdev: PCI device instance

> + *

> + * Read the Device Serial Number capability from PCI config

> + * space and decide whether the controller is secure or not.

> + *

> + * Return: 0 on success, non-zero on failure.

> + */

> +static int

> +osintfc_mrioc_security_status(struct pci_dev *pdev)

> +{

> +	u32 cap_data;

> +	int base;

> +	u32 ctlr_status;

> +	u32 debug_status;

> +	int retval = 0;

> +

> +	base = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN);

> +	if (!base) {

> +		dev_err(&pdev->dev,

> +		    "%s: PCI_EXT_CAP_ID_DSN is not supported\n", __func__);

> +		return -1;

> +	}

> +

> +	pci_read_config_dword(pdev, base + 4, &cap_data);

> +

> +	debug_status = cap_data & MPI3MR_CTLR_SECURE_DBG_STATUS_MASK;

> +	ctlr_status = cap_data & MPI3MR_CTLR_SECURITY_STATUS_MASK;

> +

> +	switch (ctlr_status) {

> +	case MPI3MR_INVALID_DEVICE:

> +		dev_err(&pdev->dev,

> +		    "%s: Non secure ctlr (Invalid) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",

> +		    __func__, pdev->device, pdev->subsystem_vendor,

> +		    pdev->subsystem_device);

> +		retval = -1;

> +		break;

> +	case MPI3MR_CONFIG_SECURE_DEVICE:

> +		if (!debug_status)

> +			dev_info(&pdev->dev,

> +			    "%s: Config secure ctlr is detected\n",

> +			    __func__);

> +		break;

> +	case MPI3MR_HARD_SECURE_DEVICE:

> +		break;

> +	case MPI3MR_TAMPERED_DEVICE:

> +		dev_err(&pdev->dev,

> +		    "%s: Non secure ctlr (Tampered) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",

> +		    __func__, pdev->device, pdev->subsystem_vendor,

> +		    pdev->subsystem_device);

> +		retval = -1;

> +		break;

> +	default:

> +		retval = -1;

> +			break;

> +	}

> +

> +	if (!retval && debug_status) {

> +		dev_err(&pdev->dev,

> +		    "%s: Non secure ctlr (Secure Dbg) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",

> +		    __func__, pdev->device, pdev->subsystem_vendor,

> +		    pdev->subsystem_device);

> +		retval = -1;

> +	}

> +

> +	return retval;

> +}

> +

> /**

>  * mpi3mr_probe - PCI probe callback

>  * @pdev: PCI device instance

> @@ -3228,6 +3297,11 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)

> 	struct Scsi_Host *shost = NULL;

> 	int retval = 0, i;

> 

> +	if (osintfc_mrioc_security_status(pdev)) {

> +		warn_non_secure_ctlr = 1;

> +		return 1; /* For Invalid and Tampered device */

> +	}

> +

> 	shost = scsi_host_alloc(&mpi3mr_driver_template,

> 	    sizeof(struct mpi3mr_ioc));

> 	if (!shost) {

> @@ -3344,6 +3418,9 @@ static void mpi3mr_remove(struct pci_dev *pdev)

> 	unsigned long flags;

> 	struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next;

> 

> +	if (!shost)

> +		return;

> +

> 	mrioc = shost_priv(shost);

> 	while (mrioc->reset_in_progress || mrioc->is_driver_loading)

> 		ssleep(1);

> @@ -3464,6 +3541,9 @@ static int mpi3mr_resume(struct pci_dev *pdev)

> 	pci_power_t device_state = pdev->current_state;

> 	int r;

> 

> +	if (!shost)

> +		return 0;

> +

> 	mrioc = shost_priv(shost);

> 

> 	ioc_info(mrioc, "pdev=0x%p, slot=%s, previous operating state [D%d]\n",

> -- 

> 2.18.1

> 


Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>


--
Himanshu Madhani	 Oracle Linux Engineering
diff mbox series

Patch

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 505df0e7b852..db9cb11db3bf 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -149,6 +149,15 @@  extern struct list_head mrioc_list;
 #define MPI3MR_IRQ_POLL_SLEEP			2
 #define MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT		8
 
+/* Definitions for the controller security status*/
+#define MPI3MR_CTLR_SECURITY_STATUS_MASK	0x0C
+#define MPI3MR_CTLR_SECURE_DBG_STATUS_MASK	0x02
+
+#define MPI3MR_INVALID_DEVICE			0x00
+#define MPI3MR_CONFIG_SECURE_DEVICE		0x04
+#define MPI3MR_HARD_SECURE_DEVICE		0x08
+#define MPI3MR_TAMPERED_DEVICE			0x0C
+
 /* SGE Flag definition */
 #define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \
 	(MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 05473b0f3c9e..836005ce6999 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -3206,6 +3206,75 @@  static inline void mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd *cmdptr,
 	cmdptr->host_tag = host_tag;
 }
 
+/**
+ * osintfc_mrioc_security_status -Check controller secure status
+ * @pdev: PCI device instance
+ *
+ * Read the Device Serial Number capability from PCI config
+ * space and decide whether the controller is secure or not.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int
+osintfc_mrioc_security_status(struct pci_dev *pdev)
+{
+	u32 cap_data;
+	int base;
+	u32 ctlr_status;
+	u32 debug_status;
+	int retval = 0;
+
+	base = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN);
+	if (!base) {
+		dev_err(&pdev->dev,
+		    "%s: PCI_EXT_CAP_ID_DSN is not supported\n", __func__);
+		return -1;
+	}
+
+	pci_read_config_dword(pdev, base + 4, &cap_data);
+
+	debug_status = cap_data & MPI3MR_CTLR_SECURE_DBG_STATUS_MASK;
+	ctlr_status = cap_data & MPI3MR_CTLR_SECURITY_STATUS_MASK;
+
+	switch (ctlr_status) {
+	case MPI3MR_INVALID_DEVICE:
+		dev_err(&pdev->dev,
+		    "%s: Non secure ctlr (Invalid) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
+		    __func__, pdev->device, pdev->subsystem_vendor,
+		    pdev->subsystem_device);
+		retval = -1;
+		break;
+	case MPI3MR_CONFIG_SECURE_DEVICE:
+		if (!debug_status)
+			dev_info(&pdev->dev,
+			    "%s: Config secure ctlr is detected\n",
+			    __func__);
+		break;
+	case MPI3MR_HARD_SECURE_DEVICE:
+		break;
+	case MPI3MR_TAMPERED_DEVICE:
+		dev_err(&pdev->dev,
+		    "%s: Non secure ctlr (Tampered) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
+		    __func__, pdev->device, pdev->subsystem_vendor,
+		    pdev->subsystem_device);
+		retval = -1;
+		break;
+	default:
+		retval = -1;
+			break;
+	}
+
+	if (!retval && debug_status) {
+		dev_err(&pdev->dev,
+		    "%s: Non secure ctlr (Secure Dbg) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
+		    __func__, pdev->device, pdev->subsystem_vendor,
+		    pdev->subsystem_device);
+		retval = -1;
+	}
+
+	return retval;
+}
+
 /**
  * mpi3mr_probe - PCI probe callback
  * @pdev: PCI device instance
@@ -3228,6 +3297,11 @@  mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	struct Scsi_Host *shost = NULL;
 	int retval = 0, i;
 
+	if (osintfc_mrioc_security_status(pdev)) {
+		warn_non_secure_ctlr = 1;
+		return 1; /* For Invalid and Tampered device */
+	}
+
 	shost = scsi_host_alloc(&mpi3mr_driver_template,
 	    sizeof(struct mpi3mr_ioc));
 	if (!shost) {
@@ -3344,6 +3418,9 @@  static void mpi3mr_remove(struct pci_dev *pdev)
 	unsigned long flags;
 	struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next;
 
+	if (!shost)
+		return;
+
 	mrioc = shost_priv(shost);
 	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
 		ssleep(1);
@@ -3464,6 +3541,9 @@  static int mpi3mr_resume(struct pci_dev *pdev)
 	pci_power_t device_state = pdev->current_state;
 	int r;
 
+	if (!shost)
+		return 0;
+
 	mrioc = shost_priv(shost);
 
 	ioc_info(mrioc, "pdev=0x%p, slot=%s, previous operating state [D%d]\n",