crypto: qat - add check to validate firmware images
authorSrinivas Kerekare <srinivas.kerekare@intel.com>
Mon, 25 Jul 2022 10:40:09 +0000 (11:40 +0100)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 19 Aug 2022 10:39:33 +0000 (18:39 +0800)
The function qat_uclo_check_image() validates the MMP and AE firmware
images. If the QAT device supports firmware authentication (indicated
by the handle to firmware loader), the input signed binary MMP and AE
images are validated by parsing the following information:
- Header length
- Full size of the binary
- Type of binary image (MMP or AE Firmware)

Firmware binaries use RSA3K for signing and verification.
The header length for the RSA3k is 0x384 bytes.

All the size field values in the binary are quantified
as DWORDS (1 DWORD = 4bytes).

On an invalid value the function prints an error message and returns
with an error code "EINVAL".

Signed-off-by: Srinivas Kerekare <srinivas.kerekare@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Wojciech Ziemba <wojciech.ziemba@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/qat/qat_common/icp_qat_uclo.h
drivers/crypto/qat/qat_common/qat_uclo.c

index 4b36869bf460bb750b6b91a36b73ab6b34e62bae..69482abdb8b936c5c8ad194d9263f0bc136b2871 100644 (file)
@@ -86,7 +86,8 @@
                                        ICP_QAT_CSS_FWSK_MODULUS_LEN(handle) + \
                                        ICP_QAT_CSS_FWSK_EXPONENT_LEN(handle) + \
                                        ICP_QAT_CSS_SIGNATURE_LEN(handle))
-#define ICP_QAT_CSS_MAX_IMAGE_LEN   0x40000
+#define ICP_QAT_CSS_RSA4K_MAX_IMAGE_LEN    0x40000
+#define ICP_QAT_CSS_RSA3K_MAX_IMAGE_LEN    0x30000
 
 #define ICP_QAT_CTX_MODE(ae_mode) ((ae_mode) & 0xf)
 #define ICP_QAT_NN_MODE(ae_mode) (((ae_mode) >> 0x4) & 0xf)
index 0fe5a474aa4525f2a00cb76056b6e1cf701a90e6..b7f7869ef8b2f35bef5ff3793ffc06184d655f53 100644 (file)
@@ -1367,6 +1367,48 @@ static void qat_uclo_ummap_auth_fw(struct icp_qat_fw_loader_handle *handle,
        }
 }
 
+static int qat_uclo_check_image(struct icp_qat_fw_loader_handle *handle,
+                               char *image, unsigned int size,
+                               unsigned int fw_type)
+{
+       char *fw_type_name = fw_type ? "MMP" : "AE";
+       unsigned int css_dword_size = sizeof(u32);
+
+       if (handle->chip_info->fw_auth) {
+               struct icp_qat_css_hdr *css_hdr = (struct icp_qat_css_hdr *)image;
+               unsigned int header_len = ICP_QAT_AE_IMG_OFFSET(handle);
+
+               if ((css_hdr->header_len * css_dword_size) != header_len)
+                       goto err;
+               if ((css_hdr->size * css_dword_size) != size)
+                       goto err;
+               if (fw_type != css_hdr->fw_type)
+                       goto err;
+               if (size <= header_len)
+                       goto err;
+               size -= header_len;
+       }
+
+       if (fw_type == CSS_AE_FIRMWARE) {
+               if (size < sizeof(struct icp_qat_simg_ae_mode *) +
+                   ICP_QAT_SIMG_AE_INIT_SEQ_LEN)
+                       goto err;
+               if (size > ICP_QAT_CSS_RSA4K_MAX_IMAGE_LEN)
+                       goto err;
+       } else if (fw_type == CSS_MMP_FIRMWARE) {
+               if (size > ICP_QAT_CSS_RSA3K_MAX_IMAGE_LEN)
+                       goto err;
+       } else {
+               pr_err("QAT: Unsupported firmware type\n");
+               return -EINVAL;
+       }
+       return 0;
+
+err:
+       pr_err("QAT: Invalid %s firmware image\n", fw_type_name);
+       return -EINVAL;
+}
+
 static int qat_uclo_map_auth_fw(struct icp_qat_fw_loader_handle *handle,
                                char *image, unsigned int size,
                                struct icp_qat_fw_auth_desc **desc)
@@ -1379,7 +1421,7 @@ static int qat_uclo_map_auth_fw(struct icp_qat_fw_loader_handle *handle,
        struct icp_qat_simg_ae_mode *simg_ae_mode;
        struct icp_firml_dram_desc img_desc;
 
-       if (size > (ICP_QAT_AE_IMG_OFFSET(handle) + ICP_QAT_CSS_MAX_IMAGE_LEN)) {
+       if (size > (ICP_QAT_AE_IMG_OFFSET(handle) + ICP_QAT_CSS_RSA4K_MAX_IMAGE_LEN)) {
                pr_err("QAT: error, input image size overflow %d\n", size);
                return -EINVAL;
        }
@@ -1547,6 +1589,11 @@ int qat_uclo_wr_mimage(struct icp_qat_fw_loader_handle *handle,
 {
        struct icp_qat_fw_auth_desc *desc = NULL;
        int status = 0;
+       int ret;
+
+       ret = qat_uclo_check_image(handle, addr_ptr, mem_size, CSS_MMP_FIRMWARE);
+       if (ret)
+               return ret;
 
        if (handle->chip_info->fw_auth) {
                status = qat_uclo_map_auth_fw(handle, addr_ptr, mem_size, &desc);
@@ -2018,8 +2065,15 @@ static int qat_uclo_wr_suof_img(struct icp_qat_fw_loader_handle *handle)
        struct icp_qat_fw_auth_desc *desc = NULL;
        struct icp_qat_suof_handle *sobj_handle = handle->sobj_handle;
        struct icp_qat_suof_img_hdr *simg_hdr = sobj_handle->img_table.simg_hdr;
+       int ret;
 
        for (i = 0; i < sobj_handle->img_table.num_simgs; i++) {
+               ret = qat_uclo_check_image(handle, simg_hdr[i].simg_buf,
+                                          simg_hdr[i].simg_len,
+                                          CSS_AE_FIRMWARE);
+               if (ret)
+                       return ret;
+
                if (qat_uclo_map_auth_fw(handle,
                                         (char *)simg_hdr[i].simg_buf,
                                         (unsigned int)