Torsten Duwe 3a6ee2
From 908f24270d9ccbe120b91e7029b372f3dcd18290 Mon Sep 17 00:00:00 2001
Torsten Duwe 3a6ee2
From: Srinivas Kerekare <srinivas.kerekare@intel.com>
Torsten Duwe 3a6ee2
Date: Mon, 25 Jul 2022 11:40:09 +0100
Torsten Duwe 3a6ee2
Subject: [PATCH] crypto: qat - add check to validate firmware images
Torsten Duwe 3a6ee2
Git-commit: 908f24270d9ccbe120b91e7029b372f3dcd18290
Torsten Duwe 3a6ee2
Patch-mainline: v6.1-rc1
Torsten Duwe 3a6ee2
References: jsc#PED-1073
Torsten Duwe 3a6ee2
Torsten Duwe 3a6ee2
The function qat_uclo_check_image() validates the MMP and AE firmware
Torsten Duwe 3a6ee2
images. If the QAT device supports firmware authentication (indicated
Torsten Duwe 3a6ee2
by the handle to firmware loader), the input signed binary MMP and AE
Torsten Duwe 3a6ee2
images are validated by parsing the following information:
Torsten Duwe 3a6ee2
- Header length
Torsten Duwe 3a6ee2
- Full size of the binary
Torsten Duwe 3a6ee2
- Type of binary image (MMP or AE Firmware)
Torsten Duwe 3a6ee2
Torsten Duwe 3a6ee2
Firmware binaries use RSA3K for signing and verification.
Torsten Duwe 3a6ee2
The header length for the RSA3k is 0x384 bytes.
Torsten Duwe 3a6ee2
Torsten Duwe 3a6ee2
All the size field values in the binary are quantified
Torsten Duwe 3a6ee2
as DWORDS (1 DWORD = 4bytes).
Torsten Duwe 3a6ee2
Torsten Duwe 3a6ee2
On an invalid value the function prints an error message and returns
Torsten Duwe 3a6ee2
with an error code "EINVAL".
Torsten Duwe 3a6ee2
Torsten Duwe 3a6ee2
Signed-off-by: Srinivas Kerekare <srinivas.kerekare@intel.com>
Torsten Duwe 3a6ee2
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Torsten Duwe 3a6ee2
Reviewed-by: Wojciech Ziemba <wojciech.ziemba@intel.com>
Torsten Duwe 3a6ee2
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Torsten Duwe 3a6ee2
Signed-off-by: Torsten Duwe <duwe@suse.de>
Torsten Duwe 3a6ee2
Torsten Duwe 3a6ee2
---
Torsten Duwe 3a6ee2
 drivers/crypto/qat/qat_common/icp_qat_uclo.h |  3 +-
Torsten Duwe 3a6ee2
 drivers/crypto/qat/qat_common/qat_uclo.c     | 56 +++++++++++++++++++-
Torsten Duwe 3a6ee2
 2 files changed, 57 insertions(+), 2 deletions(-)
Torsten Duwe 3a6ee2
Torsten Duwe 3a6ee2
diff --git a/drivers/crypto/qat/qat_common/icp_qat_uclo.h b/drivers/crypto/qat/qat_common/icp_qat_uclo.h
Torsten Duwe 3a6ee2
index 4b36869bf460b..69482abdb8b93 100644
Torsten Duwe 3a6ee2
--- a/drivers/crypto/qat/qat_common/icp_qat_uclo.h
Torsten Duwe 3a6ee2
+++ b/drivers/crypto/qat/qat_common/icp_qat_uclo.h
Torsten Duwe 3a6ee2
@@ -86,7 +86,8 @@
Torsten Duwe 3a6ee2
 					ICP_QAT_CSS_FWSK_MODULUS_LEN(handle) + \
Torsten Duwe 3a6ee2
 					ICP_QAT_CSS_FWSK_EXPONENT_LEN(handle) + \
Torsten Duwe 3a6ee2
 					ICP_QAT_CSS_SIGNATURE_LEN(handle))
Torsten Duwe 3a6ee2
-#define ICP_QAT_CSS_MAX_IMAGE_LEN   0x40000
Torsten Duwe 3a6ee2
+#define ICP_QAT_CSS_RSA4K_MAX_IMAGE_LEN    0x40000
Torsten Duwe 3a6ee2
+#define ICP_QAT_CSS_RSA3K_MAX_IMAGE_LEN    0x30000
Torsten Duwe 3a6ee2
 
Torsten Duwe 3a6ee2
 #define ICP_QAT_CTX_MODE(ae_mode) ((ae_mode) & 0xf)
Torsten Duwe 3a6ee2
 #define ICP_QAT_NN_MODE(ae_mode) (((ae_mode) >> 0x4) & 0xf)
Torsten Duwe 3a6ee2
diff --git a/drivers/crypto/qat/qat_common/qat_uclo.c b/drivers/crypto/qat/qat_common/qat_uclo.c
Torsten Duwe 3a6ee2
index 0fe5a474aa452..b7f7869ef8b2f 100644
Torsten Duwe 3a6ee2
--- a/drivers/crypto/qat/qat_common/qat_uclo.c
Torsten Duwe 3a6ee2
+++ b/drivers/crypto/qat/qat_common/qat_uclo.c
Torsten Duwe 3a6ee2
@@ -1367,6 +1367,48 @@ static void qat_uclo_ummap_auth_fw(struct icp_qat_fw_loader_handle *handle,
Torsten Duwe 3a6ee2
 	}
Torsten Duwe 3a6ee2
 }
Torsten Duwe 3a6ee2
 
Torsten Duwe 3a6ee2
+static int qat_uclo_check_image(struct icp_qat_fw_loader_handle *handle,
Torsten Duwe 3a6ee2
+				char *image, unsigned int size,
Torsten Duwe 3a6ee2
+				unsigned int fw_type)
Torsten Duwe 3a6ee2
+{
Torsten Duwe 3a6ee2
+	char *fw_type_name = fw_type ? "MMP" : "AE";
Torsten Duwe 3a6ee2
+	unsigned int css_dword_size = sizeof(u32);
Torsten Duwe 3a6ee2
+
Torsten Duwe 3a6ee2
+	if (handle->chip_info->fw_auth) {
Torsten Duwe 3a6ee2
+		struct icp_qat_css_hdr *css_hdr = (struct icp_qat_css_hdr *)image;
Torsten Duwe 3a6ee2
+		unsigned int header_len = ICP_QAT_AE_IMG_OFFSET(handle);
Torsten Duwe 3a6ee2
+
Torsten Duwe 3a6ee2
+		if ((css_hdr->header_len * css_dword_size) != header_len)
Torsten Duwe 3a6ee2
+			goto err;
Torsten Duwe 3a6ee2
+		if ((css_hdr->size * css_dword_size) != size)
Torsten Duwe 3a6ee2
+			goto err;
Torsten Duwe 3a6ee2
+		if (fw_type != css_hdr->fw_type)
Torsten Duwe 3a6ee2
+			goto err;
Torsten Duwe 3a6ee2
+		if (size <= header_len)
Torsten Duwe 3a6ee2
+			goto err;
Torsten Duwe 3a6ee2
+		size -= header_len;
Torsten Duwe 3a6ee2
+	}
Torsten Duwe 3a6ee2
+
Torsten Duwe 3a6ee2
+	if (fw_type == CSS_AE_FIRMWARE) {
Torsten Duwe 3a6ee2
+		if (size < sizeof(struct icp_qat_simg_ae_mode *) +
Torsten Duwe 3a6ee2
+		    ICP_QAT_SIMG_AE_INIT_SEQ_LEN)
Torsten Duwe 3a6ee2
+			goto err;
Torsten Duwe 3a6ee2
+		if (size > ICP_QAT_CSS_RSA4K_MAX_IMAGE_LEN)
Torsten Duwe 3a6ee2
+			goto err;
Torsten Duwe 3a6ee2
+	} else if (fw_type == CSS_MMP_FIRMWARE) {
Torsten Duwe 3a6ee2
+		if (size > ICP_QAT_CSS_RSA3K_MAX_IMAGE_LEN)
Torsten Duwe 3a6ee2
+			goto err;
Torsten Duwe 3a6ee2
+	} else {
Torsten Duwe 3a6ee2
+		pr_err("QAT: Unsupported firmware type\n");
Torsten Duwe 3a6ee2
+		return -EINVAL;
Torsten Duwe 3a6ee2
+	}
Torsten Duwe 3a6ee2
+	return 0;
Torsten Duwe 3a6ee2
+
Torsten Duwe 3a6ee2
+err:
Torsten Duwe 3a6ee2
+	pr_err("QAT: Invalid %s firmware image\n", fw_type_name);
Torsten Duwe 3a6ee2
+	return -EINVAL;
Torsten Duwe 3a6ee2
+}
Torsten Duwe 3a6ee2
+
Torsten Duwe 3a6ee2
 static int qat_uclo_map_auth_fw(struct icp_qat_fw_loader_handle *handle,
Torsten Duwe 3a6ee2
 				char *image, unsigned int size,
Torsten Duwe 3a6ee2
 				struct icp_qat_fw_auth_desc **desc)
Torsten Duwe 3a6ee2
@@ -1379,7 +1421,7 @@ static int qat_uclo_map_auth_fw(struct icp_qat_fw_loader_handle *handle,
Torsten Duwe 3a6ee2
 	struct icp_qat_simg_ae_mode *simg_ae_mode;
Torsten Duwe 3a6ee2
 	struct icp_firml_dram_desc img_desc;
Torsten Duwe 3a6ee2
 
Torsten Duwe 3a6ee2
-	if (size > (ICP_QAT_AE_IMG_OFFSET(handle) + ICP_QAT_CSS_MAX_IMAGE_LEN)) {
Torsten Duwe 3a6ee2
+	if (size > (ICP_QAT_AE_IMG_OFFSET(handle) + ICP_QAT_CSS_RSA4K_MAX_IMAGE_LEN)) {
Torsten Duwe 3a6ee2
 		pr_err("QAT: error, input image size overflow %d\n", size);
Torsten Duwe 3a6ee2
 		return -EINVAL;
Torsten Duwe 3a6ee2
 	}
Torsten Duwe 3a6ee2
@@ -1547,6 +1589,11 @@ int qat_uclo_wr_mimage(struct icp_qat_fw_loader_handle *handle,
Torsten Duwe 3a6ee2
 {
Torsten Duwe 3a6ee2
 	struct icp_qat_fw_auth_desc *desc = NULL;
Torsten Duwe 3a6ee2
 	int status = 0;
Torsten Duwe 3a6ee2
+	int ret;
Torsten Duwe 3a6ee2
+
Torsten Duwe 3a6ee2
+	ret = qat_uclo_check_image(handle, addr_ptr, mem_size, CSS_MMP_FIRMWARE);
Torsten Duwe 3a6ee2
+	if (ret)
Torsten Duwe 3a6ee2
+		return ret;
Torsten Duwe 3a6ee2
 
Torsten Duwe 3a6ee2
 	if (handle->chip_info->fw_auth) {
Torsten Duwe 3a6ee2
 		status = qat_uclo_map_auth_fw(handle, addr_ptr, mem_size, &desc);
Torsten Duwe 3a6ee2
@@ -2018,8 +2065,15 @@ static int qat_uclo_wr_suof_img(struct icp_qat_fw_loader_handle *handle)
Torsten Duwe 3a6ee2
 	struct icp_qat_fw_auth_desc *desc = NULL;
Torsten Duwe 3a6ee2
 	struct icp_qat_suof_handle *sobj_handle = handle->sobj_handle;
Torsten Duwe 3a6ee2
 	struct icp_qat_suof_img_hdr *simg_hdr = sobj_handle->img_table.simg_hdr;
Torsten Duwe 3a6ee2
+	int ret;
Torsten Duwe 3a6ee2
 
Torsten Duwe 3a6ee2
 	for (i = 0; i < sobj_handle->img_table.num_simgs; i++) {
Torsten Duwe 3a6ee2
+		ret = qat_uclo_check_image(handle, simg_hdr[i].simg_buf,
Torsten Duwe 3a6ee2
+					   simg_hdr[i].simg_len,
Torsten Duwe 3a6ee2
+					   CSS_AE_FIRMWARE);
Torsten Duwe 3a6ee2
+		if (ret)
Torsten Duwe 3a6ee2
+			return ret;
Torsten Duwe 3a6ee2
+
Torsten Duwe 3a6ee2
 		if (qat_uclo_map_auth_fw(handle,
Torsten Duwe 3a6ee2
 					 (char *)simg_hdr[i].simg_buf,
Torsten Duwe 3a6ee2
 					 (unsigned int)
Torsten Duwe 3a6ee2
-- 
Torsten Duwe 3a6ee2
2.35.3
Torsten Duwe 3a6ee2