summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2014-08-27 13:34:35 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-08-29 21:56:23 +0000
commitb8ff397674fb98c1d7eea864e7fa571369675131 (patch)
treec714f793ff718d85d8cdb1d23a0537c0b0fab39e
parent88458d9b5281aca162821a369707781ac9abb44e (diff)
downloadvboot-b8ff397674fb98c1d7eea864e7fa571369675131.tar.gz
vboot: Add system-level test for LoadKernel()
This creates a disk image and verifies a kernel can be loaded from it. It is roughly analogous to vb2_firmware_tests.sh, but at the kernel step instead of the firmware step. This will get more interesting in the near future, with the upcoming addition of a streaming API to read the kernel. BUG=chromium:408265 BRANCH=none TEST=make runtests Change-Id: Icc9e6d0e318c4bd38fc9ab1ad704da99232822e1 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/214508 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r--Makefile4
-rw-r--r--futility/cmd_verify_kernel.c141
-rwxr-xr-xtests/load_kernel_tests.sh73
3 files changed, 217 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 300d317c..d50cc4ff 100644
--- a/Makefile
+++ b/Makefile
@@ -543,7 +543,8 @@ FUTIL_SRCS = \
futility/cmd_vbutil_firmware.c \
futility/cmd_vbutil_kernel.c \
futility/cmd_vbutil_key.c \
- futility/cmd_vbutil_keyblock.c
+ futility/cmd_vbutil_keyblock.c \
+ futility/cmd_verify_kernel.c
ifneq (${VBOOT2},)
FUTIL_SRCS += \
@@ -1086,6 +1087,7 @@ runcgpttests: test_setup
.PHONY: runtestscripts
runtestscripts: test_setup genfuzztestcases
+ tests/load_kernel_tests.sh
tests/run_cgpt_tests.sh ${BUILD_RUN}/cgpt/cgpt
tests/run_cgpt_tests.sh ${BUILD_RUN}/cgpt/cgpt -N=512,32,1,3
tests/run_preamble_tests.sh
diff --git a/futility/cmd_verify_kernel.c b/futility/cmd_verify_kernel.c
new file mode 100644
index 00000000..8c413427
--- /dev/null
+++ b/futility/cmd_verify_kernel.c
@@ -0,0 +1,141 @@
+/* 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.
+ *
+ * Routines for verifying a kernel or disk image
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "host_common.h"
+#include "util_misc.h"
+#include "vboot_common.h"
+#include "vboot_api.h"
+#include "vboot_kernel.h"
+#include "futility.h"
+
+static uint8_t *diskbuf;
+
+static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
+static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
+static VbNvContext nvc;
+
+static LoadKernelParams params;
+static VbCommonParams cparams;
+
+VbError_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start,
+ uint64_t lba_count, void *buffer)
+{
+ if (handle != (VbExDiskHandle_t)1)
+ return VBERROR_UNKNOWN;
+ if (lba_start > params.ending_lba)
+ return VBERROR_UNKNOWN;
+ if (lba_start + lba_count > params.ending_lba + 1)
+ return VBERROR_UNKNOWN;
+
+ memcpy(buffer, diskbuf + lba_start * 512, lba_count * 512);
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start,
+ uint64_t lba_count, const void *buffer)
+{
+ if (handle != (VbExDiskHandle_t)1)
+ return VBERROR_UNKNOWN;
+ if (lba_start > params.ending_lba)
+ return VBERROR_UNKNOWN;
+ if (lba_start + lba_count > params.ending_lba + 1)
+ return VBERROR_UNKNOWN;
+
+ memcpy(diskbuf + lba_start * 512, buffer, lba_count * 512);
+ return VBERROR_SUCCESS;
+}
+
+int do_verify_kernel(int argc, char *argv[])
+{
+ VbPublicKey *kernkey;
+ uint64_t disk_bytes = 0;
+ int rv;
+
+ const char *progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+
+ if (argc < 3) {
+ fprintf(stderr,
+ "usage: %s <disk_image> <kernel.vbpubk>\n", progname);
+ return 1;
+ }
+
+ /* Load disk file */
+ /* TODO: better to nmap() in the long run */
+ diskbuf = ReadFile(argv[1], &disk_bytes);
+ if (!diskbuf) {
+ fprintf(stderr, "Can't read disk file %s\n", argv[1]);
+ return 1;
+ }
+
+ /* Read public key */
+ kernkey = PublicKeyRead(argv[2]);
+ if (!kernkey) {
+ fprintf(stderr, "Can't read key file %s\n", argv[2]);
+ return 1;
+ }
+
+ /* Set up shared data blob */
+ VbSharedDataInit(shared, sizeof(shared_data));
+ VbSharedDataSetKernelKey(shared, kernkey);
+ /* TODO: optional TPM current kernel version */
+
+ /* Set up params */
+ params.shared_data_blob = shared_data;
+ params.shared_data_size = sizeof(shared_data);
+ params.disk_handle = (VbExDiskHandle_t)1;
+ params.bytes_per_lba = 512;
+ params.ending_lba = disk_bytes / 512 - 1;
+
+ params.kernel_buffer_size = 16 * 1024 * 1024;
+ params.kernel_buffer = malloc(params.kernel_buffer_size);
+ if (!params.kernel_buffer) {
+ fprintf(stderr, "Can't allocate kernel buffer\n");
+ return 1;
+ }
+
+ /* GBB and cparams only needed by LoadKernel() in recovery mode */
+ params.gbb_data = NULL;
+ params.gbb_size = 0;
+
+ /* TODO: optional dev-mode flag */
+ params.boot_flags = 0;
+
+ /*
+ * LoadKernel() cares only about VBNV_DEV_BOOT_SIGNED_ONLY, and only in
+ * dev mode. So just use defaults.
+ */
+ VbNvSetup(&nvc);
+ params.nv_context = &nvc;
+
+ /* Try loading kernel */
+ rv = LoadKernel(&params, &cparams);
+ if (rv != VBERROR_SUCCESS) {
+ fprintf(stderr, "LoadKernel() failed with code %d\n", rv);
+ return 1;
+ }
+
+ printf("Found a good kernel.\n");
+ printf("Partition number: %d\n", (int)params.partition_number);
+ printf("Bootloader address: 0x%" PRIx64 "\n",
+ params.bootloader_address);
+
+ /* TODO: print other things (partition GUID, nv_context, shared_data) */
+
+ printf("Yaay!\n");
+ return 0;
+}
+
+DECLARE_FUTIL_COMMAND(verify_kernel, do_verify_kernel,
+ "Verifies a kernel / disk image");
diff --git a/tests/load_kernel_tests.sh b/tests/load_kernel_tests.sh
new file mode 100755
index 00000000..74e91e40
--- /dev/null
+++ b/tests/load_kernel_tests.sh
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+# 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.
+#
+# End-to-end test for vboot2 kernel verification
+
+# Load common constants and variables.
+. "$(dirname "$0")/common.sh"
+
+set -e
+
+echo 'Creating test kernel'
+
+# Run tests in a dedicated directory for easy cleanup or debugging.
+DIR="${TEST_DIR}/load_kernel_test_dir"
+[ -d "$DIR" ] || mkdir -p "$DIR"
+echo "Testing kernel verification in $DIR"
+cd "$DIR"
+
+# Dummy kernel data
+echo "hi there" > "dummy_config.txt"
+dd if=/dev/urandom bs=16384 count=1 of="dummy_bootloader.bin"
+dd if=/dev/urandom bs=32768 count=1 of="dummy_kernel.bin"
+
+# Pack kernel data key using original vboot utilities.
+${BIN_DIR}/vbutil_key --pack datakey.test \
+ --key ${TESTKEY_DIR}/key_rsa2048.keyb --algorithm 4
+
+# Keyblock with kernel data key is signed by kernel subkey
+# Flags=5 means dev=0 rec=0
+${BIN_DIR}/vbutil_keyblock --pack keyblock.test \
+ --datapubkey datakey.test \
+ --flags 5 \
+ --signprivate ${SCRIPT_DIR}/devkeys/kernel_subkey.vbprivk
+
+# Kernel preamble is signed with the kernel data key
+${BIN_DIR}/futility vbutil_kernel \
+ --pack "kernel.test" \
+ --keyblock "keyblock.test" \
+ --signprivate ${TESTKEY_DIR}/key_rsa2048.sha256.vbprivk \
+ --version 1 \
+ --arch arm \
+ --vmlinuz "dummy_kernel.bin" \
+ --bootloader "dummy_bootloader.bin" \
+ --config "dummy_config.txt"
+
+echo 'Verifying test kernel using vbutil_kernel'
+
+# Verify the kernel
+${BIN_DIR}/futility vbutil_kernel \
+ --verify "kernel.test" \
+ --signpubkey ${SCRIPT_DIR}/devkeys/kernel_subkey.vbpubk
+
+happy 'Kernel verification succeeded'
+
+# Now create a dummy disk image
+echo 'Creating test disk image'
+dd if=/dev/zero of=disk.test bs=1024 count=1024
+cgpt create disk.test
+cgpt add -i 1 -S 1 -P 1 -b 64 -s 960 -t kernel -l kernelA disk.test
+cgpt show disk.test
+
+# And insert the kernel into it
+dd if=kernel.test of=disk.test bs=512 seek=64 conv=notrunc
+
+# And verify it using futility
+echo 'Verifying test disk image'
+${BIN_DIR}/futility verify_kernel disk.test \
+ ${SCRIPT_DIR}/devkeys/kernel_subkey.vbpubk
+
+happy 'Image verification succeeded'