summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFurquan Shaikh <furquan@chromium.org>2016-12-24 12:27:05 -0800
committerchrome-bot <chrome-bot@chromium.org>2016-12-25 00:14:29 -0800
commit2a84553d44fb0274c9b7744217481bfc833dc5c2 (patch)
treed5f9ae4fa402dd39c011885c6a06bcc14d6bab14
parente4136dcaa0bca8fe1c0a88d4d99de675f218f5aa (diff)
downloadvboot-2a84553d44fb0274c9b7744217481bfc833dc5c2.tar.gz
futility/cmd_validate_rec_mrc: Update futility to use new MRC struct
1. Use mrc_metadata structure with new fields for header checksum and data checksum. 2. Use region file metadata to ensure there is only one metadata block present and only one slot in recovery MRC cache. Use the offset and size based on values in metadata block. BUG=chrome-os-partner:61306 BRANCH=None TEST=Verified that recovery MRC cache is verified using futility. Change-Id: I68b2d75ea70fdaef6c87cdaa6ce97656e8a8bddc Signed-off-by: Furquan Shaikh <furquan@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/424213 Reviewed-by: Aaron Durbin <adurbin@chromium.org>
-rw-r--r--futility/cmd_validate_rec_mrc.c95
1 files changed, 76 insertions, 19 deletions
diff --git a/futility/cmd_validate_rec_mrc.c b/futility/cmd_validate_rec_mrc.c
index 3013891a..1fdd47c1 100644
--- a/futility/cmd_validate_rec_mrc.c
+++ b/futility/cmd_validate_rec_mrc.c
@@ -35,19 +35,22 @@ static void print_help(int argc, char *argv[])
printf("\n");
}
-struct mrc_cache {
+struct mrc_metadata {
uint32_t signature;
- uint32_t size;
- uint32_t checksum;
+ uint32_t data_size;
+ uint16_t data_checksum;
+ uint16_t header_checksum;
uint32_t version;
- uint8_t data[0];
} __attribute__((packed));
#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24))
+#define REGF_BLOCK_SHIFT 4
+#define REGF_UNALLOCATED_BLOCK 0xffff
-unsigned long compute_ip_checksum(void *addr, unsigned long length)
+
+unsigned long compute_ip_checksum(const void *addr, unsigned long length)
{
- uint8_t *ptr;
+ const uint8_t *ptr;
volatile union {
uint8_t byte[2];
uint16_t word;
@@ -77,29 +80,71 @@ unsigned long compute_ip_checksum(void *addr, unsigned long length)
return (~value.word) & 0xFFFF;
}
-static int verify_checksum(struct mrc_cache *cache, unsigned long cache_len)
+static int verify_mrc_slot(struct mrc_metadata *md, unsigned long slot_len)
{
- uint32_t checksum;
- if (cache->signature != MRC_DATA_SIGNATURE) {
+ uint32_t header_checksum;
+ if (md->signature != MRC_DATA_SIGNATURE) {
fprintf(stderr, "MRC signature mismatch\n");
return 1;
}
fprintf(stderr, "MRC signature match.. successful\n");
- if (cache->size > cache_len) {
+ if (md->data_size > slot_len) {
fprintf(stderr, "MRC cache size overflow\n");
return 1;
}
- checksum = compute_ip_checksum((void *)&cache->data[0], cache->size);
+ header_checksum = md->header_checksum;
+ md->header_checksum = 0;
+
+ if (header_checksum != compute_ip_checksum(md, sizeof(*md))) {
+ fprintf(stderr, "MRC metadata header checksum mismatch\n");
+ return 1;
+ }
+
+ md->header_checksum = header_checksum;
+
+ fprintf(stderr, "MRC metadata header checksum.. verified!\n");
- if (checksum != cache->checksum) {
- fprintf(stderr, "MRC checksum mismatch\n");
+ if (md->data_checksum != compute_ip_checksum(&md[1], md->data_size)) {
+ fprintf(stderr, "MRC data checksum mismatch\n");
+ return 1;
+ }
+
+ fprintf(stderr, "MRC data checksum.. verified!\n");
+ return 0;
+}
+
+static int get_mrc_data_slot(uint16_t *mb, uint32_t *data_offset,
+ uint32_t *data_size)
+{
+ /*
+ * First block offset in metadata block tells the total number of
+ * metadata blocks.
+ * Currently, we expect only 1 metadata block to be present.
+ */
+ if (*mb != 1) {
+ fprintf(stderr, "Only 1 metadata block is expected. "
+ "Actual %x\n", *mb);
+ return 1;
+ }
+
+ /*
+ * RECOVERY_MRC_CACHE is expected to contain only one slot. Thus, there
+ * should be only one block offset present, indicating size of the MRC
+ * cache slot.
+ */
+ mb++;
+ *data_offset = (1 << REGF_BLOCK_SHIFT);
+ *data_size = (*mb - 1) << REGF_BLOCK_SHIFT;
+
+ mb++;
+ if (*mb != REGF_UNALLOCATED_BLOCK) {
+ fprintf(stderr, "More than 1 slot in recovery mrc cache.\n");
return 1;
}
- fprintf(stderr, "MRC checksum.. verified!\n");
return 0;
}
@@ -111,6 +156,8 @@ static int do_validate_rec_mrc(int argc, char *argv[])
uint32_t file_size;
uint8_t *buff;
uint32_t offset = 0;
+ uint32_t data_offset;
+ uint32_t data_size;
char *e;
while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
@@ -162,12 +209,22 @@ static int do_validate_rec_mrc(int argc, char *argv[])
return 1;
}
- if (file_size > offset)
- ret = verify_checksum((struct mrc_cache *)(buff + offset),
- file_size - offset);
+ if (get_mrc_data_slot((uint16_t *)(buff + offset), &data_offset,
+ &data_size)) {
+ fprintf(stderr, "Metadata block error\n");
+ futil_unmap_file(fd, MAP_RO, buff, file_size);
+ close(fd);
+ return 1;
+ }
+ offset += data_offset;
+
+ if ((file_size > offset) && ((file_size - offset) >= data_size))
+ ret = verify_mrc_slot((struct mrc_metadata *)(buff + offset),
+ data_size);
else
- fprintf(stderr, "Offset greater than file size: offset=0x%x, "
- "file size=0x%x\n", offset, file_size);
+ fprintf(stderr, "Offset or data size greater than file size: "
+ "offset=0x%x, file size=0x%x, data_size=0x%x\n",
+ offset, file_size, data_size);
if (futil_unmap_file(fd, MAP_RO, buff, file_size) != FILE_ERR_NONE) {
fprintf(stderr, "Failed to unmap file %s\n", infile);