feat(gpt): validate CRC of GPT partition entries

While loading partition entries, calculate CRC using tf_crc32() for each
entry to find the full CRC value of the partition entry array.

The start of the GPT partition entry array is located at the LBA
indicated by the partition entry array LBA field in the GPT header. The
size of the partition entry array is indicated by the size of partition
entry multiplied by the number of partition entries.

Compare the calculated CRC with the partition entry array CRC in the GPT
header, error out if the values do not match.

Change-Id: I4bfed8cf903125c1ef3fac2f0f4c0fb87d63aa78
Signed-off-by: Lauren Wehrmeister <lauren.wehrmeister@arm.com>
diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c
index f1cc87c..555fe7f 100644
--- a/drivers/partition/partition.c
+++ b/drivers/partition/partition.c
@@ -233,7 +233,9 @@
 {
 	const signed long long gpt_entry_offset = LBA(header.part_lba);
 	gpt_entry_t entry;
-	int result, i;
+	int result;
+	unsigned int i;
+	uint32_t calc_crc = 0U;
 
 	result = io_seek(image_handle, IO_SEEK_SET, gpt_entry_offset);
 	if (result != 0) {
@@ -242,23 +244,36 @@
 		return result;
 	}
 
-	for (i = 0; i < list.entry_count; i++) {
+	for (i = 0; i < (unsigned int)list.entry_count; i++) {
 		result = load_gpt_entry(image_handle, &entry);
 		if (result != 0) {
-			VERBOSE("Failed to load gpt entry data(%i) error is (%i)\n",
+			VERBOSE("Failed to load gpt entry data(%u) error is (%i)\n",
 				i, result);
 			return result;
 		}
 
 		result = parse_gpt_entry(&entry, &list.list[i]);
 		if (result != 0) {
+			result = io_seek(image_handle, IO_SEEK_SET,
+					(gpt_entry_offset + (i * sizeof(gpt_entry_t))));
+			if (result != 0) {
+				VERBOSE("Failed to seek (%i)\n", result);
+				return result;
+			}
 			break;
 		}
+
+		/*
+		 * Calculate CRC of Partition entry array to compare with CRC
+		 * value in header
+		 */
+		calc_crc = tf_crc32(calc_crc, (uint8_t *)&entry, sizeof(gpt_entry_t));
 	}
 	if (i == 0) {
 		VERBOSE("No Valid GPT Entries found\n");
 		return -EINVAL;
 	}
+
 	/*
 	 * Only records the valid partition number that is loaded from
 	 * partition table.
@@ -266,6 +281,29 @@
 	list.entry_count = i;
 	dump_entries(list.entry_count);
 
+	/*
+	 * If there are less valid entries than the possible number of entries
+	 * from the header, continue to load the partition entry table to
+	 * calculate the full CRC in order to check against the partition CRC
+	 * from the header for validation.
+	 */
+	for (; i < header.list_num; i++) {
+		result = load_gpt_entry(image_handle, &entry);
+		if (result != 0) {
+			VERBOSE("Failed to load gpt entry data(%u) error is (%i)\n",
+				i, result);
+			return result;
+		}
+
+		calc_crc = tf_crc32(calc_crc, (uint8_t *)&entry, sizeof(gpt_entry_t));
+	}
+
+	if (header.part_crc != calc_crc) {
+		ERROR("Invalid GPT Partition Array Entry CRC: Expected 0x%x"
+				" but got 0x%x.\n", header.part_crc, calc_crc);
+		return -EINVAL;
+	}
+
 	return 0;
 }