diff options
Diffstat (limited to 'futility/cmd_validate_rec_mrc.c')
-rw-r--r-- | futility/cmd_validate_rec_mrc.c | 260 |
1 files changed, 0 insertions, 260 deletions
diff --git a/futility/cmd_validate_rec_mrc.c b/futility/cmd_validate_rec_mrc.c deleted file mode 100644 index 16760d50..00000000 --- a/futility/cmd_validate_rec_mrc.c +++ /dev/null @@ -1,260 +0,0 @@ -/* Copyright 2016 The ChromiumOS Authors - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include <errno.h> -#include <fcntl.h> -#include <getopt.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "futility.h" - -enum { - OPT_HELP = 1000, - OPT_OFFSET, -}; - -static const struct option long_opts[] = { - {"help", 0, 0, OPT_HELP}, - {"offset", 1, 0, OPT_OFFSET}, - {NULL, 0, NULL, 0}, -}; - -static void print_help(int argc, char *argv[]) -{ - printf("\nUsage: " MYNAME " %s FILE [OPTIONS]\n", argv[0]); - printf("\nOptions:\n"); - printf(" --offset <offset> Offset of cache within FILE\n"); - printf("\n"); -} - -struct mrc_metadata { - uint32_t signature; - uint32_t data_size; - uint16_t data_checksum; - uint16_t header_checksum; - uint32_t version; -} __attribute__((packed)); - -#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) -#define REGF_BLOCK_SHIFT 4 -#define REGF_BLOCK_GRANULARITY (1 << REGF_BLOCK_SHIFT) -#define REGF_METADATA_BLOCK_SIZE REGF_BLOCK_GRANULARITY -#define REGF_UNALLOCATED_BLOCK 0xffff - -static unsigned long compute_ip_checksum(const void *addr, unsigned long length) -{ - const uint8_t *ptr; - volatile union { - uint8_t byte[2]; - uint16_t word; - } value; - unsigned long sum; - unsigned long i; - /* In the most straight forward way possible, - * compute an ip style checksum. - */ - sum = 0; - ptr = addr; - for(i = 0; i < length; i++) { - unsigned long v; - v = ptr[i]; - if (i & 1) { - v <<= 8; - } - /* Add the new value */ - sum += v; - /* Wrap around the carry */ - if (sum > 0xFFFF) { - sum = (sum + (sum >> 16)) & 0xFFFF; - } - } - value.byte[0] = sum & 0xff; - value.byte[1] = (sum >> 8) & 0xff; - return (~value.word) & 0xFFFF; -} - -static int verify_mrc_slot(struct mrc_metadata *md, unsigned long slot_len) -{ - uint32_t header_checksum; - - if (slot_len < sizeof(*md)) { - fprintf(stderr, "Slot too small!\n"); - return 1; - } - - if (md->signature != MRC_DATA_SIGNATURE) { - fprintf(stderr, "MRC signature mismatch\n"); - return 1; - } - - fprintf(stderr, "MRC signature match.. successful\n"); - - if (md->data_size > slot_len) { - fprintf(stderr, "MRC cache size overflow\n"); - return 1; - } - - 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 (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 block_offset_unallocated(uint16_t offset) -{ - return offset == REGF_UNALLOCATED_BLOCK; -} - -static uint8_t *get_next_mb(uint8_t *curr_mb) -{ - return curr_mb + REGF_METADATA_BLOCK_SIZE; -} - -static int get_mrc_data_slot(uint16_t *mb, uint32_t *data_offset, - uint32_t *data_size) -{ - uint16_t num_metadata_blocks = *mb; - - if (block_offset_unallocated(*mb)) { - fprintf(stderr, "MRC cache is empty!!\n"); - return 1; - } - - /* - * First block offset in metadata block tells the total number of - * metadata blocks. - * Currently, we expect only 1 metadata block to be used. - */ - if (num_metadata_blocks != 1) { - uint16_t *next_mb = (uint16_t *)get_next_mb((uint8_t *)mb); - if (!block_offset_unallocated(*next_mb)) { - fprintf(stderr, "More than 1 valid metadata block!!"); - 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) * num_metadata_blocks; - *data_size = (*mb - num_metadata_blocks) << REGF_BLOCK_SHIFT; - - mb++; - if (!block_offset_unallocated(*mb)) { - fprintf(stderr, "More than 1 slot in recovery mrc cache.\n"); - return 1; - } - - return 0; -} - -static int do_validate_rec_mrc(int argc, char *argv[]) -{ - char *infile = NULL; - int parse_error = 0; - int fd, i, ret = 1; - 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) && - !parse_error) { - switch (i) { - case OPT_HELP: - print_help(argc, argv); - return 0; - case OPT_OFFSET: - offset = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - fprintf(stderr, "Invalid --offset\n"); - parse_error = 1; - } - break; - default: - case '?': - parse_error = 1; - break; - } - } - - if (parse_error) { - print_help(argc, argv); - return 1; - } - - if ((argc - optind) < 1) { - fprintf(stderr, "You must specify an input FILE!\n"); - print_help(argc, argv); - return 1; - } else if ((argc - optind) != 1) { - fprintf(stderr, "Unexpected arguments!\n"); - print_help(argc, argv); - return 1; - } - - infile = argv[optind++]; - - if (futil_open_and_map_file(infile, &fd, FILE_RO, &buff, &file_size) != - FILE_ERR_NONE) - return 1; - - if (offset > file_size) { - fprintf(stderr, "File size(%#x) smaller than offset(%#x)\n", - file_size, offset); - futil_unmap_and_close_file(fd, FILE_RO, buff, file_size); - return 1; - } - - if (get_mrc_data_slot((uint16_t *)(buff + offset), &data_offset, - &data_size)) { - fprintf(stderr, "Metadata block error\n"); - futil_unmap_and_close_file(fd, FILE_RO, buff, file_size); - 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 or data size greater than file size: " - "offset=%#x, file size=%#x, data_size=%#x\n", - offset, file_size, data_size); - - if (futil_unmap_and_close_file(fd, FILE_RO, buff, file_size) != - FILE_ERR_NONE) - return 1; - - return ret; -} - -DECLARE_FUTIL_COMMAND(validate_rec_mrc, do_validate_rec_mrc, VBOOT_VERSION_ALL, - "Validates content of Recovery MRC cache"); |