diff options
author | Bill Richardson <wfrichar@chromium.org> | 2014-09-23 14:30:30 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-09-25 20:27:00 +0000 |
commit | f318ee205cc8d92def925c6158272da8a63bf1ed (patch) | |
tree | a0c380fed4d67fbfec256babd3b29175be52464c | |
parent | d5aa5bdb292b64f259f55319fd83bd4a4d548a12 (diff) | |
download | vboot-f318ee205cc8d92def925c6158272da8a63bf1ed.tar.gz |
futility: implement vbutil_kernel using buffers, not files
The original vbutil_kernel command used file read and write to
make changes. Futility prefers to use memory-mapped files. This
rewrites cmd_vbutil_kernel.c to use that scheme.
BUG=none
BRANCH=ToT
TEST=make runtests
The original cmd_vbutil_kernel.c is renamed, and a test written
to ensure that the refactored version produces identical results.
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Change-Id: Ic6c3e12429a5dcb271f8136a9edac70807d66120
Reviewed-on: https://chromium-review.googlesource.com/219647
Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | futility/cmd_vbutil_kernel.c | 743 | ||||
-rw-r--r-- | futility/cmd_vbutil_kernel0.c | 974 | ||||
-rw-r--r-- | futility/vb1_helper.c | 616 | ||||
-rw-r--r-- | futility/vb1_helper.h | 44 | ||||
-rw-r--r-- | tests/futility/data/vmlinuz-amd64.bin | bin | 0 -> 4019120 bytes | |||
-rw-r--r-- | tests/futility/data/vmlinuz-arm.bin | bin | 0 -> 4396960 bytes | |||
-rwxr-xr-x | tests/futility/run_test_scripts.sh | 1 | ||||
-rwxr-xr-x | tests/futility/test_sign_kernel.sh | 168 |
9 files changed, 1958 insertions, 596 deletions
@@ -541,14 +541,16 @@ FUTIL_SRCS = \ futility/cmd_dev_sign_file.c \ futility/cmd_dump_kernel_config.c \ futility/cmd_load_fmap.c \ + futility/cmd_show.c \ + futility/cmd_sign.c \ futility/cmd_vbutil_firmware.c \ futility/cmd_vbutil_kernel.c \ + futility/cmd_vbutil_kernel0.c \ futility/cmd_vbutil_key.c \ futility/cmd_vbutil_keyblock.c \ futility/cmd_verify_kernel.c \ - futility/cmd_show.c \ - futility/cmd_sign.c \ - futility/traversal.c + futility/traversal.c \ + futility/vb1_helper.c ifneq (${VBOOT2},) FUTIL_SRCS += \ diff --git a/futility/cmd_vbutil_kernel.c b/futility/cmd_vbutil_kernel.c index 855c7a53..92061f43 100644 --- a/futility/cmd_vbutil_kernel.c +++ b/futility/cmd_vbutil_kernel.c @@ -1,4 +1,5 @@ -/* Copyright 2012 The Chromium OS Authors. All rights reserved. +/* + * Copyright 2014 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * @@ -9,23 +10,28 @@ #include <fcntl.h> #include <getopt.h> #include <inttypes.h> /* For PRIu64 */ -#include <sys/ioctl.h> #include <linux/fs.h> /* For BLKGETSIZE64 */ #include <stdarg.h> -#include <stddef.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> +#include <sys/ioctl.h> #include <sys/stat.h> -#include <sys/types.h> #include <unistd.h> -#include "cryptolib.h" #include "futility.h" #include "host_common.h" #include "kernel_blob.h" -#include "util_misc.h" -#include "vboot_common.h" +#include "vb1_helper.h" + +static void Fatal(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + fprintf(stderr, "ERROR: "); + vfprintf(stderr, format, ap); + va_end(ap); + exit(1); +} /* Global opts */ static int opt_verbose; @@ -133,15 +139,6 @@ static void print_help(const char *progname) printf(usage, progname, progname, progname); } -static void Fatal(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - fprintf(stderr, "ERROR: "); - vfprintf(stderr, format, ap); - va_end(ap); - exit(1); -} /* Return an explanation when fread() fails. */ static const char *error_fread(FILE *fp) @@ -155,194 +152,14 @@ static const char *error_fread(FILE *fp) return retval; } -/* Return the smallest integral multiple of [alignment] that is equal - * to or greater than [val]. Used to determine the number of - * pages/sectors/blocks/whatever needed to contain [val] - * items/bytes/etc. */ -static uint64_t roundup(uint64_t val, uint64_t alignment) -{ - uint64_t rem = val % alignment; - if (rem) - return val + (alignment - rem); - return val; -} -/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we - * don't find one, we'll use the whole thing. */ -static unsigned int find_cmdline_start(char *input, unsigned int max_len) -{ - int start = 0; - int i; - for (i = 0; i < max_len - 1 && input[i]; i++) { - if ('-' == input[i] && '-' == input[i + 1]) { - if ((i == 0 || ' ' == input[i - 1]) && - (i + 2 >= max_len || ' ' == input[i + 2])) { - /* found "--" with nothing before or after it */ - start = i + 2; /* hope for a trailing '\0' */ - break; - } - } - } - while (' ' == input[start]) /* skip leading spaces */ - start++; - - return start; -} - -/****************************************************************************/ -/* Here are globals containing all the bits & pieces I'm working on. */ - -/* The individual parts that go into the kernel blob */ -static uint8_t *g_kernel_data; -static uint64_t g_kernel_size; -static uint8_t *g_param_data; -static uint64_t g_param_size; -static uint8_t *g_config_data; -static uint64_t g_config_size; -static uint8_t *g_bootloader_data; -static uint64_t g_bootloader_size; -static uint64_t g_bootloader_address; - -/* The individual parts of the verification blob (including the data that - * immediately follows the headers) */ -static VbKeyBlockHeader *g_keyblock; -static VbKernelPreambleHeader *g_preamble; - -/****************************************************************************/ - -/* - * Read the kernel command line from a file. Get rid of \n characters along - * the way and verify that the line fits into a 4K buffer. - * - * Return the buffer contaning the line on success (and set the line length - * using the passed in parameter), or NULL in case something goes wrong. - */ -static uint8_t *sReadConfigFile(const char *config_file, uint64_t *config_size) -{ - uint8_t *config_buf; - int ii; - - config_buf = ReadFile(config_file, config_size); - Debug(" config file size=0x%" PRIx64 "\n", *config_size); - if (CROS_CONFIG_SIZE <= *config_size) { /* room for trailing '\0' */ - VbExError("Config file %s is too large (>= %d bytes)\n", - config_file, CROS_CONFIG_SIZE); - return NULL; - } - - /* Replace newlines with spaces */ - for (ii = 0; ii < *config_size; ii++) - if ('\n' == config_buf[ii]) - config_buf[ii] = ' '; - - return config_buf; -} - -/* Offset of kernel command line string from start of packed kernel blob */ -static uint64_t CmdLineOffset(VbKernelPreambleHeader *preamble) -{ - return preamble->bootloader_address - preamble->body_load_address - - CROS_CONFIG_SIZE - CROS_PARAMS_SIZE; -} - -/* This initializes g_vmlinuz and g_param from a standard vmlinuz file. - * It returns 0 on error. */ -static int ImportVmlinuzFile(const char *vmlinuz_file, enum arch_t arch, - uint64_t kernel_body_load_address) -{ - uint8_t *kernel_buf; - uint64_t kernel_size; - uint64_t kernel32_start = 0; - uint64_t kernel32_size = 0; - struct linux_kernel_params *params = NULL, *lh = NULL; - - /* Read the kernel */ - Debug("Reading %s\n", vmlinuz_file); - kernel_buf = ReadFile(vmlinuz_file, &kernel_size); - if (!kernel_buf) - return 0; - Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size); - if (!kernel_size) - Fatal("Empty kernel file\n"); - - /* Go ahead and allocate the param region anyway. I don't think we need - * it for non-x86, but let's keep it for now. */ - g_param_size = CROS_PARAMS_SIZE; - g_param_data = VbExMalloc(g_param_size); - Memset(g_param_data, 0, g_param_size); - - /* Unless we're handling x86, the kernel is the kernel; we're done. */ - if (arch != ARCH_X86) { - g_kernel_data = kernel_buf; - g_kernel_size = kernel_size; - return 1; - } - - /* The first part of the x86 vmlinuz is a header, followed by a - * real-mode boot stub. We only want the 32-bit part. */ - lh = (struct linux_kernel_params *)kernel_buf; - kernel32_start = (lh->setup_sects + 1) << 9; - if (kernel32_start >= kernel_size) - Fatal("Malformed kernel\n"); - kernel32_size = kernel_size - kernel32_start; - - Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start); - Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size); - - /* Keep just the 32-bit kernel. */ - if (kernel32_size) { - g_kernel_size = kernel32_size; - g_kernel_data = VbExMalloc(g_kernel_size); - Memcpy(g_kernel_data, kernel_buf + kernel32_start, - kernel32_size); - } - - /* 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); - Memcpy(&(params->setup_sects), &(lh->setup_sects), - offsetof(struct linux_kernel_params, e820_entries) - - offsetof(struct linux_kernel_params, setup_sects)); - params->boot_flag = 0; - params->ramdisk_image = 0; /* we don't support initrd */ - params->ramdisk_size = 0; - params->type_of_loader = 0xff; - /* We need to point to the kernel commandline arg. On disk, it will come - * right after the 32-bit part of the kernel. */ - params->cmd_line_ptr = kernel_body_load_address + - roundup(kernel32_size, CROS_ALIGN) + - find_cmdline_start((char *)g_config_data, g_config_size); - Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr); - Debug(" version=0x%x\n", params->version); - Debug(" kernel_alignment=0x%x\n", params->kernel_alignment); - Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel); - /* A fake e820 memory map with 2 entries */ - params->n_e820_entry = 2; - params->e820_entries[0].start_addr = 0x00000000; - params->e820_entries[0].segment_size = 0x00001000; - params->e820_entries[0].segment_type = E820_TYPE_RAM; - params->e820_entries[1].start_addr = 0xfffff000; - params->e820_entries[1].segment_size = 0x00001000; - params->e820_entries[1].segment_type = E820_TYPE_RESERVED; - - /* done */ - free(kernel_buf); - return 1; -} - -/* This returns just the kernel blob, with the verification blob separated - * and copied to new memory in g_keyblock and g_preamble. */ -static uint8_t *ReadOldBlobFromFileOrDie(const char *filename, +/* This reads a complete kernel partition into a buffer */ +static uint8_t *ReadOldKPartFromFileOrDie(const char *filename, uint64_t *size_ptr) { FILE *fp = NULL; struct stat statbuf; - VbKeyBlockHeader *key_block; - VbKernelPreambleHeader *preamble; - uint64_t now = 0; uint8_t *buf; - uint8_t *kernel_blob_data; - uint64_t kernel_blob_size; uint64_t file_size = 0; if (0 != stat(filename, &statbuf)) @@ -367,330 +184,20 @@ static uint8_t *ReadOldBlobFromFileOrDie(const char *filename, Fatal("Unable to open file %s: %s\n", filename, strerror(errno)); - buf = VbExMalloc(opt_pad); - if (1 != fread(buf, opt_pad, 1, fp)) - Fatal("Unable to read header from %s: %s\n", filename, - error_fread(fp)); - - /* Sanity-check the key_block */ - key_block = (VbKeyBlockHeader *) buf; - Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size); - now += key_block->key_block_size; - if (now > file_size) - Fatal("key_block_size advances past the end of the blob\n"); - if (now > opt_pad) - Fatal("key_block_size advances past %" PRIu64 " byte padding\n", - opt_pad); - /* LGTM */ - g_keyblock = (VbKeyBlockHeader *) VbExMalloc(key_block->key_block_size); - Memcpy(g_keyblock, key_block, key_block->key_block_size); - - /* And the preamble */ - preamble = (VbKernelPreambleHeader *) (buf + now); - Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); - now += preamble->preamble_size; - if (now > file_size) - Fatal("preamble_size advances past the end of the blob\n"); - if (now > opt_pad) - Fatal("preamble_size advances past %" PRIu64 " byte padding\n", - opt_pad); - /* LGTM */ - Debug(" kernel_version = %d\n", preamble->kernel_version); - Debug(" bootloader_address = 0x%" PRIx64 "\n", - preamble->bootloader_address); - Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size); - Debug(" kern_blob_size = 0x%" PRIx64 "\n", - preamble->body_signature.data_size); - g_preamble = - (VbKernelPreambleHeader *) VbExMalloc(preamble->preamble_size); - Memcpy(g_preamble, preamble, preamble->preamble_size); - - /* Now for the kernel blob */ - Debug("kernel blob is at offset 0x%" PRIx64 "\n", now); - if (0 != fseek(fp, now, SEEK_SET)) - Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, - filename, strerror(errno)); - - /* Sanity check */ - kernel_blob_size = file_size - now; - if (!kernel_blob_size) - Fatal("No kernel blob found\n"); - if (kernel_blob_size < preamble->body_signature.data_size) - fprintf(stderr, - "Warning: kernel file only has 0x%" PRIx64 " bytes\n", - kernel_blob_size); - kernel_blob_data = VbExMalloc(kernel_blob_size); - - /* Read it in */ - if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp)) - Fatal("Unable to read kernel blob from %s: %s\n", filename, + buf = malloc(file_size); + if (1 != fread(buf, file_size, 1, fp)) + Fatal("Unable to read entirety of %s: %s\n", filename, error_fread(fp)); - /* Done */ - VbExFree(buf); - - if (size_ptr) - *size_ptr = kernel_blob_size; - - return kernel_blob_data; -} - -/* Split a kernel blob into separate g_kernel, g_param, g_config, and - * g_bootloader parts. */ -static void UnpackKernelBlob(uint8_t *kernel_blob_data, - uint64_t kernel_blob_size) -{ - - uint64_t k_blob_size = g_preamble->body_signature.data_size; - uint64_t k_blob_ofs = 0; - uint64_t b_size = g_preamble->bootloader_size; - uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address - - g_preamble->body_load_address; - uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE; - uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE; - - Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size); - Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs); - Debug("b_size = 0x%" PRIx64 "\n", b_size); - Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs); - Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs); - Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs); - - g_kernel_size = c_ofs; - g_kernel_data = VbExMalloc(g_kernel_size); - Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size); - - g_param_size = CROS_PARAMS_SIZE; - g_param_data = VbExMalloc(g_param_size); - Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size); - - g_config_size = CROS_CONFIG_SIZE; - g_config_data = VbExMalloc(g_config_size); - Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size); - - g_bootloader_size = b_size; - g_bootloader_data = VbExMalloc(g_bootloader_size); - Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size); -} - -/****************************************************************************/ - -static uint8_t *CreateKernBlob(uint64_t kernel_body_load_address, - enum arch_t arch, uint64_t *size_ptr) -{ - uint8_t *kern_blob; - uint64_t kern_blob_size; - uint64_t now; - uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN); - - /* Put the kernel blob together */ - kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) + - CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size; - Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size); - kern_blob = VbExMalloc(kern_blob_size); - Memset(kern_blob, 0, kern_blob_size); - now = 0; - - Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now); - - Memcpy(kern_blob + now, g_kernel_data, g_kernel_size); - now += roundup(g_kernel_size, CROS_ALIGN); - - Debug("config goes at kern_blob+0x%" PRIx64 "\n", now); - if (g_config_size) - Memcpy(kern_blob + now, g_config_data, g_config_size); - now += CROS_CONFIG_SIZE; - - Debug("params goes at kern_blob+0x%" PRIx64 "\n", now); - if (g_param_size) - Memcpy(kern_blob + now, g_param_data, g_param_size); - now += CROS_PARAMS_SIZE; - - Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now); - g_bootloader_address = kernel_body_load_address + now; - Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address); - Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size); - if (bootloader_size) - Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size); - now += bootloader_size; - Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now); - - /* Done */ if (size_ptr) - *size_ptr = kern_blob_size; - - return kern_blob; -} - -static int Pack(const char *outfile, - uint8_t *kernel_blob, - uint64_t kernel_size, - int version, - uint64_t kernel_body_load_address, - VbPrivateKey *signpriv_key) -{ - VbSignature *body_sig; - FILE *f; - uint64_t i; - uint64_t written = 0; - - /* Sign the kernel data */ - body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key); - if (!body_sig) - Fatal("Error calculating body signature\n"); - - /* Create preamble */ - g_preamble = CreateKernelPreamble(version, - kernel_body_load_address, - g_bootloader_address, - roundup(g_bootloader_size, - CROS_ALIGN), body_sig, - opt_pad - g_keyblock->key_block_size, - signpriv_key); - if (!g_preamble) { - VbExError("Error creating preamble.\n"); - return 1; - } - /* Write the output file */ - Debug("writing %s...\n", outfile); - f = fopen(outfile, "wb"); - if (!f) { - VbExError("Can't open output file %s\n", outfile); - return 1; - } - Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size); - Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size); - i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) || - (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f))); - if (i) { - VbExError("Can't write output file %s\n", outfile); - fclose(f); - unlink(outfile); - return 1; - } - written += g_keyblock->key_block_size; - written += g_preamble->preamble_size; - - if (!opt_vblockonly) { - Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size); - i = (1 != fwrite(kernel_blob, kernel_size, 1, f)); - if (i) { - fclose(f); - unlink(outfile); - Fatal("Can't write output file %s\n", outfile); - } - written += kernel_size; - } - Debug("0x%" PRIx64 " bytes total\n", written); - fclose(f); - - /* Success */ - return 0; -} - -static int Verify(uint8_t *kernel_blob, - uint64_t kernel_size, - VbPublicKey *signpub_key, - const char *keyblock_outfile, - uint64_t min_version) -{ - VbPublicKey *data_key; - RSAPublicKey *rsa; - - if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size, - signpub_key, (0 == signpub_key))) - Fatal("Error verifying key block.\n"); - - printf("Key block:\n"); - data_key = &g_keyblock->data_key; - if (opt_verbose) - printf(" Signature: %s\n", - signpub_key ? "valid" : "ignored"); - printf(" Size: 0x%" PRIx64 "\n", - g_keyblock->key_block_size); - printf(" Flags: %" PRIu64 " ", - g_keyblock->key_block_flags); - if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) - printf(" !DEV"); - if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) - printf(" DEV"); - if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) - printf(" !REC"); - if (g_keyblock->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(" Data key sha1sum: "); - PrintPubKeySha1Sum(data_key); - printf("\n"); - - if (keyblock_outfile) { - FILE *f = NULL; - f = fopen(keyblock_outfile, "wb"); - if (!f) - Fatal("Can't open key block file %s\n", - keyblock_outfile); - if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) - Fatal("Can't write key block file %s\n", - keyblock_outfile); - fclose(f); - } + *size_ptr = file_size; - if (data_key->key_version < (min_version >> 16)) - Fatal("Data key version %" PRIu64 - " is lower than minimum %" PRIu64 ".\n", - data_key->key_version, (min_version >> 16)); - - rsa = PublicKeyToRSA(data_key); - if (!rsa) - Fatal("Error parsing data key.\n"); - - /* Verify preamble */ - if (0 != - VerifyKernelPreamble(g_preamble, g_preamble->preamble_size, rsa)) - Fatal("Error verifying preamble.\n"); - - printf("Preamble:\n"); - printf(" Size: 0x%" PRIx64 "\n", - g_preamble->preamble_size); - printf(" Header version: %" PRIu32 ".%" PRIu32 "\n", - g_preamble->header_version_major, - g_preamble->header_version_minor); - printf(" Kernel version: %" PRIu64 "\n", - g_preamble->kernel_version); - printf(" Body load address: 0x%" PRIx64 "\n", - g_preamble->body_load_address); - printf(" Body size: 0x%" PRIx64 "\n", - g_preamble->body_signature.data_size); - printf(" Bootloader address: 0x%" PRIx64 "\n", - g_preamble->bootloader_address); - printf(" Bootloader size: 0x%" PRIx64 "\n", - g_preamble->bootloader_size); - - if (g_preamble->kernel_version < (min_version & 0xFFFF)) - Fatal("Kernel version %" PRIu64 " is lower than minimum %" - PRIu64 ".\n", g_preamble->kernel_version, - (min_version & 0xFFFF)); - - /* Verify body */ - if (0 != VerifyData(kernel_blob, kernel_size, - &g_preamble->body_signature, rsa)) - Fatal("Error verifying kernel body.\n"); - printf("Body verification succeeded.\n"); - - if (opt_verbose) - printf("Config:\n%s\n", - kernel_blob + CmdLineOffset(g_preamble)); - - return 0; + return buf; } /****************************************************************************/ -static int do_vbutil_kernel(int argc, char *argv[]) +static int do_vbutil_kernel2(int argc, char *argv[]) { char *filename = NULL; char *oldfile = NULL; @@ -703,17 +210,30 @@ static int do_vbutil_kernel(int argc, char *argv[]) char *bootloader_file = NULL; char *config_file = NULL; enum arch_t arch = ARCH_X86; - char *address_str = NULL; 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 rv; + VbKeyBlockHeader *keyblock = NULL; + VbKeyBlockHeader *t_keyblock = NULL; VbPrivateKey *signpriv_key = NULL; VbPublicKey *signpub_key = NULL; - uint8_t *kernel_blob = NULL; - uint64_t kernel_size = 0; + uint8_t *kpart_data = NULL; + uint64_t kpart_size = 0; + uint8_t *vmlinuz_buf = NULL; + uint64_t vmlinuz_size = 0; + uint8_t *t_config_data; + uint64_t t_config_size; + uint8_t *t_bootloader_data; + uint64_t t_bootloader_size; + VbKernelPreambleHeader *preamble = NULL; + uint8_t *kblob_data = NULL; + uint64_t kblob_size = 0; + uint8_t *vblock_data = NULL; + uint64_t vblock_size = 0; while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && !parse_error) { @@ -764,7 +284,6 @@ static int do_vbutil_kernel(int argc, char *argv[]) break; case OPT_KLOADADDR: - address_str = optarg; kernel_body_load_address = strtoul(optarg, &e, 0); if (!*optarg || (e && *e)) { fprintf(stderr, "Invalid --kloadaddr\n"); @@ -835,13 +354,11 @@ static int do_vbutil_kernel(int argc, char *argv[]) switch (mode) { case OPT_MODE_PACK: - /* Required */ - if (!keyblock_file) Fatal("Missing required keyblock file.\n"); - g_keyblock = (VbKeyBlockHeader *) ReadFile(keyblock_file, 0); - if (!g_keyblock) + t_keyblock = (VbKeyBlockHeader *)ReadFile(keyblock_file, 0); + if (!t_keyblock) Fatal("Error reading key block.\n"); if (!signprivkey_file) @@ -851,38 +368,66 @@ static int do_vbutil_kernel(int argc, char *argv[]) if (!signpriv_key) Fatal("Error reading signing key.\n"); - /* Optional */ - - if (config_file) { - Debug("Reading %s\n", config_file); - g_config_data = - sReadConfigFile(config_file, &g_config_size); - if (!g_config_data) - Fatal("Error reading config file.\n"); - } - - if (vmlinuz_file) - if (!ImportVmlinuzFile - (vmlinuz_file, arch, kernel_body_load_address)) - Fatal("Error reading kernel file.\n"); - - if (bootloader_file) { - Debug("Reading %s\n", bootloader_file); - g_bootloader_data = - ReadFile(bootloader_file, &g_bootloader_size); - if (!g_bootloader_data) - Fatal("Error reading bootloader file.\n"); - Debug(" bootloader file size=0x%" PRIx64 "\n", - g_bootloader_size); - } - - /* Do it */ - - kernel_blob = CreateKernBlob(kernel_body_load_address, arch, - &kernel_size); - - return Pack(filename, kernel_blob, kernel_size, - version, kernel_body_load_address, signpriv_key); + if (!config_file) + Fatal("Missing required config file.\n"); + + Debug("Reading %s\n", config_file); + t_config_data = + ReadConfigFile(config_file, &t_config_size); + if (!t_config_data) + Fatal("Error reading config file.\n"); + + if (!bootloader_file) + Fatal("Missing required bootloader file.\n"); + + Debug("Reading %s\n", bootloader_file); + t_bootloader_data = ReadFile(bootloader_file, + &t_bootloader_size); + if (!t_bootloader_data) + Fatal("Error reading bootloader file.\n"); + Debug(" bootloader file size=0x%" PRIx64 "\n", + t_bootloader_size); + + if (!vmlinuz_file) + Fatal("Missing required vmlinuz file.\n"); + Debug("Reading %s\n", vmlinuz_file); + vmlinuz_buf = ReadFile(vmlinuz_file, &vmlinuz_size); + if (!vmlinuz_buf) + Fatal("Error reading vmlinuz file.\n"); + Debug(" vmlinuz file size=0x%" PRIx64 "\n", + vmlinuz_size); + if (!vmlinuz_size) + Fatal("Empty vmlinuz file\n"); + + kblob_data = CreateKernelBlob( + vmlinuz_buf, vmlinuz_size, + arch, kernel_body_load_address, + t_config_data, t_config_size, + t_bootloader_data, t_bootloader_size, + &kblob_size); + if (!kblob_data) + Fatal("Unable to create kernel blob\n"); + + Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size); + + vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad, + version, kernel_body_load_address, + t_keyblock, signpriv_key, + &vblock_size); + if (!vblock_data) + Fatal("Unable to sign kernel blob\n"); + + Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size); + + if (opt_vblockonly) + rv = WriteSomeParts(filename, + vblock_data, vblock_size, + NULL, 0); + else + rv = WriteSomeParts(filename, + vblock_data, vblock_size, + kblob_data, kblob_size); + return rv; case OPT_MODE_REPACK: @@ -898,52 +443,56 @@ static int do_vbutil_kernel(int argc, char *argv[]) if (!oldfile) Fatal("Missing previously packed blob.\n"); - /* Load the old blob */ - - kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size); - if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0)) - Fatal("The oldblob doesn't verify\n"); - - /* Take it apart */ - - UnpackKernelBlob(kernel_blob, kernel_size); - free(kernel_blob); + /* Load the kernel partition */ + kpart_data = ReadOldKPartFromFileOrDie(oldfile, &kpart_size); - /* Load optional params */ + kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad, + &keyblock, &preamble, &kblob_size); - if (!version_str) - version = g_preamble->kernel_version; + if (!kblob_data) + Fatal("Unable to unpack kernel partition\n"); - if (!address_str) - kernel_body_load_address = - g_preamble->body_load_address; + kernel_body_load_address = preamble->body_load_address; + /* Update the config if asked */ if (config_file) { - if (g_config_data) - free(g_config_data); Debug("Reading %s\n", config_file); - g_config_data = - sReadConfigFile(config_file, &g_config_size); - if (!g_config_data) + t_config_data = + ReadConfigFile(config_file, &t_config_size); + if (!t_config_data) Fatal("Error reading config file.\n"); + if (0 != UpdateKernelBlobConfig( + kblob_data, kblob_size, + t_config_data, t_config_size)) + Fatal("Unable to update config\n"); } + if (!version_str) + version = preamble->kernel_version; + if (keyblock_file) { - if (g_keyblock) - free(g_keyblock); - g_keyblock = - (VbKeyBlockHeader *) ReadFile(keyblock_file, 0); - if (!g_keyblock) + t_keyblock = + (VbKeyBlockHeader *)ReadFile(keyblock_file, 0); + if (!t_keyblock) Fatal("Error reading key block.\n"); } - /* Put it back together */ - - kernel_blob = CreateKernBlob(kernel_body_load_address, arch, - &kernel_size); - - return Pack(filename, kernel_blob, kernel_size, - version, kernel_body_load_address, signpriv_key); + vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad, + version, kernel_body_load_address, + t_keyblock ? t_keyblock : keyblock, + signpriv_key, &vblock_size); + if (!vblock_data) + Fatal("Unable to sign kernel blob\n"); + + if (opt_vblockonly) + rv = WriteSomeParts(filename, + vblock_data, vblock_size, + NULL, 0); + else + rv = WriteSomeParts(filename, + vblock_data, vblock_size, + kblob_data, kblob_size); + return rv; case OPT_MODE_VERIFY: @@ -957,10 +506,18 @@ static int do_vbutil_kernel(int argc, char *argv[]) /* Do it */ - kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size); + /* Load the kernel partition */ + kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size); + + kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad, + 0, 0, &kblob_size); + if (!kblob_data) + Fatal("Unable to unpack kernel partition\n"); + + rv = VerifyKernelBlob(kblob_data, kblob_size, + signpub_key, keyblock_file, min_version); - return Verify(kernel_blob, kernel_size, signpub_key, - keyblock_file, min_version); + return rv; } fprintf(stderr, @@ -969,6 +526,6 @@ static int do_vbutil_kernel(int argc, char *argv[]) return 1; } -DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel, - "Creates, signs, and verifies the kernel blob", +DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel2, + "Creates, signs, and verifies the kernel partition", print_help); diff --git a/futility/cmd_vbutil_kernel0.c b/futility/cmd_vbutil_kernel0.c new file mode 100644 index 00000000..78f3d506 --- /dev/null +++ b/futility/cmd_vbutil_kernel0.c @@ -0,0 +1,974 @@ +/* Copyright 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Verified boot kernel utility + */ + +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <inttypes.h> /* For PRIu64 */ +#include <sys/ioctl.h> +#include <linux/fs.h> /* For BLKGETSIZE64 */ +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "cryptolib.h" +#include "futility.h" +#include "host_common.h" +#include "kernel_blob.h" +#include "util_misc.h" +#include "vboot_common.h" + +/* Global opts */ +static int opt_verbose; +static int opt_vblockonly; +static uint64_t opt_pad = 65536; + +/* Command line options */ +enum { + OPT_MODE_PACK = 1000, + OPT_MODE_REPACK, + OPT_MODE_VERIFY, + OPT_ARCH, + OPT_OLDBLOB, + OPT_KLOADADDR, + OPT_KEYBLOCK, + OPT_SIGNPUBKEY, + OPT_SIGNPRIVATE, + OPT_VERSION, + OPT_VMLINUZ, + OPT_BOOTLOADER, + OPT_CONFIG, + OPT_VBLOCKONLY, + OPT_PAD, + OPT_VERBOSE, + OPT_MINVERSION, +}; + +static const struct option long_opts[] = { + {"pack", 1, 0, OPT_MODE_PACK}, + {"repack", 1, 0, OPT_MODE_REPACK}, + {"verify", 1, 0, OPT_MODE_VERIFY}, + {"arch", 1, 0, OPT_ARCH}, + {"oldblob", 1, 0, OPT_OLDBLOB}, + {"kloadaddr", 1, 0, OPT_KLOADADDR}, + {"keyblock", 1, 0, OPT_KEYBLOCK}, + {"signpubkey", 1, 0, OPT_SIGNPUBKEY}, + {"signprivate", 1, 0, OPT_SIGNPRIVATE}, + {"version", 1, 0, OPT_VERSION}, + {"minversion", 1, 0, OPT_MINVERSION}, + {"vmlinuz", 1, 0, OPT_VMLINUZ}, + {"bootloader", 1, 0, OPT_BOOTLOADER}, + {"config", 1, 0, OPT_CONFIG}, + {"vblockonly", 0, 0, OPT_VBLOCKONLY}, + {"pad", 1, 0, OPT_PAD}, + {"verbose", 0, &opt_verbose, 1}, + {"debug", 0, &debugging_enabled, 1}, + {NULL, 0, 0, 0} +}; + + + +static const char usage[] = + "\n" + "Usage: " MYNAME " %s --pack <file> [PARAMETERS]\n" + "\n" + " Required parameters:\n" + " --keyblock <file> Key block in .keyblock format\n" + " --signprivate <file> Private key to sign kernel data,\n" + " in .vbprivk format\n" + " --version <number> Kernel version\n" + " --vmlinuz <file> Linux kernel bzImage file\n" + " --bootloader <file> Bootloader stub\n" + " --config <file> Command line file\n" + " --arch <arch> Cpu architecture (default x86)\n" + "\n" + " Optional:\n" + " --kloadaddr <address> Assign kernel body load address\n" + " --pad <number> Verification padding size in bytes\n" + " --vblockonly Emit just the verification blob\n" + "\nOR\n\n" + "Usage: " MYNAME " %s --repack <file> [PARAMETERS]\n" + "\n" + " Required parameters:\n" + " --signprivate <file> Private key to sign kernel data,\n" + " in .vbprivk format\n" + " --oldblob <file> Previously packed kernel blob\n" + " (including verfication blob)\n" + "\n" + " Optional:\n" + " --keyblock <file> Key block in .keyblock format\n" + " --config <file> New command line file\n" + " --version <number> Kernel version\n" + " --kloadaddr <address> Assign kernel body load address\n" + " --pad <number> Verification blob size in bytes\n" + " --vblockonly Emit just the verification blob\n" + "\nOR\n\n" + "Usage: " MYNAME " %s --verify <file> [PARAMETERS]\n" + "\n" + " Optional:\n" + " --signpubkey <file>" + " Public key to verify kernel keyblock,\n" + " in .vbpubk format\n" + " --verbose Print a more detailed report\n" + " --keyblock <file> Outputs the verified key block,\n" + " in .keyblock format\n" + " --pad <number> Verification padding size in bytes\n" + " --minversion <number> Minimum combined kernel key version\n" + " and kernel version\n" + "\n"; + + +/* Print help and return error */ +static void print_help(const char *progname) +{ + printf(usage, progname, progname, progname); +} + +static void Fatal(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + fprintf(stderr, "ERROR: "); + vfprintf(stderr, format, ap); + va_end(ap); + exit(1); +} + +/* Return an explanation when fread() fails. */ +static const char *error_fread(FILE *fp) +{ + const char *retval = "beats me why"; + if (feof(fp)) + retval = "EOF"; + else if (ferror(fp)) + retval = strerror(errno); + clearerr(fp); + return retval; +} + +/* Return the smallest integral multiple of [alignment] that is equal + * to or greater than [val]. Used to determine the number of + * pages/sectors/blocks/whatever needed to contain [val] + * items/bytes/etc. */ +static uint64_t roundup(uint64_t val, uint64_t alignment) +{ + uint64_t rem = val % alignment; + if (rem) + return val + (alignment - rem); + return val; +} + +/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we + * don't find one, we'll use the whole thing. */ +static unsigned int find_cmdline_start(char *input, unsigned int max_len) +{ + int start = 0; + int i; + for (i = 0; i < max_len - 1 && input[i]; i++) { + if ('-' == input[i] && '-' == input[i + 1]) { + if ((i == 0 || ' ' == input[i - 1]) && + (i + 2 >= max_len || ' ' == input[i + 2])) { + /* found "--" with nothing before or after it */ + start = i + 2; /* hope for a trailing '\0' */ + break; + } + } + } + while (' ' == input[start]) /* skip leading spaces */ + start++; + + return start; +} + +/****************************************************************************/ +/* Here are globals containing all the bits & pieces I'm working on. */ + +/* The individual parts that go into the kernel blob */ +static uint8_t *g_kernel_data; +static uint64_t g_kernel_size; +static uint8_t *g_param_data; +static uint64_t g_param_size; +static uint8_t *g_config_data; +static uint64_t g_config_size; +static uint8_t *g_bootloader_data; +static uint64_t g_bootloader_size; +static uint64_t g_bootloader_address; + +/* The individual parts of the verification blob (including the data that + * immediately follows the headers) */ +static VbKeyBlockHeader *g_keyblock; +static VbKernelPreambleHeader *g_preamble; + +/****************************************************************************/ + +/* + * Read the kernel command line from a file. Get rid of \n characters along + * the way and verify that the line fits into a 4K buffer. + * + * Return the buffer contaning the line on success (and set the line length + * using the passed in parameter), or NULL in case something goes wrong. + */ +static uint8_t *sReadConfigFile(const char *config_file, uint64_t *config_size) +{ + uint8_t *config_buf; + int ii; + + config_buf = ReadFile(config_file, config_size); + Debug(" config file size=0x%" PRIx64 "\n", *config_size); + if (CROS_CONFIG_SIZE <= *config_size) { /* room for trailing '\0' */ + VbExError("Config file %s is too large (>= %d bytes)\n", + config_file, CROS_CONFIG_SIZE); + return NULL; + } + + /* Replace newlines with spaces */ + for (ii = 0; ii < *config_size; ii++) + if ('\n' == config_buf[ii]) + config_buf[ii] = ' '; + + return config_buf; +} + +/* Offset of kernel command line string from start of packed kernel blob */ +static uint64_t CmdLineOffset(VbKernelPreambleHeader *preamble) +{ + return preamble->bootloader_address - preamble->body_load_address - + CROS_CONFIG_SIZE - CROS_PARAMS_SIZE; +} + +/* This initializes g_vmlinuz and g_param from a standard vmlinuz file. + * It returns 0 on error. */ +static int ImportVmlinuzFile(const char *vmlinuz_file, enum arch_t arch, + uint64_t kernel_body_load_address) +{ + uint8_t *kernel_buf; + uint64_t kernel_size; + uint64_t kernel32_start = 0; + uint64_t kernel32_size = 0; + struct linux_kernel_params *params = NULL, *lh = NULL; + + /* Read the kernel */ + Debug("Reading %s\n", vmlinuz_file); + kernel_buf = ReadFile(vmlinuz_file, &kernel_size); + if (!kernel_buf) + return 0; + Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size); + if (!kernel_size) + Fatal("Empty kernel file\n"); + + /* Go ahead and allocate the param region anyway. I don't think we need + * it for non-x86, but let's keep it for now. */ + g_param_size = CROS_PARAMS_SIZE; + g_param_data = VbExMalloc(g_param_size); + Memset(g_param_data, 0, g_param_size); + + /* Unless we're handling x86, the kernel is the kernel; we're done. */ + if (arch != ARCH_X86) { + g_kernel_data = kernel_buf; + g_kernel_size = kernel_size; + return 1; + } + + /* The first part of the x86 vmlinuz is a header, followed by a + * real-mode boot stub. We only want the 32-bit part. */ + lh = (struct linux_kernel_params *)kernel_buf; + kernel32_start = (lh->setup_sects + 1) << 9; + if (kernel32_start >= kernel_size) + Fatal("Malformed kernel\n"); + kernel32_size = kernel_size - kernel32_start; + + Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start); + Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size); + + /* Keep just the 32-bit kernel. */ + if (kernel32_size) { + g_kernel_size = kernel32_size; + g_kernel_data = VbExMalloc(g_kernel_size); + Memcpy(g_kernel_data, kernel_buf + kernel32_start, + kernel32_size); + } + + /* 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); + Memcpy(&(params->setup_sects), &(lh->setup_sects), + offsetof(struct linux_kernel_params, e820_entries) + - offsetof(struct linux_kernel_params, setup_sects)); + params->boot_flag = 0; + params->ramdisk_image = 0; /* we don't support initrd */ + params->ramdisk_size = 0; + params->type_of_loader = 0xff; + /* We need to point to the kernel commandline arg. On disk, it will come + * right after the 32-bit part of the kernel. */ + params->cmd_line_ptr = kernel_body_load_address + + roundup(kernel32_size, CROS_ALIGN) + + find_cmdline_start((char *)g_config_data, g_config_size); + Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr); + Debug(" version=0x%x\n", params->version); + Debug(" kernel_alignment=0x%x\n", params->kernel_alignment); + Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel); + /* A fake e820 memory map with 2 entries */ + params->n_e820_entry = 2; + params->e820_entries[0].start_addr = 0x00000000; + params->e820_entries[0].segment_size = 0x00001000; + params->e820_entries[0].segment_type = E820_TYPE_RAM; + params->e820_entries[1].start_addr = 0xfffff000; + params->e820_entries[1].segment_size = 0x00001000; + params->e820_entries[1].segment_type = E820_TYPE_RESERVED; + + /* done */ + free(kernel_buf); + return 1; +} + +/* This returns just the kernel blob, with the verification blob separated + * and copied to new memory in g_keyblock and g_preamble. */ +static uint8_t *ReadOldBlobFromFileOrDie(const char *filename, + uint64_t *size_ptr) +{ + FILE *fp = NULL; + struct stat statbuf; + VbKeyBlockHeader *key_block; + VbKernelPreambleHeader *preamble; + uint64_t now = 0; + uint8_t *buf; + uint8_t *kernel_blob_data; + uint64_t kernel_blob_size; + uint64_t file_size = 0; + + if (0 != stat(filename, &statbuf)) + Fatal("Unable to stat %s: %s\n", filename, strerror(errno)); + + if (S_ISBLK(statbuf.st_mode)) { + int fd = open(filename, O_RDONLY); + if (fd >= 0) { + ioctl(fd, BLKGETSIZE64, &file_size); + close(fd); + } + } else { + file_size = statbuf.st_size; + } + Debug("%s size is 0x%" PRIx64 "\n", filename, file_size); + if (file_size < opt_pad) + Fatal("%s is too small to be a valid kernel blob\n"); + + Debug("Reading %s\n", filename); + fp = fopen(filename, "rb"); + if (!fp) + Fatal("Unable to open file %s: %s\n", filename, + strerror(errno)); + + buf = VbExMalloc(opt_pad); + if (1 != fread(buf, opt_pad, 1, fp)) + Fatal("Unable to read header from %s: %s\n", filename, + error_fread(fp)); + + /* Sanity-check the key_block */ + key_block = (VbKeyBlockHeader *) buf; + Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size); + now += key_block->key_block_size; + if (now > file_size) + Fatal("key_block_size advances past the end of the blob\n"); + if (now > opt_pad) + Fatal("key_block_size advances past %" PRIu64 " byte padding\n", + opt_pad); + /* LGTM */ + g_keyblock = (VbKeyBlockHeader *) VbExMalloc(key_block->key_block_size); + Memcpy(g_keyblock, key_block, key_block->key_block_size); + + /* And the preamble */ + preamble = (VbKernelPreambleHeader *) (buf + now); + Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); + now += preamble->preamble_size; + if (now > file_size) + Fatal("preamble_size advances past the end of the blob\n"); + if (now > opt_pad) + Fatal("preamble_size advances past %" PRIu64 " byte padding\n", + opt_pad); + /* LGTM */ + Debug(" kernel_version = %d\n", preamble->kernel_version); + Debug(" bootloader_address = 0x%" PRIx64 "\n", + preamble->bootloader_address); + Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size); + Debug(" kern_blob_size = 0x%" PRIx64 "\n", + preamble->body_signature.data_size); + g_preamble = + (VbKernelPreambleHeader *) VbExMalloc(preamble->preamble_size); + Memcpy(g_preamble, preamble, preamble->preamble_size); + + /* Now for the kernel blob */ + Debug("kernel blob is at offset 0x%" PRIx64 "\n", now); + if (0 != fseek(fp, now, SEEK_SET)) + Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, + filename, strerror(errno)); + + /* Sanity check */ + kernel_blob_size = file_size - now; + if (!kernel_blob_size) + Fatal("No kernel blob found\n"); + if (kernel_blob_size < preamble->body_signature.data_size) + fprintf(stderr, + "Warning: kernel file only has 0x%" PRIx64 " bytes\n", + kernel_blob_size); + kernel_blob_data = VbExMalloc(kernel_blob_size); + + /* Read it in */ + if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp)) + Fatal("Unable to read kernel blob from %s: %s\n", filename, + error_fread(fp)); + + /* Done */ + VbExFree(buf); + + if (size_ptr) + *size_ptr = kernel_blob_size; + + return kernel_blob_data; +} + +/* Split a kernel blob into separate g_kernel, g_param, g_config, and + * g_bootloader parts. */ +static void UnpackKernelBlob(uint8_t *kernel_blob_data, + uint64_t kernel_blob_size) +{ + + uint64_t k_blob_size = g_preamble->body_signature.data_size; + uint64_t k_blob_ofs = 0; + uint64_t b_size = g_preamble->bootloader_size; + uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address - + g_preamble->body_load_address; + uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE; + uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE; + + Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size); + Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs); + Debug("b_size = 0x%" PRIx64 "\n", b_size); + Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs); + Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs); + Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs); + + g_kernel_size = c_ofs; + g_kernel_data = VbExMalloc(g_kernel_size); + Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size); + + g_param_size = CROS_PARAMS_SIZE; + g_param_data = VbExMalloc(g_param_size); + Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size); + + g_config_size = CROS_CONFIG_SIZE; + g_config_data = VbExMalloc(g_config_size); + Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size); + + g_bootloader_size = b_size; + g_bootloader_data = VbExMalloc(g_bootloader_size); + Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size); +} + +/****************************************************************************/ + +static uint8_t *CreateKernBlob(uint64_t kernel_body_load_address, + enum arch_t arch, uint64_t *size_ptr) +{ + uint8_t *kern_blob; + uint64_t kern_blob_size; + uint64_t now; + uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN); + + /* Put the kernel blob together */ + kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) + + CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size; + Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size); + kern_blob = VbExMalloc(kern_blob_size); + Memset(kern_blob, 0, kern_blob_size); + now = 0; + + Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now); + + Memcpy(kern_blob + now, g_kernel_data, g_kernel_size); + now += roundup(g_kernel_size, CROS_ALIGN); + + Debug("config goes at kern_blob+0x%" PRIx64 "\n", now); + if (g_config_size) + Memcpy(kern_blob + now, g_config_data, g_config_size); + now += CROS_CONFIG_SIZE; + + Debug("params goes at kern_blob+0x%" PRIx64 "\n", now); + if (g_param_size) + Memcpy(kern_blob + now, g_param_data, g_param_size); + now += CROS_PARAMS_SIZE; + + Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now); + g_bootloader_address = kernel_body_load_address + now; + Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address); + Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size); + if (bootloader_size) + Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size); + now += bootloader_size; + Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now); + + /* Done */ + if (size_ptr) + *size_ptr = kern_blob_size; + + return kern_blob; +} + +static int Pack(const char *outfile, + uint8_t *kernel_blob, + uint64_t kernel_size, + int version, + uint64_t kernel_body_load_address, + VbPrivateKey *signpriv_key) +{ + VbSignature *body_sig; + FILE *f; + uint64_t i; + uint64_t written = 0; + + /* Sign the kernel data */ + body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key); + if (!body_sig) + Fatal("Error calculating body signature\n"); + + /* Create preamble */ + g_preamble = CreateKernelPreamble(version, + kernel_body_load_address, + g_bootloader_address, + roundup(g_bootloader_size, + CROS_ALIGN), body_sig, + opt_pad - g_keyblock->key_block_size, + signpriv_key); + if (!g_preamble) { + VbExError("Error creating preamble.\n"); + return 1; + } + /* Write the output file */ + Debug("writing %s...\n", outfile); + f = fopen(outfile, "wb"); + if (!f) { + VbExError("Can't open output file %s\n", outfile); + return 1; + } + Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size); + Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size); + i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) || + (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f))); + if (i) { + VbExError("Can't write output file %s\n", outfile); + fclose(f); + unlink(outfile); + return 1; + } + written += g_keyblock->key_block_size; + written += g_preamble->preamble_size; + + if (!opt_vblockonly) { + Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size); + i = (1 != fwrite(kernel_blob, kernel_size, 1, f)); + if (i) { + fclose(f); + unlink(outfile); + Fatal("Can't write output file %s\n", outfile); + } + written += kernel_size; + } + Debug("0x%" PRIx64 " bytes total\n", written); + fclose(f); + + /* Success */ + return 0; +} + +static int Verify(uint8_t *kernel_blob, + uint64_t kernel_size, + VbPublicKey *signpub_key, + const char *keyblock_outfile, + uint64_t min_version) +{ + VbPublicKey *data_key; + RSAPublicKey *rsa; + + if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size, + signpub_key, (0 == signpub_key))) + Fatal("Error verifying key block.\n"); + + printf("Key block:\n"); + data_key = &g_keyblock->data_key; + if (opt_verbose) + printf(" Signature: %s\n", + signpub_key ? "valid" : "ignored"); + printf(" Size: 0x%" PRIx64 "\n", + g_keyblock->key_block_size); + printf(" Flags: %" PRIu64 " ", + g_keyblock->key_block_flags); + if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) + printf(" !DEV"); + if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) + printf(" DEV"); + if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) + printf(" !REC"); + if (g_keyblock->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(" Data key sha1sum: "); + PrintPubKeySha1Sum(data_key); + printf("\n"); + + if (keyblock_outfile) { + FILE *f = NULL; + f = fopen(keyblock_outfile, "wb"); + if (!f) + Fatal("Can't open key block file %s\n", + keyblock_outfile); + if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) + Fatal("Can't write key block file %s\n", + keyblock_outfile); + fclose(f); + } + + if (data_key->key_version < (min_version >> 16)) + Fatal("Data key version %" PRIu64 + " is lower than minimum %" PRIu64 ".\n", + data_key->key_version, (min_version >> 16)); + + rsa = PublicKeyToRSA(data_key); + if (!rsa) + Fatal("Error parsing data key.\n"); + + /* Verify preamble */ + if (0 != + VerifyKernelPreamble(g_preamble, g_preamble->preamble_size, rsa)) + Fatal("Error verifying preamble.\n"); + + printf("Preamble:\n"); + printf(" Size: 0x%" PRIx64 "\n", + g_preamble->preamble_size); + printf(" Header version: %" PRIu32 ".%" PRIu32 "\n", + g_preamble->header_version_major, + g_preamble->header_version_minor); + printf(" Kernel version: %" PRIu64 "\n", + g_preamble->kernel_version); + printf(" Body load address: 0x%" PRIx64 "\n", + g_preamble->body_load_address); + printf(" Body size: 0x%" PRIx64 "\n", + g_preamble->body_signature.data_size); + printf(" Bootloader address: 0x%" PRIx64 "\n", + g_preamble->bootloader_address); + printf(" Bootloader size: 0x%" PRIx64 "\n", + g_preamble->bootloader_size); + + if (g_preamble->kernel_version < (min_version & 0xFFFF)) + Fatal("Kernel version %" PRIu64 " is lower than minimum %" + PRIu64 ".\n", g_preamble->kernel_version, + (min_version & 0xFFFF)); + + /* Verify body */ + if (0 != VerifyData(kernel_blob, kernel_size, + &g_preamble->body_signature, rsa)) + Fatal("Error verifying kernel body.\n"); + printf("Body verification succeeded.\n"); + + if (opt_verbose) + printf("Config:\n%s\n", + kernel_blob + CmdLineOffset(g_preamble)); + + return 0; +} + +/****************************************************************************/ + +static int do_vbutil_kernel(int argc, char *argv[]) +{ + char *filename = NULL; + char *oldfile = NULL; + char *keyblock_file = NULL; + char *signpubkey_file = NULL; + char *signprivkey_file = NULL; + char *version_str = NULL; + int version = -1; + char *vmlinuz_file = NULL; + char *bootloader_file = NULL; + char *config_file = NULL; + enum arch_t arch = ARCH_X86; + char *address_str = NULL; + 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; + VbPrivateKey *signpriv_key = NULL; + VbPublicKey *signpub_key = NULL; + uint8_t *kernel_blob = NULL; + uint64_t kernel_size = 0; + + while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && + !parse_error) { + switch (i) { + default: + case '?': + /* Unhandled option */ + parse_error = 1; + break; + + case 0: + /* silently handled option */ + break; + + case OPT_MODE_PACK: + case OPT_MODE_REPACK: + case OPT_MODE_VERIFY: + if (mode && (mode != i)) { + fprintf(stderr, + "Only one mode can be specified\n"); + parse_error = 1; + break; + } + mode = i; + filename = optarg; + break; + + case OPT_ARCH: + /* check the first 3 characters to also detect x86_64 */ + if ((!strncasecmp(optarg, "x86", 3)) || + (!strcasecmp(optarg, "amd64"))) + arch = ARCH_X86; + else if ((!strcasecmp(optarg, "arm")) || + (!strcasecmp(optarg, "aarch64"))) + arch = ARCH_ARM; + else if (!strcasecmp(optarg, "mips")) + arch = ARCH_MIPS; + else { + fprintf(stderr, + "Unknown architecture string: %s\n", + optarg); + parse_error = 1; + } + break; + + case OPT_OLDBLOB: + oldfile = optarg; + break; + + case OPT_KLOADADDR: + address_str = optarg; + kernel_body_load_address = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --kloadaddr\n"); + parse_error = 1; + } + break; + + case OPT_KEYBLOCK: + keyblock_file = optarg; + break; + + case OPT_SIGNPUBKEY: + signpubkey_file = optarg; + break; + + case OPT_SIGNPRIVATE: + signprivkey_file = optarg; + break; + + case OPT_VMLINUZ: + vmlinuz_file = optarg; + break; + + case OPT_BOOTLOADER: + bootloader_file = optarg; + break; + + case OPT_CONFIG: + config_file = optarg; + break; + + case OPT_VBLOCKONLY: + opt_vblockonly = 1; + break; + + case OPT_VERSION: + version_str = optarg; + version = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --version\n"); + parse_error = 1; + } + break; + + case OPT_MINVERSION: + min_version = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --minversion\n"); + parse_error = 1; + } + break; + + case OPT_PAD: + opt_pad = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --pad\n"); + parse_error = 1; + } + break; + } + } + + if (parse_error) { + print_help(argv[0]); + return 1; + } + + switch (mode) { + case OPT_MODE_PACK: + + /* Required */ + + if (!keyblock_file) + Fatal("Missing required keyblock file.\n"); + + g_keyblock = (VbKeyBlockHeader *) ReadFile(keyblock_file, 0); + if (!g_keyblock) + Fatal("Error reading key block.\n"); + + if (!signprivkey_file) + Fatal("Missing required signprivate file.\n"); + + signpriv_key = PrivateKeyRead(signprivkey_file); + if (!signpriv_key) + Fatal("Error reading signing key.\n"); + + /* Optional */ + + if (config_file) { + Debug("Reading %s\n", config_file); + g_config_data = + sReadConfigFile(config_file, &g_config_size); + if (!g_config_data) + Fatal("Error reading config file.\n"); + } + + if (vmlinuz_file) + if (!ImportVmlinuzFile + (vmlinuz_file, arch, kernel_body_load_address)) + Fatal("Error reading kernel file.\n"); + + if (bootloader_file) { + Debug("Reading %s\n", bootloader_file); + g_bootloader_data = + ReadFile(bootloader_file, &g_bootloader_size); + if (!g_bootloader_data) + Fatal("Error reading bootloader file.\n"); + Debug(" bootloader file size=0x%" PRIx64 "\n", + g_bootloader_size); + } + + /* Do it */ + + kernel_blob = CreateKernBlob(kernel_body_load_address, arch, + &kernel_size); + + return Pack(filename, kernel_blob, kernel_size, + version, kernel_body_load_address, signpriv_key); + + case OPT_MODE_REPACK: + + /* Required */ + + if (!signprivkey_file) + Fatal("Missing required signprivate file.\n"); + + signpriv_key = PrivateKeyRead(signprivkey_file); + if (!signpriv_key) + Fatal("Error reading signing key.\n"); + + if (!oldfile) + Fatal("Missing previously packed blob.\n"); + + /* Load the old blob */ + + kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size); + if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0)) + Fatal("The oldblob doesn't verify\n"); + + /* Take it apart */ + + UnpackKernelBlob(kernel_blob, kernel_size); + free(kernel_blob); + + /* Load optional params */ + + if (!version_str) + version = g_preamble->kernel_version; + + if (!address_str) + kernel_body_load_address = + g_preamble->body_load_address; + + if (config_file) { + if (g_config_data) + free(g_config_data); + Debug("Reading %s\n", config_file); + g_config_data = + sReadConfigFile(config_file, &g_config_size); + if (!g_config_data) + Fatal("Error reading config file.\n"); + } + + if (keyblock_file) { + if (g_keyblock) + free(g_keyblock); + g_keyblock = + (VbKeyBlockHeader *) ReadFile(keyblock_file, 0); + if (!g_keyblock) + Fatal("Error reading key block.\n"); + } + + /* Put it back together */ + + kernel_blob = CreateKernBlob(kernel_body_load_address, arch, + &kernel_size); + + return Pack(filename, kernel_blob, kernel_size, + version, kernel_body_load_address, signpriv_key); + + case OPT_MODE_VERIFY: + + /* Optional */ + + if (signpubkey_file) { + signpub_key = PublicKeyRead(signpubkey_file); + if (!signpub_key) + Fatal("Error reading public key.\n"); + } + + /* Do it */ + + kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size); + + return Verify(kernel_blob, kernel_size, signpub_key, + keyblock_file, min_version); + } + + fprintf(stderr, + "You must specify a mode: --pack, --repack or --verify\n"); + print_help(argv[0]); + return 1; +} + +DECLARE_FUTIL_COMMAND(vbutil_kernel0, do_vbutil_kernel, + "Creates, signs, and verifies the kernel blob", + print_help); diff --git a/futility/vb1_helper.c b/futility/vb1_helper.c new file mode 100644 index 00000000..d0dbefcd --- /dev/null +++ b/futility/vb1_helper.c @@ -0,0 +1,616 @@ +/* + * Copyright 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <errno.h> +#include <inttypes.h> /* For PRIu64 */ +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "futility.h" +#include "host_common.h" +#include "kernel_blob.h" +#include "util_misc.h" +#include "vb1_helper.h" + +/****************************************************************************/ +/* 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 partition = kernel vblock + kernel blob + * + * The VbKernelPreambleHeader.preamble_size includes the padding. + */ + +/* The keyblock, preamble, and kernel blob are kept in separate places. */ +static VbKeyBlockHeader *g_keyblock; +static VbKernelPreambleHeader *g_preamble; +static uint8_t *g_kernel_blob_data; +static uint64_t g_kernel_blob_size; + +/* These refer to individual parts within the kernel blob. */ +static uint8_t *g_kernel_data; +static uint64_t g_kernel_size; +static uint8_t *g_config_data; +static uint64_t g_config_size; +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 uint64_t g_ondisk_bootloader_addr; + + +/* + * Read the kernel command line from a file. Get rid of \n characters along + * the way and verify that the line fits into a 4K buffer. + * + * Return the buffer contaning the line on success (and set the line length + * using the passed in parameter), or NULL in case something goes wrong. + */ +uint8_t *ReadConfigFile(const char *config_file, uint64_t *config_size) +{ + uint8_t *config_buf; + int i; + + config_buf = ReadFile(config_file, config_size); + if (!config_buf) + return NULL; + Debug(" config file size=0x%" PRIx64 "\n", *config_size); + if (CROS_CONFIG_SIZE <= *config_size) { /* room for trailing '\0' */ + fprintf(stderr, "Config file %s is too large (>= %d bytes)\n", + config_file, CROS_CONFIG_SIZE); + return NULL; + } + + /* Replace newlines with spaces */ + for (i = 0; i < *config_size; i++) + if ('\n' == config_buf[i]) + config_buf[i] = ' '; + + return config_buf; +} + +/****************************************************************************/ + +/* Return the smallest integral multiple of [alignment] that is equal + * to or greater than [val]. Used to determine the number of + * pages/sectors/blocks/whatever needed to contain [val] + * items/bytes/etc. */ +static uint64_t roundup(uint64_t val, uint64_t alignment) +{ + uint64_t rem = val % alignment; + if (rem) + return val + (alignment - rem); + return val; +} + +/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we + * don't find one, we'll use the whole thing. */ +static unsigned int find_cmdline_start(uint8_t *buf_ptr, unsigned int max_len) +{ + char *input = (char *)buf_ptr; + int start = 0; + int i; + for (i = 0; i < max_len - 1 && input[i]; i++) { + if ('-' == input[i] && '-' == input[i + 1]) { + if ((i == 0 || ' ' == input[i - 1]) && + (i + 2 >= max_len || ' ' == input[i + 2])) { + /* found "--" with nothing before or after it */ + start = i + 2; /* hope for a trailing '\0' */ + break; + } + } + } + while (' ' == input[start]) /* skip leading spaces */ + start++; + + return start; +} + +/* Offset of kernel command line string from the start of the kernel blob */ +uint64_t KernelCmdLineOffset(VbKernelPreambleHeader *preamble) +{ + return preamble->bootloader_address - preamble->body_load_address - + CROS_CONFIG_SIZE - CROS_PARAMS_SIZE; +} + +/* Returns the size of the 32-bit kernel, or negative on error. */ +static int KernelSize(uint8_t *kernel_buf, uint64_t kernel_size, + enum arch_t arch) +{ + uint64_t kernel32_start = 0; + struct linux_kernel_params *lh; + + /* Except for x86, the kernel is the kernel. */ + if (arch != ARCH_X86) + return kernel_size; + + /* The first part of the x86 vmlinuz is a header, followed by + * a real-mode boot stub. We only want the 32-bit part. */ + lh = (struct linux_kernel_params *)kernel_buf; + kernel32_start = (lh->setup_sects + 1) << 9; + if (kernel32_start >= kernel_size) { + fprintf(stderr, "Malformed kernel\n"); + return -1; + } + return kernel_size - kernel32_start; +} + +/* This extracts g_kernel_* and g_param_* from a standard vmlinuz file. + * It returns nonzero on error. */ +static int PickApartVmlinuz(uint8_t *kernel_buf, uint64_t kernel_size, + enum arch_t arch, + uint64_t kernel_body_load_address) +{ + uint64_t kernel32_start = 0; + uint64_t kernel32_size = kernel_size; + struct linux_kernel_params *lh, *params; + + /* Except for x86, the kernel is the kernel. */ + if (arch == ARCH_X86) { + /* The first part of the x86 vmlinuz is a header, followed by + * a real-mode boot stub. We only want the 32-bit part. */ + lh = (struct linux_kernel_params *)kernel_buf; + kernel32_start = (lh->setup_sects + 1) << 9; + if (kernel32_start >= kernel_size) { + fprintf(stderr, "Malformed kernel\n"); + return -1; + } + kernel32_size = kernel_size - 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); + Memcpy(&(params->setup_sects), &(lh->setup_sects), + offsetof(struct linux_kernel_params, e820_entries) + - offsetof(struct linux_kernel_params, setup_sects)); + params->boot_flag = 0; + params->ramdisk_image = 0; /* we don't support initrd */ + params->ramdisk_size = 0; + params->type_of_loader = 0xff; + /* We need to point to the kernel commandline arg. On disk, it + * will come right after the 32-bit part of the kernel. */ + params->cmd_line_ptr = kernel_body_load_address + + roundup(kernel32_size, CROS_ALIGN) + + find_cmdline_start(g_config_data, g_config_size); + Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr); + Debug(" version=0x%x\n", params->version); + Debug(" kernel_alignment=0x%x\n", params->kernel_alignment); + Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel); + /* Add a fake e820 memory map with 2 entries. */ + params->n_e820_entry = 2; + params->e820_entries[0].start_addr = 0x00000000; + params->e820_entries[0].segment_size = 0x00001000; + params->e820_entries[0].segment_type = E820_TYPE_RAM; + params->e820_entries[1].start_addr = 0xfffff000; + params->e820_entries[1].segment_size = 0x00001000; + params->e820_entries[1].segment_type = E820_TYPE_RESERVED; + } + + Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start); + Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size); + + /* Keep just the 32-bit kernel. */ + if (kernel32_size) { + g_kernel_size = kernel32_size; + Memcpy(g_kernel_data, kernel_buf + kernel32_start, + g_kernel_size); + } + + /* done */ + return 0; +} + +/* Split a kernel blob into separate g_kernel, g_param, g_config, and + * g_bootloader parts. */ +static void UnpackKernelBlob(uint8_t *kernel_blob_data) +{ + uint64_t now; + + /* We have to work backwards from the end, because the preamble + only describes the bootloader stub. */ + + /* Where does the bootloader stub begin? */ + now = g_preamble->bootloader_address - g_preamble->body_load_address; + + /* Bootloader is at the end */ + g_bootloader_size = g_preamble->bootloader_size; + g_bootloader_data = kernel_blob_data + now; + Debug("bootloader_size = 0x%" PRIx64 "\n", g_bootloader_size); + Debug("bootloader_ofs = 0x%" PRIx64 "\n", now); + + /* Before that is the params */ + now -= CROS_PARAMS_SIZE; + g_param_size = CROS_PARAMS_SIZE; + g_param_data = kernel_blob_data + now; + Debug("param_ofs = 0x%" PRIx64 "\n", now); + + /* Before that is the config */ + now -= CROS_CONFIG_SIZE; + g_config_size = CROS_CONFIG_SIZE; + g_config_data = kernel_blob_data + now; + Debug("config_ofs = 0x%" PRIx64 "\n", now); + + /* The kernel starts at offset 0 and extends up to the config */ + g_kernel_data = kernel_blob_data; + g_kernel_size = now; + Debug("kernel_size = 0x%" PRIx64 "\n", g_kernel_size); +} + + +/* Replaces the config section of the specified kernel blob. + * Return nonzero on error. */ +int UpdateKernelBlobConfig(uint8_t *kblob_data, uint64_t kblob_size, + uint8_t *config_data, uint64_t config_size) +{ + /* We should have already examined this blob. If not, we could do it + * again, but it's more likely due to an error. */ + if (kblob_data != g_kernel_blob_data || + kblob_size != g_kernel_blob_size) { + fprintf(stderr, "Trying to update some other blob\n"); + return -1; + } + + Memset(g_config_data, 0, g_config_size); + Memcpy(g_config_data, config_data, config_size); + + return 0; +} + +/* Split a kernel partition into separate vblock and blob parts. */ +uint8_t *UnpackKPart(uint8_t *kpart_data, uint64_t kpart_size, + uint64_t padding, + VbKeyBlockHeader **keyblock_ptr, + VbKernelPreambleHeader **preamble_ptr, + uint64_t *blob_size_ptr) +{ + VbKeyBlockHeader *keyblock; + VbKernelPreambleHeader *preamble; + uint64_t now = 0; + + /* Sanity-check the keyblock */ + keyblock = (VbKeyBlockHeader *)kpart_data; + Debug("Keyblock is 0x%" PRIx64 " bytes\n", keyblock->key_block_size); + now += keyblock->key_block_size; + if (now > kpart_size) { + fprintf(stderr, + "key_block_size advances past the end of the blob\n"); + return NULL; + } + if (now > padding) { + fprintf(stderr, + "key_block_size advances past %" PRIu64 + " byte padding\n", + padding); + return NULL; + } + + /* LGTM */ + g_keyblock = keyblock; + + /* And the preamble */ + preamble = (VbKernelPreambleHeader *)(kpart_data + now); + Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); + now += preamble->preamble_size; + if (now > kpart_size) { + fprintf(stderr, + "preamble_size advances past the end of the blob\n"); + return NULL; + } + if (now > padding) { + fprintf(stderr, "preamble_size advances past %" PRIu64 + " byte padding\n", padding); + return NULL; + } + /* LGTM */ + Debug(" kernel_version = %d\n", preamble->kernel_version); + Debug(" bootloader_address = 0x%" PRIx64 "\n", + preamble->bootloader_address); + Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size); + Debug(" kern_blob_size = 0x%" PRIx64 "\n", + preamble->body_signature.data_size); + g_preamble = preamble; + g_ondisk_bootloader_addr = g_preamble->bootloader_address; + + Debug("kernel blob is at offset 0x%" PRIx64 "\n", now); + g_kernel_blob_data = kpart_data + now; + g_kernel_blob_size = kpart_size - now; + + /* Sanity check */ + if (g_kernel_blob_size < preamble->body_signature.data_size) + fprintf(stderr, + "Warning: kernel file only has 0x%" PRIx64 " bytes\n", + g_kernel_blob_size); + + /* Update the blob pointers */ + UnpackKernelBlob(g_kernel_blob_data); + + if (keyblock_ptr) + *keyblock_ptr = keyblock; + if (preamble_ptr) + *preamble_ptr = preamble; + if (blob_size_ptr) + *blob_size_ptr = g_kernel_blob_size; + + return g_kernel_blob_data; +} + +uint8_t *SignKernelBlob(uint8_t *kernel_blob, uint64_t kernel_size, + uint64_t padding, + int version, uint64_t kernel_body_load_address, + VbKeyBlockHeader *keyblock, VbPrivateKey *signpriv_key, + uint64_t *vblock_size_ptr) +{ + VbSignature *body_sig; + VbKernelPreambleHeader *preamble; + uint64_t min_size = padding > keyblock->key_block_size + ? padding - keyblock->key_block_size : 0; + void *outbuf; + uint64_t outsize; + + /* Sign the kernel data */ + body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key); + if (!body_sig) { + fprintf(stderr, "Error calculating body signature\n"); + return NULL; + } + + /* Create preamble */ + preamble = CreateKernelPreamble(version, + kernel_body_load_address, + g_ondisk_bootloader_addr, + g_bootloader_size, + body_sig, min_size, + signpriv_key); + if (!preamble) { + fprintf(stderr, "Error creating preamble.\n"); + return 0; + } + + outsize = keyblock->key_block_size + preamble->preamble_size; + outbuf = malloc(outsize); + Memset(outbuf, 0, outsize); + Memcpy(outbuf, keyblock, keyblock->key_block_size); + Memcpy(outbuf + keyblock->key_block_size, + preamble, preamble->preamble_size); + + if (vblock_size_ptr) + *vblock_size_ptr = outsize; + return outbuf; +} + +/* Returns zero on success */ +int WriteSomeParts(const char *outfile, + void *part1_data, uint64_t part1_size, + void *part2_data, uint64_t part2_size) +{ + FILE *f; + + /* Write the output file */ + Debug("writing %s with 0x%" PRIx64 ", 0x%" PRIx64 "\n", + outfile, part1_size, part2_size); + + f = fopen(outfile, "wb"); + if (!f) { + fprintf(stderr, "Can't open output file %s: %s\n", + outfile, strerror(errno)); + return -1; + } + + if (part1_data && part1_size) { + if (1 != fwrite(part1_data, part1_size, 1, f)) { + fprintf(stderr, "Can't write output file %s: %s\n", + outfile, strerror(errno)); + fclose(f); + unlink(outfile); + return -1; + } + } + + if (part2_data && part2_size) { + if (1 != fwrite(part2_data, part2_size, 1, f)) { + fprintf(stderr, "Can't write output file %s: %s\n", + outfile, strerror(errno)); + fclose(f); + unlink(outfile); + return -1; + } + } + + fclose(f); + + /* Success */ + return 0; +} + +/* Returns 0 on success */ +int VerifyKernelBlob(uint8_t *kernel_blob, + uint64_t kernel_size, + VbPublicKey *signpub_key, + const char *keyblock_outfile, + uint64_t min_version) +{ + VbPublicKey *data_key; + RSAPublicKey *rsa; + int rv = -1; + + if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size, + signpub_key, (0 == signpub_key))) { + fprintf(stderr, "Error verifying key block.\n"); + goto done; + } + + printf("Key block:\n"); + data_key = &g_keyblock->data_key; + printf(" Signature: %s\n", + signpub_key ? "valid" : "ignored"); + printf(" Size: 0x%" PRIx64 "\n", + g_keyblock->key_block_size); + printf(" Flags: %" PRIu64 " ", + g_keyblock->key_block_flags); + if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) + printf(" !DEV"); + if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) + printf(" DEV"); + if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) + printf(" !REC"); + if (g_keyblock->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(" Data key sha1sum: "); + PrintPubKeySha1Sum(data_key); + printf("\n"); + + if (keyblock_outfile) { + FILE *f = NULL; + f = fopen(keyblock_outfile, "wb"); + if (!f) { + fprintf(stderr, "Can't open key block file %s: %s\n", + keyblock_outfile, strerror(errno)); + goto done; + } + if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) { + fprintf(stderr, "Can't write key block file %s: %s\n", + keyblock_outfile, strerror(errno)); + fclose(f); + goto done; + } + fclose(f); + } + + if (data_key->key_version < (min_version >> 16)) { + fprintf(stderr, "Data key version %" PRIu64 + " is lower than minimum %" PRIu64 ".\n", + data_key->key_version, (min_version >> 16)); + goto done; + } + + rsa = PublicKeyToRSA(data_key); + if (!rsa) { + fprintf(stderr, "Error parsing data key.\n"); + goto done; + } + + /* Verify preamble */ + if (0 != VerifyKernelPreamble(g_preamble, + g_preamble->preamble_size, rsa)) { + fprintf(stderr, "Error verifying preamble.\n"); + goto done; + } + + printf("Preamble:\n"); + printf(" Size: 0x%" PRIx64 "\n", + g_preamble->preamble_size); + printf(" Header version: %" PRIu32 ".%" PRIu32 "\n", + g_preamble->header_version_major, + g_preamble->header_version_minor); + printf(" Kernel version: %" PRIu64 "\n", + g_preamble->kernel_version); + printf(" Body load address: 0x%" PRIx64 "\n", + g_preamble->body_load_address); + printf(" Body size: 0x%" PRIx64 "\n", + g_preamble->body_signature.data_size); + printf(" Bootloader address: 0x%" PRIx64 "\n", + g_preamble->bootloader_address); + printf(" Bootloader size: 0x%" PRIx64 "\n", + g_preamble->bootloader_size); + + if (g_preamble->kernel_version < (min_version & 0xFFFF)) { + fprintf(stderr, + "Kernel version %" PRIu64 " is lower than minimum %" + PRIu64 ".\n", g_preamble->kernel_version, + (min_version & 0xFFFF)); + goto done; + } + + /* Verify body */ + if (0 != VerifyData(kernel_blob, kernel_size, + &g_preamble->body_signature, rsa)) { + fprintf(stderr, "Error verifying kernel body.\n"); + goto done; + } + printf("Body verification succeeded.\n"); + + printf("Config:\n%s\n", kernel_blob + KernelCmdLineOffset(g_preamble)); + + rv = 0; +done: + return rv; +} + + +uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size, + enum arch_t arch, uint64_t kernel_body_load_address, + uint8_t *config_data, uint64_t config_size, + uint8_t *bootloader_data, uint64_t bootloader_size, + uint64_t *blob_size_ptr) +{ + uint64_t now = 0; + int tmp; + + /* We have all the parts. How much room do we need? */ + tmp = KernelSize(vmlinuz_buf, vmlinuz_size, arch); + if (tmp < 0) + return NULL; + g_kernel_size = tmp; + 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; + Debug("g_kernel_blob_size 0x%" PRIx64 "\n", g_kernel_blob_size); + + /* Allocate space for the blob. */ + g_kernel_blob_data = malloc(g_kernel_blob_size); + Memset(g_kernel_blob_data, 0, g_kernel_blob_size); + + /* Assign the sub-pointers */ + g_kernel_data = g_kernel_blob_data + now; + Debug("g_kernel_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n", + g_kernel_size, now); + now += roundup(g_kernel_size, CROS_ALIGN); + + g_config_data = g_kernel_blob_data + now; + Debug("g_config_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n", + g_config_size, now); + now += g_config_size; + + g_param_data = g_kernel_blob_data + now; + Debug("g_param_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n", + g_param_size, now); + now += g_param_size; + + g_bootloader_data = g_kernel_blob_data + now; + Debug("g_bootloader_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n", + g_bootloader_size, now); + g_ondisk_bootloader_addr = kernel_body_load_address + now; + Debug("g_ondisk_bootloader_addr 0x%" PRIx64 "\n", + g_ondisk_bootloader_addr); + + /* Copy the kernel and params bits into the correct places */ + if (0 != PickApartVmlinuz(vmlinuz_buf, vmlinuz_size, + arch, kernel_body_load_address)) { + fprintf(stderr, "Error picking apart kernel file.\n"); + free(g_kernel_blob_data); + g_kernel_blob_data = NULL; + g_kernel_blob_size = 0; + return NULL; + } + + /* Copy the other bits too */ + Memcpy(g_config_data, config_data, config_size); + Memcpy(g_bootloader_data, bootloader_data, bootloader_size); + + if (blob_size_ptr) + *blob_size_ptr = g_kernel_blob_size; + return g_kernel_blob_data; +} diff --git a/futility/vb1_helper.h b/futility/vb1_helper.h new file mode 100644 index 00000000..fd976e0e --- /dev/null +++ b/futility/vb1_helper.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef VBOOT_REFERENCE_FUTILITY_VB1_HELPER_H_ +#define VBOOT_REFERENCE_FUTILITY_VB1_HELPER_H_ + +uint8_t *ReadConfigFile(const char *config_file, uint64_t *config_size); + +uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size, + enum arch_t arch, uint64_t kernel_body_load_address, + uint8_t *config_data, uint64_t config_size, + uint8_t *bootloader_data, uint64_t bootloader_size, + uint64_t *blob_size_ptr); + +uint8_t *SignKernelBlob(uint8_t *kernel_blob, uint64_t kernel_size, + uint64_t padding, + int version, uint64_t kernel_body_load_address, + VbKeyBlockHeader *keyblock, VbPrivateKey *signpriv_key, + uint64_t *vblock_size_ptr); + +int WriteSomeParts(const char *outfile, + void *part1_data, uint64_t part1_size, + void *part2_data, uint64_t part2_size); + +uint8_t *UnpackKPart(uint8_t *kpart_data, uint64_t kpart_size, + uint64_t padding, + VbKeyBlockHeader **keyblock_ptr, + VbKernelPreambleHeader **preamble_ptr, + uint64_t *blob_size_ptr); + +int UpdateKernelBlobConfig(uint8_t *kblob_data, uint64_t kblob_size, + uint8_t *config_data, uint64_t config_size); + +int VerifyKernelBlob(uint8_t *kernel_blob, + uint64_t kernel_size, + VbPublicKey *signpub_key, + const char *keyblock_outfile, + uint64_t min_version); + +uint64_t KernelCmdLineOffset(VbKernelPreambleHeader *preamble); + +#endif /* VBOOT_REFERENCE_FUTILITY_VB1_HELPER_H_ */ diff --git a/tests/futility/data/vmlinuz-amd64.bin b/tests/futility/data/vmlinuz-amd64.bin Binary files differnew file mode 100644 index 00000000..f54663ca --- /dev/null +++ b/tests/futility/data/vmlinuz-amd64.bin diff --git a/tests/futility/data/vmlinuz-arm.bin b/tests/futility/data/vmlinuz-arm.bin Binary files differnew file mode 100644 index 00000000..c7199879 --- /dev/null +++ b/tests/futility/data/vmlinuz-arm.bin diff --git a/tests/futility/run_test_scripts.sh b/tests/futility/run_test_scripts.sh index a1aa24cb..37759123 100755 --- a/tests/futility/run_test_scripts.sh +++ b/tests/futility/run_test_scripts.sh @@ -45,6 +45,7 @@ ${SCRIPTDIR}/test_dump_fmap.sh ${SCRIPTDIR}/test_load_fmap.sh ${SCRIPTDIR}/test_gbb_utility.sh ${SCRIPTDIR}/test_resign_firmware.sh +${SCRIPTDIR}/test_sign_kernel.sh " # Get ready... diff --git a/tests/futility/test_sign_kernel.sh b/tests/futility/test_sign_kernel.sh new file mode 100755 index 00000000..f6fe1a1a --- /dev/null +++ b/tests/futility/test_sign_kernel.sh @@ -0,0 +1,168 @@ +#!/bin/bash -eux +# Copyright (c) 2014 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +me=${0##*/} +TMP="$me.tmp" + +# Work in scratch directory +cd "$OUTDIR" + +DEVKEYS=${SRCDIR}/tests/devkeys + +echo "hi there" > ${TMP}.config.txt +echo "hello boys" > ${TMP}.config2.txt +dd if=/dev/urandom bs=512 count=1 of=${TMP}.bootloader.bin +dd if=/dev/urandom bs=512 count=1 of=${TMP}.bootloader2.bin + +# default padding +padding=65536 + +try_arch () { + local arch=$1 + + echo -n "${arch}.a " 1>&3 + + # pack it up the old way + ${FUTILITY} vbutil_kernel0 --debug \ + --pack ${TMP}.blob1.${arch} \ + --keyblock ${DEVKEYS}/recovery_kernel.keyblock \ + --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \ + --version 1 \ + --config ${TMP}.config.txt \ + --bootloader ${TMP}.bootloader.bin \ + --vmlinuz ${SCRIPTDIR}/data/vmlinuz-${arch}.bin \ + --arch ${arch} \ + --kloadaddr 0x11000 + + # verify the old way + ${FUTILITY} vbutil_kernel0 --verify ${TMP}.blob1.${arch} \ + --signpubkey ${DEVKEYS}/recovery_key.vbpubk + ${FUTILITY} vbutil_kernel --verify ${TMP}.blob1.${arch} \ + --signpubkey ${DEVKEYS}/recovery_key.vbpubk --debug + + # pack it up the new way + ${FUTILITY} vbutil_kernel --debug \ + --pack ${TMP}.blob2.${arch} \ + --keyblock ${DEVKEYS}/recovery_kernel.keyblock \ + --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \ + --version 1 \ + --config ${TMP}.config.txt \ + --bootloader ${TMP}.bootloader.bin \ + --vmlinuz ${SCRIPTDIR}/data/vmlinuz-${arch}.bin \ + --arch ${arch} \ + --kloadaddr 0x11000 + + # they should be identical + cmp ${TMP}.blob1.${arch} ${TMP}.blob2.${arch} + + # repack it the old way + ${FUTILITY} vbutil_kernel0 \ + --repack ${TMP}.blob3.${arch} \ + --oldblob ${TMP}.blob1.${arch} \ + --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ + --keyblock ${DEVKEYS}/kernel.keyblock \ + --version 2 \ + --config ${TMP}.config2.txt \ + --bootloader ${TMP}.bootloader2.bin + + # verify the old way + ${FUTILITY} vbutil_kernel0 --verify ${TMP}.blob3.${arch} \ + --signpubkey ${DEVKEYS}/kernel_subkey.vbpubk + ${FUTILITY} vbutil_kernel --verify ${TMP}.blob3.${arch} \ + --signpubkey ${DEVKEYS}/kernel_subkey.vbpubk + + # repack it the new way + ${FUTILITY} vbutil_kernel \ + --repack ${TMP}.blob4.${arch} \ + --oldblob ${TMP}.blob2.${arch} \ + --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ + --keyblock ${DEVKEYS}/kernel.keyblock \ + --version 2 \ + --config ${TMP}.config2.txt \ + --bootloader ${TMP}.bootloader2.bin + + # they should be identical + cmp ${TMP}.blob3.${arch} ${TMP}.blob4.${arch} + + # and now just the vblocks... + echo -n "${arch}.v " 1>&3 + + dd bs=${padding} count=1 if=${TMP}.blob1.${arch} of=${TMP}.blob1.${arch}.vb0 + ${FUTILITY} vbutil_kernel0 \ + --pack ${TMP}.blob1.${arch}.vb1 \ + --vblockonly \ + --keyblock ${DEVKEYS}/recovery_kernel.keyblock \ + --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \ + --version 1 \ + --config ${TMP}.config.txt \ + --bootloader ${TMP}.bootloader.bin \ + --vmlinuz ${SCRIPTDIR}/data/vmlinuz-${arch}.bin \ + --arch ${arch} \ + --kloadaddr 0x11000 + cmp ${TMP}.blob1.${arch}.vb0 ${TMP}.blob1.${arch}.vb1 + + dd bs=${padding} count=1 if=${TMP}.blob2.${arch} of=${TMP}.blob2.${arch}.vb0 + ${FUTILITY} vbutil_kernel \ + --pack ${TMP}.blob2.${arch}.vb1 \ + --vblockonly \ + --keyblock ${DEVKEYS}/recovery_kernel.keyblock \ + --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \ + --version 1 \ + --config ${TMP}.config.txt \ + --bootloader ${TMP}.bootloader.bin \ + --vmlinuz ${SCRIPTDIR}/data/vmlinuz-${arch}.bin \ + --arch ${arch} \ + --kloadaddr 0x11000 + cmp ${TMP}.blob2.${arch}.vb0 ${TMP}.blob2.${arch}.vb1 + + dd bs=${padding} count=1 if=${TMP}.blob3.${arch} of=${TMP}.blob3.${arch}.vb0 + ${FUTILITY} vbutil_kernel0 \ + --repack ${TMP}.blob3.${arch}.vb1 \ + --vblockonly \ + --oldblob ${TMP}.blob1.${arch} \ + --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ + --keyblock ${DEVKEYS}/kernel.keyblock \ + --version 2 \ + --config ${TMP}.config2.txt \ + --bootloader ${TMP}.bootloader2.bin + cmp ${TMP}.blob3.${arch}.vb0 ${TMP}.blob3.${arch}.vb1 + + dd bs=${padding} count=1 if=${TMP}.blob4.${arch} of=${TMP}.blob4.${arch}.vb0 + ${FUTILITY} vbutil_kernel \ + --repack ${TMP}.blob4.${arch}.vb1 \ + --vblockonly \ + --oldblob ${TMP}.blob2.${arch} \ + --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ + --keyblock ${DEVKEYS}/kernel.keyblock \ + --version 2 \ + --config ${TMP}.config2.txt \ + --bootloader ${TMP}.bootloader2.bin + cmp ${TMP}.blob4.${arch}.vb0 ${TMP}.blob4.${arch}.vb1 + + + # Note: We specifically do not test repacking with a different --kloadaddr, + # because the old way has a bug and does not update params->cmd_line_ptr to + # point at the new on-disk location. Apparently (and not surprisingly), no + # one has ever done that. + +#HEY # pack it up the new way +#HEY ${FUTILITY} sign --debug \ +#HEY --vmlinuz ${SCRIPTDIR}/data/vmlinuz-${arch}.bin \ +#HEY --config ${TMP}.config.txt \ +#HEY --bootloader ${TMP}.bootloader.bin \ +#HEY --arch ${arch} \ +#HEY --keyblock ${DEVKEYS}/recovery_kernel.keyblock \ +#HEY --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \ +#HEY --version 1 \ +#HEY --outfile ${TMP}.blob2.${arch} + +} + +try_arch amd64 +try_arch arm + +# cleanup +rm -rf ${TMP}* +exit 0 |