diff options
author | Shelley Chen <shchen@chromium.org> | 2015-01-08 09:13:44 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-01-23 21:32:12 +0000 |
commit | f1f53b3732f235da15a50080db6e7bbd4666e390 (patch) | |
tree | edddd76b155d86824fe33934a3d427914987b7ef /futility | |
parent | f242ad0f6fcfc9dc9195af06fe79301a9bd74113 (diff) | |
download | vboot-f1f53b3732f235da15a50080db6e7bbd4666e390.tar.gz |
vboot: Add flag to vbutil_kernel for reconstruction of vmlinuz image
Adding functionality to allow for rebuilding of vmlinuz after it
has been processed into vblock and header stripped. Basically appends
the 16-bit header of a vmlinuz image onto the end of the vblock.
BUG=chromium:438302
BRANCH=none
TEST=Successfully ran "make runalltests".
Also, ran:
1. Repack kernel block (so that 16-bit header is included):
"vbutil_kernel --pack kern_0 ..."
2. Verify kernel: "vbutil_kernel --verify kern_0 ... ". This should
be done before booting into kernel, but not necessary for it to work.
3. Rebuild vmlinuz image:
"vbutil_kernel --get-vmlinuz kern_0 --vmlinuz-out vm.out"
4. Set up kexec with vmlinuz (this should complete with no errors):
"kexec -l vm.out (other kernel cmd line args)"
5. Boot into kernel:
"kexec -e"
Change-Id: Iaa1582a1aedf70b43cdb3a56cde1fb248f1793d4
Signed-off-by: Shelley Chen <shchen@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/232750
Reviewed-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'futility')
-rw-r--r-- | futility/cmd_show.c | 15 | ||||
-rw-r--r-- | futility/cmd_vbutil_kernel.c | 92 | ||||
-rw-r--r-- | futility/vb1_helper.c | 99 |
3 files changed, 195 insertions, 11 deletions
diff --git a/futility/cmd_show.c b/futility/cmd_show.c index f2262698..7f0e488f 100644 --- a/futility/cmd_show.c +++ b/futility/cmd_show.c @@ -385,6 +385,8 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state) uint64_t kernel_size = 0; int good_sig = 0; int retval = 0; + uint64_t vmlinuz_header_size = 0; + uint64_t vmlinuz_header_address = 0; /* Check the hash... */ if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) { @@ -435,6 +437,19 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state) printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size); + if (VbGetKernelVmlinuzHeader(preamble, + &vmlinuz_header_address, + &vmlinuz_header_size) + != VBOOT_SUCCESS) { + fprintf(stderr, "Unable to retrieve Vmlinuz Header!"); + return 1; + } + if (vmlinuz_header_size) { + printf(" Vmlinuz_header address: 0x%" PRIx64 "\n", + vmlinuz_header_address); + printf(" Vmlinuz header size: 0x%" PRIx64 "\n", + vmlinuz_header_size); + } /* Verify kernel body */ if (option.fv) { diff --git a/futility/cmd_vbutil_kernel.c b/futility/cmd_vbutil_kernel.c index 786344fb..3b2643e4 100644 --- a/futility/cmd_vbutil_kernel.c +++ b/futility/cmd_vbutil_kernel.c @@ -43,6 +43,7 @@ enum { OPT_MODE_PACK = 1000, OPT_MODE_REPACK, OPT_MODE_VERIFY, + OPT_MODE_GET_VMLINUZ, OPT_ARCH, OPT_OLDBLOB, OPT_KLOADADDR, @@ -57,12 +58,14 @@ enum { OPT_PAD, OPT_VERBOSE, OPT_MINVERSION, + OPT_VMLINUZ_OUT, }; static const struct option long_opts[] = { {"pack", 1, 0, OPT_MODE_PACK}, {"repack", 1, 0, OPT_MODE_REPACK}, {"verify", 1, 0, OPT_MODE_VERIFY}, + {"get-vmlinuz", 1, 0, OPT_MODE_GET_VMLINUZ}, {"arch", 1, 0, OPT_ARCH}, {"oldblob", 1, 0, OPT_OLDBLOB}, {"kloadaddr", 1, 0, OPT_KLOADADDR}, @@ -78,6 +81,7 @@ static const struct option long_opts[] = { {"pad", 1, 0, OPT_PAD}, {"verbose", 0, &opt_verbose, 1}, {"debug", 0, &debugging_enabled, 1}, + {"vmlinuz-out", 1, 0, OPT_VMLINUZ_OUT}, {NULL, 0, 0, 0} }; @@ -129,14 +133,18 @@ static const char usage[] = " in .keyblock format\n" " --pad <number> Verification padding size in bytes\n" " --minversion <number> Minimum combined kernel key version\n" - " and kernel version\n" + "\nOR\n\n" + "Usage: " MYNAME " %s --get-vmlinuz <file> [PARAMETERS]\n" + "\n" + " Required parameters:\n" + " --vmlinuz-out <file> vmlinuz image output file\n" "\n"; /* Print help and return error */ static void print_help(const char *progname) { - printf(usage, progname, progname, progname); + printf(usage, progname, progname, progname, progname); } @@ -209,13 +217,14 @@ static int do_vbutil_kernel(int argc, char *argv[]) char *vmlinuz_file = NULL; char *bootloader_file = NULL; char *config_file = NULL; + char *vmlinuz_out_file = NULL; enum arch_t arch = ARCH_X86; uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR; int mode = 0; int parse_error = 0; uint64_t min_version = 0; char *e; - int i; + int i = 0; int rv; VbKeyBlockHeader *keyblock = NULL; VbKeyBlockHeader *t_keyblock = NULL; @@ -229,11 +238,14 @@ static int do_vbutil_kernel(int argc, char *argv[]) uint64_t t_config_size; uint8_t *t_bootloader_data; uint64_t t_bootloader_size; + uint64_t vmlinuz_header_size = 0; + uint64_t vmlinuz_header_address = 0; VbKernelPreambleHeader *preamble = NULL; uint8_t *kblob_data = NULL; uint64_t kblob_size = 0; uint8_t *vblock_data = NULL; uint64_t vblock_size = 0; + FILE *f; while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && !parse_error) { @@ -251,6 +263,7 @@ static int do_vbutil_kernel(int argc, char *argv[]) case OPT_MODE_PACK: case OPT_MODE_REPACK: case OPT_MODE_VERIFY: + case OPT_MODE_GET_VMLINUZ: if (mode && (mode != i)) { fprintf(stderr, "Only one mode can be specified\n"); @@ -343,6 +356,8 @@ static int do_vbutil_kernel(int argc, char *argv[]) parse_error = 1; } break; + case OPT_VMLINUZ_OUT: + vmlinuz_out_file = optarg; } } @@ -519,10 +534,79 @@ static int do_vbutil_kernel(int argc, char *argv[]) signpub_key, keyblock_file, min_version); return rv; + + case OPT_MODE_GET_VMLINUZ: + + if (!vmlinuz_out_file) { + fprintf(stderr, + "USE: vbutil_kernel --get-vmlinuz <file> " + "--vmlinuz-out <file>\n"); + print_help(argv[0]); + return 1; + } + + kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size); + + kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad, + &keyblock, &preamble, &kblob_size); + + if (!kblob_data) + Fatal("Unable to unpack kernel partition\n"); + + f = fopen(vmlinuz_out_file, "wb"); + if (!f) { + VbExError("Can't open output file %s\n", + vmlinuz_out_file); + return 1; + } + + /* Now stick 16-bit header followed by kernel block into + output */ + if (VbGetKernelVmlinuzHeader(preamble, + &vmlinuz_header_address, + &vmlinuz_header_size) + != VBOOT_SUCCESS) { + Fatal("Unable to retrieve Vmlinuz Header!"); + } + if (vmlinuz_header_size) { + // verify that the 16-bit header is included in the + // kblob (to make sure that it's included in the + // signature) + if (VerifyVmlinuzInsideKBlob(preamble->body_load_address, + kblob_size, + vmlinuz_header_address, + vmlinuz_header_size)) { + VbExError("Vmlinuz header not signed!\n"); + fclose(f); + unlink(vmlinuz_out_file); + return 1; + } + + i = (1 != fwrite((void*)(uintptr_t) + vmlinuz_header_address, + vmlinuz_header_size, + 1, + f)); + } + i = i || (1 != fwrite(kblob_data, + kblob_size, + 1, + f)); + if (i) { + VbExError("Can't write output file %s\n", + vmlinuz_out_file); + fclose(f); + unlink(vmlinuz_out_file); + return 1; + } + + fclose(f); + return 1; } fprintf(stderr, - "You must specify a mode: --pack, --repack or --verify\n"); + "You must specify a mode: " + "--pack, --repack, --verify, or --get-vmlinuz\n"); print_help(argv[0]); return 1; } diff --git a/futility/vb1_helper.c b/futility/vb1_helper.c index b3376726..dd219ef8 100644 --- a/futility/vb1_helper.c +++ b/futility/vb1_helper.c @@ -20,7 +20,8 @@ /* Here are globals containing all the bits & pieces I'm working on. * * kernel vblock = keyblock + kernel preamble + padding to 64K (or whatever) - * kernel blob = 32-bit kernel + config file + params + bootloader stub + * kernel blob = 32-bit kernel + config file + params + bootloader stub + + * vmlinuz_header * kernel partition = kernel vblock + kernel blob * * The VbKernelPreambleHeader.preamble_size includes the padding. @@ -41,8 +42,11 @@ static uint8_t *g_param_data; static uint64_t g_param_size; static uint8_t *g_bootloader_data; static uint64_t g_bootloader_size; +static uint8_t *g_vmlinuz_header_data; +static uint64_t g_vmlinuz_header_size; static uint64_t g_ondisk_bootloader_addr; +static uint64_t g_ondisk_vmlinuz_header_addr; /* @@ -163,6 +167,9 @@ static int PickApartVmlinuz(uint8_t *kernel_buf, uint64_t kernel_size, } kernel32_size = kernel_size - kernel32_start; + Debug(" kernel16_start=0x%" PRIx64 "\n", 0); + Debug(" kernel16_size=0x%" PRIx64 "\n", kernel32_start); + /* Copy the original zeropage data from kernel_buf into * g_param_data, then tweak a few fields for our purposes */ params = (struct linux_kernel_params *)(g_param_data); @@ -206,14 +213,34 @@ static int PickApartVmlinuz(uint8_t *kernel_buf, uint64_t kernel_size, return 0; } -/* Split a kernel blob into separate g_kernel, g_param, g_config, and - * g_bootloader parts. */ +/* Split a kernel blob into separate g_kernel, g_param, g_config, + * g_bootloader, and g_vmlinuz_header parts. */ static void UnpackKernelBlob(uint8_t *kernel_blob_data) { uint64_t now; + uint64_t vmlinuz_header_size = 0; + uint64_t vmlinuz_header_address = 0; /* We have to work backwards from the end, because the preamble - only describes the bootloader stub. */ + only describes the bootloader and vmlinuz stubs. */ + + /* Vmlinuz Header is at the end */ + if (VbGetKernelVmlinuzHeader(g_preamble, + &vmlinuz_header_address, + &vmlinuz_header_size) + != VBOOT_SUCCESS) { + fprintf(stderr, "Unable to retrieve Vmlinuz Header!"); + return; + } + if (vmlinuz_header_size) { + now = vmlinuz_header_address - g_preamble->body_load_address; + g_vmlinuz_header_size = vmlinuz_header_size; + g_vmlinuz_header_data = kernel_blob_data + now; + + Debug("vmlinuz_header_size = 0x%" PRIx64 "\n", + g_vmlinuz_header_size); + Debug("vmlinuz_header_ofs = 0x%" PRIx64 "\n", now); + } /* Where does the bootloader stub begin? */ now = g_preamble->bootloader_address - g_preamble->body_load_address; @@ -273,6 +300,8 @@ uint8_t *UnpackKPart(uint8_t *kpart_data, uint64_t kpart_size, { VbKeyBlockHeader *keyblock; VbKernelPreambleHeader *preamble; + uint64_t vmlinuz_header_size = 0; + uint64_t vmlinuz_header_address = 0; uint64_t now = 0; /* Sanity-check the keyblock */ @@ -319,6 +348,21 @@ uint8_t *UnpackKPart(uint8_t *kpart_data, uint64_t kpart_size, g_preamble = preamble; g_ondisk_bootloader_addr = g_preamble->bootloader_address; + if (VbGetKernelVmlinuzHeader(preamble, + &vmlinuz_header_address, + &vmlinuz_header_size) + != VBOOT_SUCCESS) { + fprintf(stderr, "Unable to retrieve Vmlinuz Header!"); + return NULL; + } + if (vmlinuz_header_size) { + Debug(" vmlinuz_header_address = 0x%" PRIx64 "\n", + vmlinuz_header_address); + Debug(" vmlinuz_header_size = 0x%" PRIx64 "\n", + vmlinuz_header_size); + g_ondisk_vmlinuz_header_addr = vmlinuz_header_address; + } + Debug("kernel blob is at offset 0x%" PRIx64 "\n", now); g_kernel_blob_data = kpart_data + now; g_kernel_blob_size = preamble->body_signature.data_size; @@ -367,7 +411,10 @@ uint8_t *SignKernelBlob(uint8_t *kernel_blob, uint64_t kernel_size, kernel_body_load_address, g_ondisk_bootloader_addr, g_bootloader_size, - body_sig, min_size, + body_sig, + g_ondisk_vmlinuz_header_addr, + g_vmlinuz_header_size, + min_size, signpriv_key); if (!preamble) { fprintf(stderr, "Error creating preamble.\n"); @@ -440,6 +487,8 @@ int VerifyKernelBlob(uint8_t *kernel_blob, VbPublicKey *data_key; RSAPublicKey *rsa; int rv = -1; + uint64_t vmlinuz_header_size = 0; + uint64_t vmlinuz_header_address = 0; if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size, signpub_key, (0 == signpub_key))) { @@ -526,6 +575,20 @@ int VerifyKernelBlob(uint8_t *kernel_blob, printf(" Bootloader size: 0x%" PRIx64 "\n", g_preamble->bootloader_size); + if (VbGetKernelVmlinuzHeader(g_preamble, + &vmlinuz_header_address, + &vmlinuz_header_size) + != VBOOT_SUCCESS) { + fprintf(stderr, "Unable to retrieve Vmlinuz Header!"); + goto done; + } + if (vmlinuz_header_size) { + printf(" Vmlinuz header address: 0x%" PRIx64 "\n", + vmlinuz_header_address); + printf(" Vmlinuz header size: 0x%" PRIx64 "\n", + vmlinuz_header_size); + } + if (g_preamble->kernel_version < (min_version & 0xFFFF)) { fprintf(stderr, "Kernel version %" PRIu64 " is lower than minimum %" @@ -567,8 +630,13 @@ uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size, g_config_size = CROS_CONFIG_SIZE; g_param_size = CROS_PARAMS_SIZE; g_bootloader_size = roundup(bootloader_size, CROS_ALIGN); - g_kernel_blob_size = roundup(g_kernel_size, CROS_ALIGN) + - g_config_size + g_param_size + g_bootloader_size; + g_vmlinuz_header_size = vmlinuz_size-g_kernel_size; + g_kernel_blob_size = + roundup(g_kernel_size, CROS_ALIGN) + + g_config_size + + g_param_size + + g_bootloader_size + + g_vmlinuz_header_size; Debug("g_kernel_blob_size 0x%" PRIx64 "\n", g_kernel_blob_size); /* Allocate space for the blob. */ @@ -597,6 +665,18 @@ uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size, g_ondisk_bootloader_addr = kernel_body_load_address + now; Debug("g_ondisk_bootloader_addr 0x%" PRIx64 "\n", g_ondisk_bootloader_addr); + now += g_bootloader_size; + + if (g_vmlinuz_header_size) { + g_vmlinuz_header_data = g_kernel_blob_data + now; + Debug("g_vmlinuz_header_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n", + g_vmlinuz_header_size, now); + g_ondisk_vmlinuz_header_addr = kernel_body_load_address + now; + Debug("g_ondisk_vmlinuz_header_addr 0x%" PRIx64 "\n", + g_ondisk_vmlinuz_header_addr); + } + + Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now); /* Copy the kernel and params bits into the correct places */ if (0 != PickApartVmlinuz(vmlinuz_buf, vmlinuz_size, @@ -611,6 +691,11 @@ uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size, /* Copy the other bits too */ Memcpy(g_config_data, config_data, config_size); Memcpy(g_bootloader_data, bootloader_data, bootloader_size); + if (g_vmlinuz_header_size) { + Memcpy(g_vmlinuz_header_data, + vmlinuz_buf, + g_vmlinuz_header_size); + } if (blob_size_ptr) *blob_size_ptr = g_kernel_blob_size; |