diff options
author | Furquan Shaikh <furquan@chromium.org> | 2016-12-24 12:27:05 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-12-25 00:14:29 -0800 |
commit | 2a84553d44fb0274c9b7744217481bfc833dc5c2 (patch) | |
tree | d5f9ae4fa402dd39c011885c6a06bcc14d6bab14 | |
parent | e4136dcaa0bca8fe1c0a88d4d99de675f218f5aa (diff) | |
download | vboot-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.c | 95 |
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); |