From 60bcbe3cd4c3921e6499170fd91eb47a040933a9 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Thu, 9 Sep 2010 14:53:56 -0700 Subject: [PATCH] New tools to help debug vboot failures. This adds some tools to help us figure out why a particular kernel isn't booting. Often we suspect it's because it was signed with the wrong keys, or has flags restricting its use to certain boot modes. This change adds some tools to extract and display all the keys from the BIOS, and try them on the various kernels. We also display the sha1sum of all the keys we find, to make comparing them easier. Change-Id: I38e447bf95cb6c3a0b87aa949611bb135f2f94b4 BUG=chromeos-partner:888 TEST=manual To test, obtain a root shell, and run dev_debug_vboot. You should see lots of useful information go by. Review URL: http://codereview.chromium.org/3303018 --- host/include/host_misc.h | 2 + host/lib/host_misc.c | 10 ++ utility/Makefile | 12 ++- utility/dev_debug_vboot | 67 +++++++++++++ utility/dump_fmap.c | 192 ++++++++++++++++++++++++++++++++++++++ utility/vbutil_firmware.c | 36 +++++-- utility/vbutil_kernel.c | 14 ++- utility/vbutil_key.c | 13 +-- utility/vbutil_keyblock.c | 12 +++ 9 files changed, 337 insertions(+), 21 deletions(-) create mode 100755 utility/dev_debug_vboot create mode 100644 utility/dump_fmap.c diff --git a/host/include/host_misc.h b/host/include/host_misc.h index abbfc0f622..cbf9eaffab 100644 --- a/host/include/host_misc.h +++ b/host/include/host_misc.h @@ -24,5 +24,7 @@ uint8_t* ReadFile(const char* filename, uint64_t* size); * Returns 0 if success, 1 if error. */ int WriteFile(const char* filename, const void *data, uint64_t size); +/* Prints the sha1sum of the given VbPublicKey to stdout. */ +void PrintPubKeySha1Sum(VbPublicKey* key); #endif /* VBOOT_REFERENCE_HOST_MISC_H_ */ diff --git a/host/lib/host_misc.c b/host/lib/host_misc.c index d8f5297020..91eaea25d5 100644 --- a/host/lib/host_misc.c +++ b/host/lib/host_misc.c @@ -66,3 +66,13 @@ int WriteFile(const char* filename, const void *data, uint64_t size) { fclose(f); return 0; } + +void PrintPubKeySha1Sum(VbPublicKey* key) { + uint8_t* buf = ((uint8_t *)key) + key->key_offset; + uint64_t buflen = key->key_size; + uint8_t* digest = DigestBuf(buf, buflen, SHA1_DIGEST_ALGORITHM); + int i; + for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* global variables */ +static int opt_extract = 0; +static char *progname; +static void *base_of_rom; + +/* FMAP structs. See http://code.google.com/p/flashmap/wiki/FmapSpec */ +#define FMAP_SIGLEN 8 +#define FMAP_NAMELEN 32 +#define FMAP_SEARCH_STRIDE 4 +typedef struct _FmapHeader { + char fmap_signature[FMAP_SIGLEN]; /* avoiding endian issues */ + uint8_t fmap_ver_major; + uint8_t fmap_ver_minor; + uint64_t fmap_base; + uint32_t fmap_size; + char fmap_name[FMAP_NAMELEN]; + uint16_t fmap_nareas; +} __attribute__((packed)) FmapHeader; + +typedef struct _AreaHeader { + uint32_t area_offset; + uint32_t area_size; + char area_name[FMAP_NAMELEN]; + uint16_t area_flags; +} __attribute__((packed)) AreaHeader; + + +/* Return 0 if successful */ +static int dump_fmap(void *ptr) { + int i,retval = 0; + char buf[80]; // DWR: magic number + FmapHeader *fmh = (FmapHeader *)ptr; + AreaHeader *ah = (AreaHeader *)(ptr + sizeof(FmapHeader)); + + snprintf(buf, FMAP_SIGLEN+1, "%s", fmh->fmap_signature); + printf("fmap_signature %s\n", buf); + printf("fmap_version: %d.%d\n", fmh->fmap_ver_major, fmh->fmap_ver_minor); + printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base); + printf("fmap_size: 0x%08x (%d)\n", fmh->fmap_size, fmh->fmap_size); + snprintf(buf, FMAP_NAMELEN+1, "%s", fmh->fmap_name); + printf("fmap_name: %s\n", buf); + printf("fmap_nareas: %d\n", fmh->fmap_nareas); + + for (i=0; ifmap_nareas; i++) { + printf("area: %d\n", i+1); + printf("area_offset: 0x%08x\n", ah->area_offset); + printf("area_size: 0x%08x (%d)\n", ah->area_size, ah->area_size); + snprintf(buf, FMAP_NAMELEN+1, "%s", ah->area_name); + printf("area_name: %s\n", buf); + + if (opt_extract) { + char *s; + for (s=buf; *s; s++) + if (*s == ' ') + *s = '_'; + FILE *fp = fopen(buf,"wb"); + if (!fp) { + fprintf(stderr, "%s: can't open %s: %s\n", + progname, buf, strerror(errno)); + retval = 1; + } else { + if (1 != fwrite(base_of_rom + ah->area_offset, ah->area_size, 1, fp)) { + fprintf(stderr, "%s: can't write %s: %s\n", + progname, buf, strerror(errno)); + retval = 1; + } else { + printf("saved as \"%s\"\n", buf); + } + fclose(fp); + } + } + + ah++; + } + + return retval; +} + + +int main(int argc, char *argv[]) { + int c; + int errorcnt = 0; + struct stat sb; + int fd; + char *s; + size_t i; + int retval = 1; + + progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + + opterr = 0; /* quiet, you */ + while ((c=getopt(argc, argv, ":x")) != -1) { + switch (c) + { + case 'x': + opt_extract = 1; + break; + case '?': + fprintf(stderr, "%s: unrecognized switch: -%c\n", + progname, optopt); + errorcnt++; + break; + case ':': + fprintf(stderr, "%s: missing argument to -%c\n", + progname, optopt); + errorcnt++; + break; + default: + errorcnt++; + break; + } + } + + if (errorcnt || optind >= argc) { + fprintf(stderr, + "\nUsage: %s [-x] FLASHIMAGE\n\n" + "Display (and extract with -x) the FMAP components from a BIOS image" + "\n\n", + progname); + return 1; + } + + if (0 != stat(argv[optind], &sb)) { + fprintf(stderr, "%s: can't stat %s: %s\n", + progname, + argv[optind], + strerror(errno)); + return 1; + } + + fd = open(argv[optind], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: can't open %s: %s\n", + progname, + argv[optind], + strerror(errno)); + return 1; + } + printf("opened %s\n", argv[optind]); + + base_of_rom = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (base_of_rom == (char *)-1) { + fprintf(stderr, "%s: can't mmap %s: %s\n", + progname, + argv[optind], + strerror(errno)); + close(fd); + return 1; + } + close(fd); /* done with this now */ + + s = (char *)base_of_rom; + for (i=0; i', required OPTIONS are:\n" " --signpubkey Signing public key in .vbpubk format\n" " --fv Firmware volume to verify\n" + "\n" + "For '--verify ', optional OPTIONS are:\n" + " --kernelkey Write the kernel subkey to this file\n" ""); return 1; } @@ -157,14 +160,14 @@ static int Vblock(const char* outfile, const char* keyblock_file, return 0; } - static int Verify(const char* infile, const char* signpubkey, - const char* fv_file) { + const char* fv_file, const char* kernelkey_file) { VbKeyBlockHeader* key_block; VbFirmwarePreambleHeader* preamble; VbPublicKey* data_key; VbPublicKey* sign_key; + VbPublicKey* kernel_subkey; RSAPublicKey* rsa; uint8_t* blob; uint64_t blob_size; @@ -210,11 +213,15 @@ static int Verify(const char* infile, const char* signpubkey, printf("Key block:\n"); data_key = &key_block->data_key; printf(" Size: %" PRIu64 "\n", key_block->key_block_size); + printf(" Flags: %" PRIu64 " (ignored)\n", + key_block->key_block_flags); printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, (data_key->algorithm < kNumAlgorithms ? algo_strings[data_key->algorithm] : "(invalid)")); printf(" Data key version: %" PRIu64 "\n", data_key->key_version); - printf(" Flags: %" PRIu64 "\n", key_block->key_block_flags); + printf(" Data key sha1sum: "); + PrintPubKeySha1Sum(data_key); + printf("\n"); rsa = PublicKeyToRSA(&key_block->data_key); if (!rsa) { @@ -235,12 +242,16 @@ static int Verify(const char* infile, const char* signpubkey, printf(" Header version: %" PRIu32 ".%" PRIu32"\n", preamble->header_version_major, preamble->header_version_minor); printf(" Firmware version: %" PRIu64 "\n", preamble->firmware_version); + kernel_subkey = &preamble->kernel_subkey; printf(" Kernel key algorithm: %" PRIu64 " %s\n", - preamble->kernel_subkey.algorithm, - (preamble->kernel_subkey.algorithm < kNumAlgorithms ? - algo_strings[preamble->kernel_subkey.algorithm] : "(invalid)")); + kernel_subkey->algorithm, + (kernel_subkey->algorithm < kNumAlgorithms ? + algo_strings[kernel_subkey->algorithm] : "(invalid)")); printf(" Kernel key version: %" PRIu64 "\n", - preamble->kernel_subkey.key_version); + kernel_subkey->key_version); + printf(" Kernel key sha1sum: "); + PrintPubKeySha1Sum(kernel_subkey); + printf("\n"); printf(" Firmware body size: %" PRIu64 "\n", preamble->body_signature.data_size); @@ -252,6 +263,15 @@ static int Verify(const char* infile, const char* signpubkey, return 1; } printf("Body verification succeeded.\n"); + + if (kernelkey_file) { + if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) { + fprintf(stderr, + "vbutil_firmware: unable to write kernel subkey\n"); + return 1; + } + } + return 0; } @@ -322,7 +342,7 @@ int main(int argc, char* argv[]) { return Vblock(filename, key_block_file, signprivate, version, fv_file, kernelkey_file); case OPT_MODE_VERIFY: - return Verify(filename, signpubkey, fv_file); + return Verify(filename, signpubkey, fv_file, kernelkey_file); default: printf("Must specify a mode.\n"); return PrintHelp(); diff --git a/utility/vbutil_kernel.c b/utility/vbutil_kernel.c index 80197194b8..acf156f704 100644 --- a/utility/vbutil_kernel.c +++ b/utility/vbutil_kernel.c @@ -661,11 +661,23 @@ static int Verify(const char* infile, const char* signpubkey, int verbose) { if (verbose) printf(" Signature: %s\n", sign_key ? "valid" : "ignored"); printf(" Size: 0x%" PRIx64 "\n", key_block->key_block_size); + printf(" Flags: %" PRIu64 " ", key_block->key_block_flags); + if (key_block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) + printf(" !DEV"); + if (key_block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) + printf(" DEV"); + if (key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) + printf(" !REC"); + if (key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1) + printf(" REC"); + printf("\n"); printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, (data_key->algorithm < kNumAlgorithms ? algo_strings[data_key->algorithm] : "(invalid)")); printf(" Data key version: %" PRIu64 "\n", data_key->key_version); - printf(" Flags: %" PRIu64 "\n", key_block->key_block_flags); + printf(" Data key sha1sum: "); + PrintPubKeySha1Sum(data_key); + printf("\n"); rsa = PublicKeyToRSA(&key_block->data_key); if (!rsa) { diff --git a/utility/vbutil_key.c b/utility/vbutil_key.c index c076bfff0f..38d9000305 100644 --- a/utility/vbutil_key.c +++ b/utility/vbutil_key.c @@ -108,15 +108,6 @@ static int Pack(const char *infile, const char *outfile, uint64_t algorithm, } -static void PrintDigest(const uint8_t* buf, uint64_t buflen) { - uint8_t *digest = DigestBuf(buf, buflen, SHA1_DIGEST_ALGORITHM); - int i; - for (i=0; ialgorithm] : "(invalid)")); printf("Key Version: %" PRIu64 "\n", pubkey->key_version); printf("Key sha1sum: "); - PrintDigest(((uint8_t *)pubkey) + pubkey->key_offset, pubkey->key_size); + PrintPubKeySha1Sum(pubkey); + printf("\n"); if (outfile) { if (0 != PublicKeyWrite(outfile, pubkey)) { fprintf(stderr, "vbutil_key: Error writing key copy.\n"); @@ -146,7 +138,6 @@ static int Unpack(const char *infile, const char *outfile) { return 0; } - if ((privkey = PrivateKeyRead(infile))) { printf("Private Key file: %s\n", infile); printf("Algorithm: %" PRIu64 " %s\n", privkey->algorithm, diff --git a/utility/vbutil_keyblock.c b/utility/vbutil_keyblock.c index 7d5b7c137a..ff1b44be45 100644 --- a/utility/vbutil_keyblock.c +++ b/utility/vbutil_keyblock.c @@ -152,12 +152,24 @@ static int Unpack(const char* infile, const char* datapubkey, printf("Key block file: %s\n", infile); printf("Flags: %" PRIu64 "\n", block->key_block_flags); + if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) + printf(" !DEV"); + if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) + printf(" DEV"); + if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) + printf(" !REC"); + if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1) + printf(" REC"); + printf("\n"); data_key = &block->data_key; printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, (data_key->algorithm < kNumAlgorithms ? algo_strings[data_key->algorithm] : "(invalid)")); printf("Data key version: %" PRIu64 "\n", data_key->key_version); + printf("Data key sha1sum: "); + PrintPubKeySha1Sum(data_key); + printf("\n"); if (datapubkey) { if (0 != PublicKeyWrite(datapubkey, data_key)) {