imx: hab: Check if CSF is valid before authenticating image

For proper authentication the HAB code must check if the CSF is valid.
Users must call the csf_is_valid() function to parse the CSF prior to
authenticating any additional images. The function will return a failure
if any of the following invalid conditions are met:

- CSF pointer is NULL
- CSF Header does not exist
- CSF does not lie within the image bounds
- CSF command length zero

Signed-off-by: Utkarsh Gupta <utkarsh.gupta@nxp.com>
Signed-off-by: Breno Lima <breno.lima@nxp.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
diff --git a/arch/arm/include/asm/mach-imx/hab.h b/arch/arm/include/asm/mach-imx/hab.h
index a0cb19d..bb73203 100644
--- a/arch/arm/include/asm/mach-imx/hab.h
+++ b/arch/arm/include/asm/mach-imx/hab.h
@@ -38,6 +38,12 @@
 	uint32_t reserved2;	/* Reserved should be zero */
 };
 
+struct __packed hab_hdr {
+	u8 tag;              /* Tag field */
+	u8 len[2];           /* Length field in bytes (big-endian) */
+	u8 par;              /* Parameters field */
+};
+
 /* -------- start of HAB API updates ------------*/
 /* The following are taken from HAB4 SIS */
 
@@ -182,6 +188,8 @@
 #define HAB_CID_ROM 0 /**< ROM Caller ID */
 #define HAB_CID_UBOOT 1 /**< UBOOT Caller ID*/
 
+#define HAB_CMD_HDR          0xD4  /* CSF Header */
+
 #define IVT_SIZE			0x20
 #define CSF_PAD_SIZE			0x2000
 
diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c
index ba6b31d..7f66965 100644
--- a/arch/arm/mach-imx/hab.c
+++ b/arch/arm/mach-imx/hab.c
@@ -453,6 +453,83 @@
 
 #endif /* !defined(CONFIG_SPL_BUILD) */
 
+/* Get CSF Header length */
+static int get_hab_hdr_len(struct hab_hdr *hdr)
+{
+	return (size_t)((hdr->len[0] << 8) + (hdr->len[1]));
+}
+
+/* Check whether addr lies between start and
+ * end and is within the length of the image
+ */
+static int chk_bounds(u8 *addr, size_t bytes, u8 *start, u8 *end)
+{
+	size_t csf_size = (size_t)((end + 1) - addr);
+
+	return (addr && (addr >= start) && (addr <= end) &&
+		(csf_size >= bytes));
+}
+
+/* Get Length of each command in CSF */
+static int get_csf_cmd_hdr_len(u8 *csf_hdr)
+{
+	if (*csf_hdr == HAB_CMD_HDR)
+		return sizeof(struct hab_hdr);
+
+	return get_hab_hdr_len((struct hab_hdr *)csf_hdr);
+}
+
+/* Check if CSF is valid */
+static bool csf_is_valid(struct ivt *ivt, ulong start_addr, size_t bytes)
+{
+	u8 *start = (u8 *)start_addr;
+	u8 *csf_hdr;
+	u8 *end;
+
+	size_t csf_hdr_len;
+	size_t cmd_hdr_len;
+	size_t offset = 0;
+
+	if (bytes != 0)
+		end = start + bytes - 1;
+	else
+		end = start;
+
+	/* Verify if CSF pointer content is zero */
+	if (!ivt->csf) {
+		puts("Error: CSF pointer is NULL\n");
+		return false;
+	}
+
+	csf_hdr = (u8 *)ivt->csf;
+
+	/* Verify if CSF Header exist */
+	if (*csf_hdr != HAB_CMD_HDR) {
+		puts("Error: CSF header command not found\n");
+		return false;
+	}
+
+	csf_hdr_len = get_hab_hdr_len((struct hab_hdr *)csf_hdr);
+
+	/* Check if the CSF lies within the image bounds */
+	if (!chk_bounds(csf_hdr, csf_hdr_len, start, end)) {
+		puts("Error: CSF lies outside the image bounds\n");
+		return false;
+	}
+
+	do {
+		cmd_hdr_len = get_csf_cmd_hdr_len(&csf_hdr[offset]);
+		if (!cmd_hdr_len) {
+			puts("Error: Invalid command length\n");
+			return false;
+		}
+		offset += cmd_hdr_len;
+
+	} while (offset < csf_hdr_len);
+
+	return true;
+}
+
 bool imx_hab_is_enabled(void)
 {
 	struct imx_sec_config_fuse_t *fuse =
@@ -525,6 +602,10 @@
 	start = ddr_start;
 	bytes = image_size;
 
+	/* Verify CSF */
+	if (!csf_is_valid(ivt, start, bytes))
+		goto hab_authentication_exit;
+
 	if (hab_rvt_entry() != HAB_SUCCESS) {
 		puts("hab entry function fail\n");
 		goto hab_exit_failure_print_status;