Merge cos-sdk into ToT Includes changes for the most recent ChromeOS merge. BUG=b/257271340 TEST=presubmit RELEASE_NOTE=None Change-Id: I9910568160c45bbbf5cc1a7267cf74dcba9d8aa3
diff --git a/.gitignore b/.gitignore index 9edc243..bb49193 100644 --- a/.gitignore +++ b/.gitignore
@@ -11,3 +11,4 @@ scripts/newbitmaps/strings/localized_text/*/*.png target .idea +*.swp
diff --git a/Android.mk b/Android.mk index c54a3b7..e0ba6aa 100644 --- a/Android.mk +++ b/Android.mk
@@ -67,7 +67,6 @@ firmware/stub/vboot_api_stub_sf.c VBSLK_SRCS += \ - firmware/stub/vboot_api_stub.c \ firmware/stub/vboot_api_stub_disk.c \ firmware/stub/vboot_api_stub_stream.c @@ -169,4 +168,3 @@ LOCAL_STATIC_LIBRARIES := libvboot_util-host LOCAL_SHARED_LIBRARIES := libcrypto-host include $(BUILD_HOST_EXECUTABLE) -
diff --git a/Makefile b/Makefile index 4a07128..7731598 100644 --- a/Makefile +++ b/Makefile
@@ -237,7 +237,7 @@ # Code coverage ifneq ($(filter-out 0,${COV}),) - COV_FLAGS = -O0 --coverage -DCOVERAGE + COV_FLAGS = -Og --coverage -DCOVERAGE CFLAGS += ${COV_FLAGS} LDFLAGS += ${COV_FLAGS} COV_INFO = ${BUILD}/coverage.info @@ -275,6 +275,13 @@ LIBZIP_LIBS := $(shell ${PKG_CONFIG} --libs libzip) endif +LIBARCHIVE_VERSION := $(shell ${PKG_CONFIG} --modversion libarchive 2>/dev/null) +HAVE_LIBARCHIVE := $(if ${LIBARCHIVE_VERSION},1) +ifneq ($(filter-out 0,${HAVE_LIBARCHIVE}),) + CFLAGS += -DHAVE_LIBARCHIVE $(shell ${PKG_CONFIG} --cflags libarchive) + LIBARCHIVE_LIBS := $(shell ${PKG_CONFIG} --libs libarchive) +endif + HAVE_CROSID := $(shell ${PKG_CONFIG} --exists crosid && echo 1) ifeq ($(HAVE_CROSID),1) CFLAGS += -DHAVE_CROSID $(shell ${PKG_CONFIG} --cflags crosid) @@ -369,6 +376,7 @@ firmware/2lib/2gbb.c \ firmware/2lib/2hmac.c \ firmware/2lib/2kernel.c \ + firmware/2lib/2load_kernel.c \ firmware/2lib/2misc.c \ firmware/2lib/2nvstorage.c \ firmware/2lib/2packed_key.c \ @@ -388,8 +396,6 @@ firmware/lib/cgptlib/cgptlib_internal.c \ firmware/lib/cgptlib/crc32.c \ firmware/lib/gpt_misc.c \ - firmware/lib/vboot_api_kernel.c \ - firmware/lib/vboot_kernel.c \ firmware/lib20/api_kernel.c \ firmware/lib20/kernel.c @@ -423,7 +429,6 @@ # TODO: split out other stub funcs too FWLIB_SRCS += \ firmware/stub/tpm_lite_stub.c \ - firmware/stub/vboot_api_stub.c \ firmware/stub/vboot_api_stub_disk.c \ firmware/stub/vboot_api_stub_stream.c \ firmware/2lib/2stub.c @@ -439,12 +444,14 @@ ifneq ($(filter-out 0,${USE_FLASHROM}),) $(info building with libflashrom support) FLASHROM_LIBS := $(shell ${PKG_CONFIG} --libs flashrom) -COMMONLIB_SRCS = \ +COMMONLIB_SRCS += \ host/lib/flashrom.c \ - host/lib/flashrom_drv.c \ - host/lib/subprocess.c + host/lib/flashrom_drv.c CFLAGS += -DUSE_FLASHROM endif +COMMONLIB_SRCS += \ + host/lib/subprocess.c \ + host/lib/cbfstool.c # Intermediate library for the vboot_reference utilities to link against. UTILLIB = ${BUILD}/libvboot_util.a @@ -515,7 +522,6 @@ firmware/lib/cgptlib/crc32.c \ firmware/lib/gpt_misc.c \ firmware/stub/tpm_lite_stub.c \ - firmware/stub/vboot_api_stub.c \ firmware/stub/vboot_api_stub_disk.c \ futility/dump_kernel_config_lib.c \ $(CROSSYSTEM_ARCH_C) \ @@ -675,6 +681,7 @@ FUTIL_SRCS += host/lib/flashrom_drv.c \ futility/flashrom_wp_drv.c \ futility/updater_archive.c \ + futility/updater_manifest.c \ futility/updater_quirks.c \ futility/updater_utils.c \ futility/updater.c @@ -693,10 +700,10 @@ # Library of handy test functions. TESTLIB = ${BUILD}/tests/test.a -TESTLIB_SRCS += \ - tests/test_common.c \ - tests/timer_utils.c \ - tests/crc32_test.c +TEST_COMMON_DIR = tests/common + +TESTLIB_SRCS += $(wildcard $(TEST_COMMON_DIR)/*.c) +TESTLIB_SRCS += tests/crc32_test.c TESTLIB_OBJS = ${TESTLIB_SRCS:%.c=${BUILD}/%.o} TEST_OBJS += ${TESTLIB_OBJS} @@ -709,10 +716,6 @@ tests/gpt_misc_tests \ tests/sha_benchmark \ tests/subprocess_tests \ - tests/vboot_api_kernel4_tests \ - tests/vboot_api_kernel_tests \ - tests/vboot_kernel_tests \ - tests/vboot_kernel2_tests \ tests/verify_kernel ifeq ($(filter-out 0,${MOCK_TPM})$(filter-out 0,${TPM2_MODE}),) @@ -743,7 +746,10 @@ tests/vb2_host_key_tests \ tests/vb2_host_nvdata_flashrom_tests \ tests/vb2_kernel_tests \ + tests/vb2_load_kernel_tests \ + tests/vb2_load_kernel2_tests \ tests/vb2_misc_tests \ + tests/vb2_misc2_tests \ tests/vb2_nvstorage_tests \ tests/vb2_rsa_utility_tests \ tests/vb2_recovery_reasons_tests \ @@ -1043,7 +1049,8 @@ futil: ${FUTIL_BIN} # FUTIL_LIBS is shared by FUTIL_BIN and TEST_FUTIL_BINS. -FUTIL_LIBS = ${CROSID_LIBS} ${CRYPTO_LIBS} ${LIBZIP_LIBS} ${FLASHROM_LIBS} +FUTIL_LIBS = ${CROSID_LIBS} ${CRYPTO_LIBS} ${LIBZIP_LIBS} ${LIBARCHIVE_LIBS} \ + ${FLASHROM_LIBS} ${FUTIL_BIN}: LDLIBS += ${FUTIL_LIBS} ${FUTIL_BIN}: ${FUTIL_OBJS} ${UTILLIB} ${FWLIB} @@ -1279,10 +1286,6 @@ # tlcl_tests only works when MOCK_TPM is disabled ${RUNTEST} ${BUILD_RUN}/tests/tlcl_tests endif - ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel4_tests - ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel_tests - ${RUNTEST} ${BUILD_RUN}/tests/vboot_kernel_tests - ${RUNTEST} ${BUILD_RUN}/tests/vboot_kernel2_tests .PHONY: run2tests run2tests: install_for_test @@ -1296,8 +1299,11 @@ ${RUNTEST} ${BUILD_RUN}/tests/vb2_firmware_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_gbb_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_host_key_tests + ${RUNTEST} ${BUILD_RUN}/tests/vb2_load_kernel_tests + ${RUNTEST} ${BUILD_RUN}/tests/vb2_load_kernel2_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_kernel_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_misc_tests + ${RUNTEST} ${BUILD_RUN}/tests/vb2_misc2_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_nvstorage_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_rsa_utility_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_firmware_tests @@ -1340,13 +1346,18 @@ ${Q}echo -e "\nruntests: \E[32;1mALL TESTS PASSED SUCCESSFULLY!\E[0;m\n" # Code coverage +.PHONY: coverage +ifeq ($(filter-out 0,${COV}),) +coverage: + $(error Build coverage like this: make clean && COV=1 make coverage) +else .PHONY: coverage_init coverage_init: install_for_test rm -f ${COV_INFO}* lcov -c -i -d . -b . -o ${COV_INFO}.initial .PHONY: coverage_html -coverage_html: +coverage_html: coverage_init runtests lcov -c -d . -b . -o ${COV_INFO}.tests lcov -a ${COV_INFO}.initial -a ${COV_INFO}.tests -o ${COV_INFO}.total lcov -r ${COV_INFO}.total '/usr/*' -o ${COV_INFO}.local @@ -1358,11 +1369,6 @@ lcov -e ${COV_INFO}.nostub '${SRCDIR}/firmware/*' \ -o ${COV_INFO}.firmware -.PHONY: coverage -ifeq ($(filter-out 0,${COV}),) -coverage: - $(error Build coverage like this: make clean && COV=1 make coverage) -else coverage: coverage_init runtests coverage_html endif
diff --git a/OWNERS b/OWNERS index 21ecb22..b748e0e 100644 --- a/OWNERS +++ b/OWNERS
@@ -2,4 +2,4 @@ yupingso@chromium.org twawrzynczak@chromium.org hungte@chromium.org -* +roccochen@chromium.org
diff --git a/cgpt/cgpt_find.c b/cgpt/cgpt_find.c index 8046aad..f50908f 100644 --- a/cgpt/cgpt_find.c +++ b/cgpt/cgpt_find.c
@@ -243,8 +243,14 @@ goto cleanup; } } + // Create a temp dir to work in. + if (mkdtemp(temp_dir) == NULL) { + perror("Cannot create a temporary directory.\n"); + goto cleanup; + } if (ReadNorFlash(temp_dir) != 0) { perror("ReadNorFlash"); + RemoveDir(temp_dir); goto cleanup; } char nor_file[64];
diff --git a/cgpt/cgpt_nor.c b/cgpt/cgpt_nor.c index 1530271..e96ee27 100644 --- a/cgpt/cgpt_nor.c +++ b/cgpt/cgpt_nor.c
@@ -203,20 +203,11 @@ #define FLASHROM_RW_GPT_SEC "RW_GPT_SECONDARY:rw_gpt_2" #define FLASHROM_RW_GPT "RW_GPT:rw_gpt" -// Read RW_GPT from NOR flash to "rw_gpt" in a temp dir |temp_dir_template|. -// |temp_dir_template| is passed to mkdtemp() so it must satisfy all -// requirements by mkdtemp. +// Read RW_GPT from NOR flash to "rw_gpt" in a dir. // TODO(b:184812319): Replace this function with flashrom_read. -int ReadNorFlash(char *temp_dir_template) { +int ReadNorFlash(const char *dir) { int ret = 0; - // Create a temp dir to work in. - ret++; - if (mkdtemp(temp_dir_template) == NULL) { - Error("Cannot create a temporary directory.\n"); - return ret; - } - // Read RW_GPT section from NOR flash to "rw_gpt". ret++; @@ -225,7 +216,7 @@ Error("Cannot get current directory.\n"); return ret; } - if (chdir(temp_dir_template) < 0) { + if (chdir(dir) < 0) { Error("Cannot change directory.\n"); goto out_free; } @@ -234,7 +225,6 @@ // output. if (subprocess_run(argv, &subprocess_null, &subprocess_null, NULL) != 0) { Error("Cannot exec flashrom to read from RW_GPT section.\n"); - RemoveDir(temp_dir_template); } else { ret = 0; } @@ -248,6 +238,18 @@ return ret; } +static int FlashromWriteRegion(const char *region) +{ + const char *const argv[] = {FLASHROM_PATH, "-i", region, "-w", "--noverify-all"}; + // Redirect stdout to /dev/null so that flashrom does not muck up cgpt's + // output. + if (subprocess_run(argv, &subprocess_null, &subprocess_null, NULL) != 0) { + Warning("Cannot write '%s' back with flashrom.\n", region); + return 1; + } + return 0; +} + // Write "rw_gpt" back to NOR flash. We write the file in two parts for safety. // TODO(b:184812319): Replace this function with flashrom_write. int WriteNorFlash(const char *dir) { @@ -270,22 +272,11 @@ Error("Cannot change directory.\n"); goto out_free; } - const char *const argv1[] = {FLASHROM_PATH, "-i", FLASHROM_RW_GPT_PRI, - "-w", "--noverify-all"}; - // Redirect stdout to /dev/null so that flashrom does not muck up cgpt's - // output. - if (subprocess_run(argv1, &subprocess_null, &subprocess_null, NULL) != 0) { - Warning("Cannot write the 1st half of rw_gpt back with flashrom.\n"); + if (FlashromWriteRegion(FLASHROM_RW_GPT_PRI)) nr_fails++; - } - const char *const argv2[] = {FLASHROM_PATH, "-i", FLASHROM_RW_GPT_SEC, - "-w", "--noverify-all"}; - // Redirect stdout to /dev/null so that flashrom does not muck up cgpt's - // output. - if (subprocess_run(argv2, &subprocess_null, &subprocess_null, NULL) != 0) { - Warning("Cannot write the 2nd half of rw_gpt back with flashrom.\n"); + if (FlashromWriteRegion(FLASHROM_RW_GPT_SEC)) nr_fails++; - } + if (chdir(cwd) < 0) { Error("Cannot change directory back to original.\n"); goto out_free;
diff --git a/cgpt/cgpt_nor.h b/cgpt/cgpt_nor.h index 4746089..93e9dde 100644 --- a/cgpt/cgpt_nor.h +++ b/cgpt/cgpt_nor.h
@@ -23,10 +23,8 @@ // Exec "rm" to remove |dir|. int RemoveDir(const char *dir); -// Read RW_GPT from NOR flash to "rw_gpt" in a temp dir |temp_dir_template|. -// |temp_dir_template| is passed to mkdtemp() so it must satisfy all -// requirements by mkdtemp(). -int ReadNorFlash(char *temp_dir_template); +// Read RW_GPT from NOR flash to "rw_gpt" in dir. +int ReadNorFlash(const char *dir); // Write "rw_gpt" back to NOR flash. We write the file in two parts for safety. int WriteNorFlash(const char *dir);
diff --git a/cgpt/cgpt_wrapper.c b/cgpt/cgpt_wrapper.c index d26682d..17336c1 100644 --- a/cgpt/cgpt_wrapper.c +++ b/cgpt/cgpt_wrapper.c
@@ -82,9 +82,13 @@ // Create a temp dir to work in. ret++; char temp_dir[] = "/tmp/cgpt_wrapper.XXXXXX"; - if (ReadNorFlash(temp_dir) != 0) { + if (mkdtemp(temp_dir_template) == NULL) { + Error("Cannot create a temporary directory.\n"); return ret; } + if (ReadNorFlash(temp_dir) != 0) { + goto cleanup; + } char rw_gpt_path[PATH_MAX]; if (snprintf(rw_gpt_path, sizeof(rw_gpt_path), "%s/rw_gpt", temp_dir) < 0) { goto cleanup;
diff --git a/firmware/2lib/2api.c b/firmware/2lib/2api.c index c041d8a..13b3a69 100644 --- a/firmware/2lib/2api.c +++ b/firmware/2lib/2api.c
@@ -72,26 +72,21 @@ */ vb2_check_recovery(ctx); + /* Decide the boot mode */ + vb2_set_boot_mode(ctx); + /* - * Check for possible reasons to ask the firmware to make display - * available. VB2_CONTEXT_RECOVERY_MODE may have been set above by - * vb2_check_recovery. VB2_SD_FLAG_DEV_MODE_ENABLED may have been set - * above by vb2_check_dev_switch. VB2_NV_DIAG_REQUEST may have been - * set during the last boot in recovery mode. + * Initialize display if VB2_NV_DISPLAY_REQUEST is set or in non-normal + * boot mode. */ - if (!(ctx->flags & VB2_CONTEXT_DISPLAY_INIT) && - (vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST) || - sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED || - ctx->flags & VB2_CONTEXT_RECOVERY_MODE || - vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST))) + if (vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST) || + ctx->boot_mode != VB2_BOOT_MODE_NORMAL) ctx->flags |= VB2_CONTEXT_DISPLAY_INIT; + /* Mark display as available for downstream vboot and vboot callers. */ if (ctx->flags & VB2_CONTEXT_DISPLAY_INIT) sd->flags |= VB2_SD_FLAG_DISPLAY_AVAILABLE; - /* Decide the boot mode */ - vb2_set_boot_mode(ctx); - /* Return error if recovery is needed */ if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) { /* Always clear RAM when entering recovery mode */ @@ -370,3 +365,33 @@ { return vb2api_check_hash_get_digest(ctx, NULL, 0); } + +union vb2_fw_boot_info vb2api_get_fw_boot_info(struct vb2_context *ctx) +{ + union vb2_fw_boot_info info; + + struct vb2_shared_data *sd = vb2_get_sd(ctx); + + info.tries = vb2_nv_get(ctx, VB2_NV_TRY_COUNT); + info.slot = sd->fw_slot; + info.prev_slot = sd->last_fw_slot; + info.prev_result = sd->last_fw_result; + info.boot_mode = ctx->boot_mode; + + VB2_DEBUG("boot_mode=`%s`\n", vb2_boot_mode_string(info.boot_mode)); + + if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) { + info.recovery_reason = sd->recovery_reason; + info.recovery_subcode = vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE); + VB2_DEBUG("recovery_reason: %#x / %#x\n", + info.recovery_reason, info.recovery_subcode); + } + + VB2_DEBUG("fw_tried=`%s` fw_try_count=%d " + "fw_prev_tried=`%s` fw_prev_result=`%s`.\n", + vb2_slot_string(info.slot), info.tries, + vb2_slot_string(info.prev_slot), + vb2_result_string(info.prev_result)); + + return info; +}
diff --git a/firmware/2lib/2auxfw_sync.c b/firmware/2lib/2auxfw_sync.c index eaea1d4..76ad722 100644 --- a/firmware/2lib/2auxfw_sync.c +++ b/firmware/2lib/2auxfw_sync.c
@@ -48,12 +48,14 @@ return vb2ex_auxfw_check(severity); } +test_mockable vb2_error_t vb2api_auxfw_sync(struct vb2_context *ctx) { enum vb2_auxfw_update_severity fw_update = VB2_AUXFW_NO_UPDATE; /* Check for update severity */ - VB2_TRY(auxfw_sync_check_update(ctx, &fw_update)); + VB2_TRY(auxfw_sync_check_update(ctx, &fw_update), ctx, + VB2_RECOVERY_AUXFW_UPDATE); if (fw_update > VB2_AUXFW_NO_UPDATE) { VB2_DEBUG("Updating auxfw\n");
diff --git a/firmware/2lib/2ec_sync.c b/firmware/2lib/2ec_sync.c index e75313b..b1bc7eb 100644 --- a/firmware/2lib/2ec_sync.c +++ b/firmware/2lib/2ec_sync.c
@@ -338,6 +338,7 @@ return sync_ec(ctx); } +test_mockable vb2_error_t vb2api_ec_sync(struct vb2_context *ctx) { struct vb2_shared_data *sd = vb2_get_sd(ctx);
diff --git a/firmware/2lib/2kernel.c b/firmware/2lib/2kernel.c index 5b18cad..ff89e14 100644 --- a/firmware/2lib/2kernel.c +++ b/firmware/2lib/2kernel.c
@@ -5,94 +5,12 @@ * Kernel selection, loading, verification, and booting. */ +#include "2api.h" #include "2common.h" -#include "2kernel.h" #include "2misc.h" #include "2nvstorage.h" #include "2rsa.h" #include "2secdata.h" -#include "vboot_api.h" - -/** - * Reset any NVRAM requests. - * - * @param ctx Vboot context - * @return 1 if a reboot is required, 0 otherwise. - */ -static int vb2_reset_nv_requests(struct vb2_context *ctx) -{ - int need_reboot = 0; - - if (vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST)) { - VB2_DEBUG("Unset display request (undo display init)\n"); - vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 0); - need_reboot = 1; - } - - if (vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST)) { - VB2_DEBUG("Unset diagnostic request (undo display init)\n"); - vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 0); - need_reboot = 1; - } - - return need_reboot; -} - -vb2_error_t vb2_normal_boot(struct vb2_context *ctx) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - uint32_t max_rollforward = vb2_nv_get(ctx, - VB2_NV_KERNEL_MAX_ROLLFORWARD); - - /* Boot from fixed disk only */ - VB2_DEBUG("Entering\n"); - - if (vb2_reset_nv_requests(ctx)) { - VB2_DEBUG("Normal mode: reboot to reset NVRAM requests\n"); - return VB2_REQUEST_REBOOT; - } - - vb2_error_t rv = VbTryLoadKernel(ctx, VB_DISK_FLAG_FIXED); - - VB2_DEBUG("Checking if TPM kernel version needs advancing\n"); - - /* - * Special case for when we're trying a slot with new firmware. - * Firmware updates also usually change the kernel key, which means - * that the new firmware can only boot a new kernel, and the old - * firmware in the previous slot can only boot the previous kernel. - * - * Don't roll-forward the kernel version, because we don't yet know if - * the new kernel will successfully boot. - */ - if (vb2_nv_get(ctx, VB2_NV_FW_RESULT) == VB2_FW_RESULT_TRYING) { - VB2_DEBUG("Trying new FW; skip kernel version roll-forward.\n"); - return rv; - } - - /* - * Limit kernel version rollforward if needed. Can't limit kernel - * version to less than the version currently in the TPM. That is, - * we're limiting rollforward, not allowing rollback. - */ - if (max_rollforward < sd->kernel_version_secdata) - max_rollforward = sd->kernel_version_secdata; - - if (sd->kernel_version > max_rollforward) { - VB2_DEBUG("Limiting TPM kernel version roll-forward " - "to %#x < %#x\n", - max_rollforward, sd->kernel_version); - - sd->kernel_version = max_rollforward; - } - - if (sd->kernel_version > sd->kernel_version_secdata) { - vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS, - sd->kernel_version); - } - - return rv; -} int vb2api_is_developer_signed(struct vb2_context *ctx) { @@ -197,3 +115,165 @@ return VB2_SUCCESS; } + +static vb2_error_t handle_battery_cutoff(struct vb2_context *ctx) +{ + /* + * Check if we need to cut-off battery. This should be done after EC + * FW and auxfw are updated, and before the kernel is started. This + * is to make sure all firmware is up-to-date before shipping (which + * is the typical use-case for cutoff). + */ + if (vb2_nv_get(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST)) { + VB2_DEBUG("Request to cut-off battery\n"); + vb2_nv_set(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST, 0); + + /* May lose power immediately, so commit our update now. */ + VB2_TRY(vb2ex_commit_data(ctx)); + + vb2ex_ec_battery_cutoff(); + return VB2_REQUEST_SHUTDOWN; + } + + return VB2_SUCCESS; +} + +vb2_error_t vb2api_kernel_phase2(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + vb2_gbb_flags_t gbb_flags = vb2api_gbb_get_flags(ctx); + + VB2_DEBUG("GBB flags are %#x\n", gbb_flags); + + /* + * Do EC and auxfw software sync unless we're in recovery mode. This + * has UI but it's just a single non-interactive WAIT screen. + */ + if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + VB2_TRY(vb2api_ec_sync(ctx)); + VB2_TRY(vb2api_auxfw_sync(ctx)); + VB2_TRY(handle_battery_cutoff(ctx)); + } + + /* + * If in the broken screen, save the recovery reason as subcode. + * Otherwise, clear any leftover recovery requests or subcodes. + */ + vb2_clear_recovery(ctx); + + /* + * Clear the diagnostic request flag and commit nvdata to prevent + * booting back into diagnostic mode when a forced system reset occurs. + */ + if (vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST)) { + vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 0); + /* + * According to current FAFT design (firmware_MiniDiag), we + * need an AP reset after MiniDiag test items to preserve the + * CBMEM console logs. So we need to commit nvdata immediately + * to prevent booting back to VB2_BOOT_MODE_DIAGNOSTICS. + */ + vb2ex_commit_data(ctx); + } + + /* Select boot path */ + switch (ctx->boot_mode) { + case VB2_BOOT_MODE_MANUAL_RECOVERY: + case VB2_BOOT_MODE_BROKEN_SCREEN: + /* If we're in recovery mode just to do memory retraining, all + we need to do is reboot. */ + if (sd->recovery_reason == VB2_RECOVERY_TRAIN_AND_REBOOT) { + VB2_DEBUG("Reboot after retraining in recovery\n"); + return VB2_REQUEST_REBOOT; + } + + /* + * Need to commit nvdata changes immediately, since we will be + * entering either manual recovery UI or BROKEN screen shortly. + */ + vb2ex_commit_data(ctx); + break; + case VB2_BOOT_MODE_DIAGNOSTICS: + case VB2_BOOT_MODE_DEVELOPER: + break; + case VB2_BOOT_MODE_NORMAL: + if (vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST)) { + vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 0); + VB2_DEBUG("Normal mode: " + "reboot to unset display request\n"); + return VB2_REQUEST_REBOOT; + } + break; + default: + return VB2_ERROR_ESCAPE_NO_BOOT; + } + + return VB2_SUCCESS; +} + +static void update_kernel_version(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + uint32_t max_rollforward = + vb2_nv_get(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD); + + VB2_DEBUG("Checking if TPM kernel version needs advancing\n"); + + /* + * Special case for when we're trying a slot with new firmware. + * Firmware updates also usually change the kernel key, which means + * that the new firmware can only boot a new kernel, and the old + * firmware in the previous slot can only boot the previous kernel. + * + * Don't roll-forward the kernel version, because we don't yet know if + * the new kernel will successfully boot. + */ + if (vb2_nv_get(ctx, VB2_NV_FW_RESULT) == VB2_FW_RESULT_TRYING) { + VB2_DEBUG("Trying new FW; " + "skip kernel version roll-forward.\n"); + return; + } + + /* + * Limit kernel version rollforward if needed. Can't limit kernel + * version to less than the version currently in the TPM. That is, + * we're limiting rollforward, not allowing rollback. + */ + if (max_rollforward < sd->kernel_version_secdata) + max_rollforward = sd->kernel_version_secdata; + + if (sd->kernel_version > max_rollforward) { + VB2_DEBUG("Limiting TPM kernel version roll-forward " + "to %#x < %#x\n", + max_rollforward, sd->kernel_version); + + sd->kernel_version = max_rollforward; + } + + if (sd->kernel_version > sd->kernel_version_secdata) { + vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS, + sd->kernel_version); + } +} + +vb2_error_t vb2api_kernel_finalize(struct vb2_context *ctx) +{ + vb2_gbb_flags_t gbb_flags = vb2api_gbb_get_flags(ctx); + + /* + * Disallow booting to kernel when NO_BOOT flag is set, except when + * GBB flag disables software sync. + */ + if (!(gbb_flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC) + && (ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED) + && (ctx->flags & VB2_CONTEXT_NO_BOOT)) { + VB2_DEBUG("Blocking escape from NO_BOOT mode.\n"); + vb2api_fail(ctx, VB2_RECOVERY_ESCAPE_NO_BOOT, 0); + return VB2_ERROR_ESCAPE_NO_BOOT; + } + + if (ctx->boot_mode == VB2_BOOT_MODE_NORMAL) + update_kernel_version(ctx); + + return VB2_SUCCESS; +}
diff --git a/firmware/lib/vboot_kernel.c b/firmware/2lib/2load_kernel.c similarity index 95% rename from firmware/lib/vboot_kernel.c rename to firmware/2lib/2load_kernel.c index 1edf4a5..65e4053 100644 --- a/firmware/lib/vboot_kernel.c +++ b/firmware/2lib/2load_kernel.c
@@ -16,7 +16,6 @@ #include "cgptlib.h" #include "cgptlib_internal.h" #include "gpt_misc.h" -#include "load_kernel_fw.h" #include "vboot_api.h" enum vb2_load_partition_flags { @@ -348,7 +347,7 @@ * @return VB2_SUCCESS, or non-zero error code. */ static vb2_error_t vb2_load_partition( - struct vb2_context *ctx, VbSelectAndLoadKernelParams *params, + struct vb2_context *ctx, struct vb2_kernel_params *params, VbExStream_t stream, uint32_t lpflags) { uint32_t read_ms = 0, start_ts; @@ -462,8 +461,8 @@ } static vb2_error_t try_minios_kernel(struct vb2_context *ctx, - VbSelectAndLoadKernelParams *params, - VbDiskInfo *disk_info, + struct vb2_kernel_params *params, + struct vb2_disk_info *disk_info, uint64_t sector) { VbExStream_t stream; uint64_t sectors_left = disk_info->lba_count - sector; @@ -471,7 +470,7 @@ vb2_error_t rv = VB2_ERROR_LK_NO_KERNEL_FOUND; /* Re-open stream at correct offset to pass to vb2_load_partition. */ - if (VbExStreamOpen(params->disk_handle, sector, sectors_left, + if (VbExStreamOpen(disk_info->handle, sector, sectors_left, &stream)) { VB2_DEBUG("Unable to open disk handle.\n"); return rv; @@ -488,8 +487,8 @@ } static vb2_error_t try_minios_sectors(struct vb2_context *ctx, - VbSelectAndLoadKernelParams *params, - VbDiskInfo *disk_info, + struct vb2_kernel_params *params, + struct vb2_disk_info *disk_info, uint64_t start, uint64_t count) { const uint32_t buf_size = count * disk_info->bytes_per_lba; @@ -504,7 +503,7 @@ return rv; } - if (VbExStreamOpen(params->disk_handle, start, count, &stream)) { + if (VbExStreamOpen(disk_info->handle, start, count, &stream)) { VB2_DEBUG("Unable to open disk handle.\n"); free(buf); return rv; @@ -534,8 +533,8 @@ } static vb2_error_t try_minios_sector_region(struct vb2_context *ctx, - VbSelectAndLoadKernelParams *params, - VbDiskInfo *disk_info, + struct vb2_kernel_params *params, + struct vb2_disk_info *disk_info, int end_region) { const uint64_t disk_count_half = (disk_info->lba_count + 1) / 2; @@ -577,14 +576,15 @@ * the start and end of disks are considered, and the kernel must start exactly * at the first byte of the sector. */ -vb2_error_t LoadMiniOsKernel(struct vb2_context *ctx, - VbSelectAndLoadKernelParams *params, - VbDiskInfo *disk_info, uint32_t minios_flags) +vb2_error_t vb2api_load_minios_kernel(struct vb2_context *ctx, + struct vb2_kernel_params *params, + struct vb2_disk_info *disk_info, + uint32_t minios_flags) { vb2_error_t rv; int end_region_first = vb2_nv_get(ctx, VB2_NV_MINIOS_PRIORITY); - if (minios_flags & VB_MINIOS_FLAG_NON_ACTIVE) + if (minios_flags & VB2_MINIOS_FLAG_NON_ACTIVE) rv = VB2_ERROR_UNKNOWN; /* Ignore active partition */ else rv = try_minios_sector_region(ctx, params, disk_info, @@ -593,19 +593,16 @@ if (rv) rv = try_minios_sector_region(ctx, params, disk_info, !end_region_first); - if (rv) - return rv; - rv = vb2ex_tpm_set_mode(VB2_TPM_MODE_DISABLED); - if (rv) - VB2_DEBUG("Failed to disable TPM\n"); + if (rv == VB2_SUCCESS) + params->disk_handle = disk_info->handle; return rv; } -vb2_error_t LoadKernel(struct vb2_context *ctx, - VbSelectAndLoadKernelParams *params, - VbDiskInfo *disk_info) +vb2_error_t vb2api_load_kernel(struct vb2_context *ctx, + struct vb2_kernel_params *params, + struct vb2_disk_info *disk_info) { struct vb2_shared_data *sd = vb2_get_sd(ctx); int found_partitions = 0; @@ -621,7 +618,7 @@ gpt.streaming_drive_sectors = disk_info->streaming_lba_count ?: disk_info->lba_count; gpt.gpt_drive_sectors = disk_info->lba_count; - gpt.flags = disk_info->flags & VB_DISK_FLAG_EXTERNAL_GPT + gpt.flags = disk_info->flags & VB2_DISK_FLAG_EXTERNAL_GPT ? GPT_FLAG_EXTERNAL : 0; if (AllocAndReadGptData(disk_info->handle, &gpt)) { VB2_DEBUG("Unable to read GPT data\n"); @@ -754,6 +751,7 @@ /* Success! */ rv = VB2_SUCCESS; + params->disk_handle = disk_info->handle; } else if (found_partitions > 0) { rv = VB2_ERROR_LK_INVALID_KERNEL_FOUND; } else {
diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c index 6e92690..5735127 100644 --- a/firmware/2lib/2misc.c +++ b/firmware/2lib/2misc.c
@@ -520,6 +520,7 @@ VB2_SECDATA_KERNEL_FLAG_PHONE_RECOVERY_UI_DISABLED); } +test_mockable int vb2api_diagnostic_ui_enabled(struct vb2_context *ctx) { return !(vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_FLAGS) &
diff --git a/firmware/2lib/2recovery_reasons.c b/firmware/2lib/2recovery_reasons.c index 8c43dce..73fd812 100644 --- a/firmware/2lib/2recovery_reasons.c +++ b/firmware/2lib/2recovery_reasons.c
@@ -113,7 +113,7 @@ /* 0x46 */ case VB2_RECOVERY_RW_SHARED_DATA: return "Shared data error in rewritable firmware"; /* 0x47 */ case VB2_RECOVERY_DEPRECATED_RW_TEST_LK: - return "Test error from LoadKernel()"; + return "Test error from vb2api_load_kernel()"; /* 0x48 */ case VB2_RECOVERY_DEPRECATED_RW_NO_DISK: return "No bootable storage device in system"; /* 0x49 */ case VB2_RECOVERY_TPM_E_FAIL:
diff --git a/firmware/2lib/2rsa.c b/firmware/2lib/2rsa.c index dcd8bad..eb07b04 100644 --- a/firmware/2lib/2rsa.c +++ b/firmware/2lib/2rsa.c
@@ -14,7 +14,6 @@ #include "2rsa_private.h" #include "2sha.h" #include "2sysincludes.h" -#include "vboot_test.h" /** * a[] -= mod
diff --git a/firmware/2lib/2secdata_kernel.c b/firmware/2lib/2secdata_kernel.c index 0d4208f..754552c 100644 --- a/firmware/2lib/2secdata_kernel.c +++ b/firmware/2lib/2secdata_kernel.c
@@ -11,7 +11,6 @@ #include "2secdata.h" #include "2secdata_struct.h" #include "2sysincludes.h" -#include "vboot_test.h" #define MAJOR_VER(x) (((x) & 0xf0) >> 4) #define MINOR_VER(x) ((x) & 0x0f) @@ -181,6 +180,7 @@ return VB2_SUCCESS; } +test_mockable uint32_t vb2_secdata_kernel_get(struct vb2_context *ctx, enum vb2_secdata_kernel_param param) { @@ -213,6 +213,7 @@ return 0; } +test_mockable void vb2_secdata_kernel_set(struct vb2_context *ctx, enum vb2_secdata_kernel_param param, uint32_t value) @@ -273,6 +274,7 @@ VB2_REC_OR_DIE(ctx, "%s\n", msg); } +test_mockable const uint8_t *vb2_secdata_kernel_get_ec_hash(struct vb2_context *ctx) { struct vb2_shared_data *sd = vb2_get_sd(ctx);
diff --git a/firmware/2lib/2stub.c b/firmware/2lib/2stub.c index da754ad..51d2eb2 100644 --- a/firmware/2lib/2stub.c +++ b/firmware/2lib/2stub.c
@@ -38,11 +38,12 @@ } __attribute__((weak)) -uint32_t vb2ex_mtime(void) +vb2_error_t vb2ex_commit_data(struct vb2_context *ctx) { - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * VB2_MSEC_PER_SEC + tv.tv_usec / VB2_USEC_PER_MSEC; + ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED; + ctx->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED; + ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED; + return VB2_SUCCESS; } __attribute__((weak)) @@ -159,105 +160,17 @@ } /*****************************************************************************/ -/* UI-related stubs */ +/* Timer-related stubs */ __attribute__((weak)) -const char *vb2ex_get_debug_info(struct vb2_context *ctx) +uint32_t vb2ex_mtime(void) { - return NULL; -} - -__attribute__((weak)) -const char *vb2ex_get_firmware_log(int reset) -{ - return NULL; -} - -__attribute__((weak)) -vb2_error_t vb2ex_diag_get_storage_health(const char **out) -{ - *out = "mock"; - return VB2_SUCCESS; -} - -__attribute__((weak)) -vb2_error_t vb2ex_diag_get_storage_test_log(const char **out) -{ - *out = "mock"; - return VB2_SUCCESS; -} - -__attribute__((weak)) -vb2_error_t vb2ex_diag_memory_quick_test(int reset, const char **out) -{ - *out = "mock"; - return VB2_SUCCESS; -} - -__attribute__((weak)) -vb2_error_t vb2ex_diag_memory_full_test(int reset, const char **out) -{ - *out = "mock"; - return VB2_SUCCESS; + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * VB2_MSEC_PER_SEC + tv.tv_usec / VB2_USEC_PER_MSEC; } __attribute__((weak)) void vb2ex_msleep(uint32_t msec) { } - -__attribute__((weak)) -void vb2ex_beep(uint32_t msec, uint32_t frequency) -{ -} - -__attribute__((weak)) -uint32_t vb2ex_get_locale_count(void) -{ - return 0; -} - -__attribute__((weak)) -uint32_t vb2ex_get_altfw_count(void) -{ - return 0; -} - -__attribute__((weak)) -int vb2ex_physical_presence_pressed(void) -{ - return 0; -} - -__attribute__((weak)) -vb2_error_t vb2ex_commit_data(struct vb2_context *ctx) -{ - ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED; - ctx->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED; - ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED; - return VB2_SUCCESS; -} - -__attribute__((weak)) -vb2_error_t vb2ex_broken_screen_ui(struct vb2_context *ctx) -{ - return VB2_SUCCESS; -} - -__attribute__((weak)) -vb2_error_t vb2ex_manual_recovery_ui(struct vb2_context *ctx) -{ - return VB2_SUCCESS; -} - -__attribute__((weak)) -vb2_error_t vb2ex_developer_ui(struct vb2_context *ctx) -{ - return VB2_SUCCESS; -} - -__attribute__((weak)) -vb2_error_t vb2ex_diagnostic_ui(struct vb2_context *ctx) -{ - return VB2_SUCCESS; -}
diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index 1430111..79283c2 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h
@@ -24,6 +24,7 @@ #include "2fw_hash_tags.h" #include "2gbb_flags.h" #include "2id.h" +#include "2info.h" #include "2recovery_reasons.h" #include "2return_codes.h" #include "2rsa.h" @@ -165,14 +166,14 @@ /* * System supports EC software sync. Caller may set this flag at any - * time before calling VbSelectAndLoadKernel(). + * time before calling vb2api_kernel_phase2(). */ VB2_CONTEXT_EC_SYNC_SUPPORTED = (1 << 15), /* * EC software sync is slow to update; warning screen should be * displayed. Caller may set this flag at any time before calling - * VbSelectAndLoadKernel(). Deprecated as part of chromium:1038259. + * vb2api_kernel_phase2(). Deprecated as part of chromium:1038259. */ VB2_CONTEXT_DEPRECATED_EC_SYNC_SLOW = (1 << 16), @@ -257,58 +258,12 @@ * nvdata, FWMP or GBB flags. */ VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED = (1 << 27), -}; - -/* Boot mode decided in vb2api_fw_phase1. - * - * Boot mode is a constant set by verified boot and may be read (but should not - * be set or cleared) by the caller. - * The boot modes are mutually exclusive. If a boot fulfill more than one - * constraints of the listing boot modes, it will be set to the most important - * one. The priority is the same as the listing order. - */ -enum vb2_boot_mode { - /* Undefined, The boot mode is not set. */ - VB2_BOOT_MODE_UNDEFINED = 0, /* - * Manual recovery boot, regardless of dev mode state. - * - * VB2_CONTEXT_RECOVERY_MODE is set and the recovery is physically - * requested (a.k.a. Manual recovery). All other recovery requests - * including manual recovery requested by a (compromised) host will end - * up with a broken screen. + * If this is set after kernel verification, caller should disable the + * TPM before jumping to kernel. */ - VB2_BOOT_MODE_MANUAL_RECOVERY = 1, - - /* - * Broken screen. - * - * If a recovery boot is not a manual recovery (a.k.a. not requested - * physically), the recovery is not allowed and will end up with - * broken screen. - */ - VB2_BOOT_MODE_BROKEN_SCREEN = 2, - - /* - * Diagnostic boot. - * - * If diagnostic boot is enabled (a.k.a. vb2api_diagnostic_ui_enabled) - * and the nvdata contains VB2_NV_DIAG_REQUEST from previous boot, it - * will boot to diagnostic mode. - */ - VB2_BOOT_MODE_DIAGNOSTICS = 3, - - /* - * Developer boot: self-signed kernel okay. - * - * The developer mode switch is set (a.k.a. VB2_CONTEXT_DEVELOPER_MODE) - * and we are in the developer boot mode. - */ - VB2_BOOT_MODE_DEVELOPER = 4, - - /* Normal boot: kernel must be verified. */ - VB2_BOOT_MODE_NORMAL = 5, + VB2_CONTEXT_DISABLE_TPM = (1 << 28), }; /* Helper for aligning fields in vb2_context. */ @@ -391,10 +346,10 @@ */ /* - * Mutually exclusive boot mode. + * Mutually exclusive boot mode (from enum vb2_boot_mode). * This constant is initialized after calling vb2api_fw_phase1(). */ - const enum vb2_boot_mode boot_mode; + const uint8_t boot_mode; }; /* Resource index for vb2ex_read_resource() */ @@ -506,7 +461,8 @@ * use to verify kernel data - the recovery key from the GBB, or the * kernel subkey from the firmware verification stage. * - * Kernel phase 2 is finding loading, and verifying the kernel partition. + * Call vb2api_kernel_phase2(). Do EC and auxfw software sync, clear + * recovery and commit nvdata if needed. * * Find a boot device (you're on your own here). * @@ -812,6 +768,142 @@ vb2_error_t vb2api_kernel_phase1(struct vb2_context *ctx); /** + * Do kernel verification. + * + * Must be called after vb2api_kernel_phase1. + * + * @param ctx Vboot context + * @return VB2_SUCCESS, or error code on error. + */ +vb2_error_t vb2api_kernel_phase2(struct vb2_context *ctx); + +/** + * Finalize for kernel verification stage. + * + * Handle NO_BOOT flag. Also, check and roll forward kernel version. + * + * @param ctx Vboot context + * @return VB2_SUCCESS, or error code on error. + */ +vb2_error_t vb2api_kernel_finalize(struct vb2_context *ctx); + +struct vb2_kernel_params { + /* Inputs to vb2api_load_kernel(). */ + /* Destination buffer for kernel (normally at 0x100000 on x86). */ + void *kernel_buffer; + /* Size of kernel buffer in bytes. */ + uint32_t kernel_buffer_size; + + /* + * Outputs from vb2api_load_kernel(); valid only if it returns success. + */ + /* Handle of disk containing loaded kernel. */ + vb2ex_disk_handle_t disk_handle; + /* Partition number on disk to boot (1...M). */ + uint32_t partition_number; + /* Address of bootloader image in RAM. */ + uint64_t bootloader_address; + /* Size of bootloader image in bytes. */ + uint32_t bootloader_size; + /* UniquePartitionGuid for boot partition. */ + uint8_t partition_guid[16]; + /* Flags set by signer. */ + uint32_t flags; +}; + +/*****************************************************************************/ +/* Disk access */ + +/* Flags for vb2_disk_info */ + +/* + * Disk selection in the lower 16 bits (where the disk lives), and disk + * attributes in the higher 16 bits (extra information about the disk + * needed to access it correctly). + */ +#define VB2_DISK_FLAG_SELECT_MASK 0xffff +#define VB2_DISK_FLAG_ATTRIBUTE_MASK (0xffff << 16) + +/* + * Disks are used in two ways: + * - As a random-access device to read and write the GPT + * - As a streaming device to read the kernel + * These are implemented differently on raw NAND vs eMMC/SATA/USB + * - On eMMC/SATA/USB, both of these refer to the same underlying + * storage, so they have the same size and LBA size. In this case, + * the GPT should not point to the same address as itself. + * - On raw NAND, the GPT is held on a portion of the SPI flash. + * Random access GPT operations refer to the SPI and streaming + * operations refer to NAND. The GPT may therefore point into + * the same offsets as itself. + * These types are distinguished by the following flag and vb2_disk_info + * has separate fields to describe the random-access ("GPT") and + * streaming aspects of the disk. If a disk is random-access (i.e. + * not raw NAND) then these fields are equal. + */ +#define VB2_DISK_FLAG_EXTERNAL_GPT (1 << 16) + +/* Information on a single disk. */ +struct vb2_disk_info { + /* Disk handle. */ + vb2ex_disk_handle_t handle; + /* Size of a random-access LBA sector in bytes. */ + uint64_t bytes_per_lba; + /* Number of random-access LBA sectors on the device. + * If streaming_lba_count is 0, this stands in for the size of the + * randomly accessed portion as well as the streaming portion. + * Otherwise, this is only the randomly-accessed portion. */ + uint64_t lba_count; + /* Number of streaming sectors on the device. */ + uint64_t streaming_lba_count; + /* Flags (see VB2_DISK_FLAG_* constants). */ + uint32_t flags; + /* + * Optional name string, for use in debugging. May be empty or null if + * not available. + */ + const char *name; +}; + +/** + * Attempt to load kernel from the specified device. On success, the output + * fields of params will be filled. The caller should set the input fields of + * params. + * + * + * @param ctx Vboot context + * @param params Params specific to loading the kernel + * @param disk_info Disk from which to read kernel + * + * @return VB2_SUCCESS, or non-zero error code. + */ +vb2_error_t vb2api_load_kernel(struct vb2_context *ctx, + struct vb2_kernel_params *params, + struct vb2_disk_info *disk_info); + +/* miniOS flags */ + +/* Boot from non-active miniOS partition only. */ +#define VB2_MINIOS_FLAG_NON_ACTIVE (1 << 0) + +/** + * Attempt to load miniOS kernel from the specified device. On success, the + * output fields of params will be filled. The caller should set the input + * fields of params. + * + * @param ctx Vboot context + * @param params Params specific to loading the kernel + * @param disk_info Disk from which to read kernel + * @param minios_flags Flags for miniOS + * + * @return VB2_SUCCESS, or non-zero error code. + */ +vb2_error_t vb2api_load_minios_kernel(struct vb2_context *ctx, + struct vb2_kernel_params *params, + struct vb2_disk_info *disk_info, + uint32_t minios_flags); + +/** * Load the verified boot block (vblock) for a kernel. * * This function may be called multiple times, to load and verify the @@ -1027,7 +1119,7 @@ vb2_error_t vb2api_enable_developer_mode(struct vb2_context *ctx); /** - * Request to disable developer mode by setting VB2_NV_DIAG_REQUEST. + * Request to disable developer mode by setting VB2_NV_DISABLE_DEV_REQUEST. * * @param ctx Vboot context * @return VB2_SUCCESS if success; other errors if the check of @@ -1433,124 +1525,7 @@ vb2_error_t vb2ex_ec_battery_cutoff(void); /*****************************************************************************/ -/* Functions for UI display. */ - -/** - * UI for a non-manual recovery ("BROKEN"). - * - * Enter the broken screen UI, which shows that an unrecoverable error was - * encountered last boot. Wait for the user to physically reset or shut down. - * - * @param ctx Vboot context - * @return VB2_SUCCESS, or non-zero error code. - */ -vb2_error_t vb2ex_broken_screen_ui(struct vb2_context *ctx); - -/** - * UI for a manual recovery-mode boot. - * - * Enter the recovery menu, which prompts the user to insert recovery media, - * navigate the step-by-step recovery, or enter developer mode if allowed. - * - * @param ctx Vboot context - * @return VB2_SUCCESS, or non-zero error code. - */ -vb2_error_t vb2ex_manual_recovery_ui(struct vb2_context *ctx); - -/** - * UI for a developer-mode boot. - * - * Enter the developer menu, which provides options to switch out of developer - * mode, boot from external media, use legacy bootloader, or boot Chrome OS from - * disk. - * - * If a timeout occurs, take the default boot action. - * - * @param ctx Vboot context - * @return VB2_SUCCESS, or non-zero error code. - */ -vb2_error_t vb2ex_developer_ui(struct vb2_context *ctx); - -/** - * UI for a diagnostic tools boot. - * - * Enter the diagnostic tools menu, which provides debug information and - * diagnostic tests of various hardware components. - * - * @param ctx Vboot context - * @return VB2_SUCCESS, or non-zero error code. - */ -vb2_error_t vb2ex_diagnostic_ui(struct vb2_context *ctx); - -/* Helpers for bitmask operations */ -#define VB2_SET_BIT(mask, index) ((mask) |= ((uint32_t)1 << (index))) -#define VB2_CLR_BIT(mask, index) ((mask) &= ~((uint32_t)1 << (index))) -#define VB2_GET_BIT(mask, index) ((mask) & ((uint32_t)1 << (index))) - -/** - * Check that physical presence button is currently pressed by the user. - * - * @return 1 for pressed, 0 for not. - */ -int vb2ex_physical_presence_pressed(void); - -/** - * Get the number of supported locales. - * - * @return Number of locales. 0 if none or on error. - */ -uint32_t vb2ex_get_locale_count(void); - -/** - * Return the number of available alternate bootloaders. - * - * @return Number of alternate bootloaders. 0 if none or on error. - */ -uint32_t vb2ex_get_altfw_count(void); - -/** - * Run alternate bootloader. - * - * @param altfw_id ID of alternate bootloader to run, where - * altfw_id <= vb2ex_get_altfw_count(). 0 for default, - * which corresponds to an alternate bootloader in - * the range 1 <= altfw_id <= vb2ex_getfw_count(). - * @return VB2_SUCCESS, or error code on error. - */ -vb2_error_t vb2ex_run_altfw(uint32_t altfw_id); - -/** - * Delay for at least the specified number of milliseconds. - * - * @param msec Duration in milliseconds. - */ -void vb2ex_msleep(uint32_t msec); - -/** - * Play a beep tone of the specified frequency in Hz for the duration msec. - * - * This is effectively a sleep call that makes noise. The implementation may - * beep at a fixed frequency if frequency support is not available. Regardless - * of whether any errors occur, the callback is expected to delay for the - * specified duration before returning. - * - * @param msec Duration of beep in milliseconds. - * @param frequency Sound frequency in Hz. - */ -void vb2ex_beep(uint32_t msec, uint32_t frequency); - -/** - * Get the full debug info string. - * - * Return a pointer to the full debug info string which is guaranteed to be - * null-terminated. The function implementation should manage string memory - * internally. Subsequent calls may update the string and return the same - * pointer, or return a new pointer if necessary. - * - * @param ctx Vboot context - * @return The pointer to the full debug info string. NULL on error. - */ -const char *vb2ex_get_debug_info(struct vb2_context *ctx); +/* Functions for firmware UI. */ /** * Get the vboot debug info. @@ -1564,67 +1539,6 @@ */ char *vb2api_get_debug_info(struct vb2_context *ctx); -/** - * Get the full firmware log string. - * - * Return a pointer to the full firmware log string which is guaranteed to be - * null-terminated. The function implementation should snapshot the full - * firmware log when it is called. If `reset` is not zero, it will reset the - * firmware log snapshot. - * - * @param reset Discard the current firmware log snapshot and - * reacquire a new one. - * @return The pointer to the full firmware log string. NULL on error. - */ -const char *vb2ex_get_firmware_log(int reset); - -/** - * Get the health info of the storage. - * - * @param out For returning a read-only pointer of full log string which is - * guaranteed to be null-terminated. The function will manage - * memory internally, so the returned pointer will only be valid - * until next call. - * @return VB2_SUCCESS, or error code on error. - */ -vb2_error_t vb2ex_diag_get_storage_health(const char **out); - -/** - * Get the storage self-test log. - * - * @param out For returning a read-only pointer of full log string which is - * guaranteed to be null-terminated. The function will manage - * memory internally, so the returned pointer will only be valid - * until next call. - * @return The status of storage test. VB2_SUCCESS means the test is finished, - * regardless of passing or failing. VB2_ERROR_EX_DIAG_TEST_RUNNING means - * the test is still running. VB2_ERROR_EX_UNIMPLEMENTED means the storage - * self-test is not supported on this device. Other non-zero codes for internal - * errors. - */ -vb2_error_t vb2ex_diag_get_storage_test_log(const char **out); - -/** - * Get the memory diagnostic status. When it is called, it will take over the - * control for a short period of time running memory test, and then return the - * result of current status. If `reset` is not zero, it will reset the memory - * test state. - * - * @param reset Discard the current memory test result and re-initialize - * a new test. - * @param out For returning a read-only pointer of full log string which is - * guaranteed to be null-terminated. The function will manage - * memory internally, so the returned pointer will only be valid - * until next call. - * @return The status of memory test. VB2_SUCCESS means the test is finished, - * regardless of passing or failing. VB2_ERROR_EX_DIAG_TEST_RUNNING means - * the test is still running but the output buffer was unchanged. - * VB2_ERROR_EX_DIAG_TEST_UPDATED means the test is still running and the output - * buffer was updated. Other non-zero codes for internal errors. - */ -vb2_error_t vb2ex_diag_memory_quick_test(int reset, const char **out); -vb2_error_t vb2ex_diag_memory_full_test(int reset, const char **out); - /*****************************************************************************/ /* Timer. */ @@ -1638,4 +1552,37 @@ */ uint32_t vb2ex_mtime(void); +/** + * Delay for at least the specified number of milliseconds. + * + * @param msec Duration in milliseconds. + */ +void vb2ex_msleep(uint32_t msec); + +union vb2_fw_boot_info { + uint8_t raw[4]; + struct { + uint8_t tries : 4; + uint8_t slot : 1; + uint8_t prev_slot : 1; + uint8_t prev_result : 2; + uint8_t boot_mode; + /* The following 2 bytes only exist for recovery mode */ + uint8_t recovery_reason; + uint8_t recovery_subcode; + }; +}; + +/** + * Return `vb2_fw_boot_info` and can be used + * to log information about the current boot in a compact format. + * + * Note: Only call this API at minimum after `vb2api_fw_phase2` function + * returns. + * + * @param ctx Vboot context + * @return filled out vb2 info as per `union vb2_fw_boot_info`. + */ +union vb2_fw_boot_info vb2api_get_fw_boot_info(struct vb2_context *ctx); + #endif /* VBOOT_REFERENCE_2API_H_ */
diff --git a/firmware/2lib/include/2constants.h b/firmware/2lib/include/2constants.h index 96dc999..c1e6bb9 100644 --- a/firmware/2lib/include/2constants.h +++ b/firmware/2lib/include/2constants.h
@@ -80,6 +80,14 @@ #ifndef __ASSEMBLER__ #include <stdint.h> typedef uint32_t vb2_gbb_flags_t; +/* + * We use disk handles rather than indices. Using indices causes problems if + * a disk is removed/inserted in the middle of processing. + * + * TODO(b/181739551): move this to 2api.h when the VbExDisk* functions are + * removed from vboot_api.h. + */ +typedef void *vb2ex_disk_handle_t; #endif /* Size of legacy VbSharedDataHeader struct. Defined here to avoid including
diff --git a/firmware/2lib/include/2info.h b/firmware/2lib/include/2info.h new file mode 100644 index 0000000..be2ea60 --- /dev/null +++ b/firmware/2lib/include/2info.h
@@ -0,0 +1,146 @@ +/* Copyright 2022 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. + * + * Helper functions to retrieve vboot firmware information. + */ + +#ifndef VBOOT_REFERENCE_2INFO_H_ +#define VBOOT_REFERENCE_2INFO_H_ + +/* Boot mode decided in vb2api_fw_phase1. + * + * Boot mode is a constant set by verified boot and may be read (but should not + * be set or cleared) by the caller. + * The boot modes are mutually exclusive. If a boot fulfill more than one + * constraints of the listing boot modes, it will be set to the most important + * one. The priority is the same as the listing order. + */ +enum vb2_boot_mode { + /* Undefined, The boot mode is not set. */ + VB2_BOOT_MODE_UNDEFINED = 0, + + /* + * Manual recovery boot, regardless of dev mode state. + * + * VB2_CONTEXT_RECOVERY_MODE is set and the recovery is physically + * requested (a.k.a. Manual recovery). All other recovery requests + * including manual recovery requested by a (compromised) host will end + * up with a broken screen. + */ + VB2_BOOT_MODE_MANUAL_RECOVERY = 1, + + /* + * Broken screen. + * + * If a recovery boot is not a manual recovery (a.k.a. not requested + * physically), the recovery is not allowed and will end up with + * broken screen. + */ + VB2_BOOT_MODE_BROKEN_SCREEN = 2, + + /* + * Diagnostic boot. + * + * If diagnostic boot is enabled (a.k.a. vb2api_diagnostic_ui_enabled) + * and the nvdata contains VB2_NV_DIAG_REQUEST from previous boot, it + * will boot to diagnostic mode. + */ + VB2_BOOT_MODE_DIAGNOSTICS = 3, + + /* + * Developer boot: self-signed kernel okay. + * + * The developer mode switch is set (a.k.a. VB2_CONTEXT_DEVELOPER_MODE) + * and we are in the developer boot mode. + */ + VB2_BOOT_MODE_DEVELOPER = 4, + + /* Normal boot: kernel must be verified. */ + VB2_BOOT_MODE_NORMAL = 5, +}; + +/* Firmware slot codes */ +enum vb2_fw_slot { + /* Slot A */ + VB2_FW_SLOT_A = 0, + + /* Slot B */ + VB2_FW_SLOT_B = 1, +}; + +/* Firmware result codes for VB2_NV_FW_RESULT and VB2_NV_FW_PREV_RESULT */ +enum vb2_fw_result { + /* Unknown */ + VB2_FW_RESULT_UNKNOWN = 0, + + /* Trying a new slot, but haven't reached success/failure */ + VB2_FW_RESULT_TRYING = 1, + + /* Successfully booted to the OS */ + VB2_FW_RESULT_SUCCESS = 2, + + /* Known failure */ + VB2_FW_RESULT_FAILURE = 3, +}; + +/** + * Convert Firmware Boot Mode into supported string + * + * @return char* firmware boot mode string + */ +static inline const char *vb2_boot_mode_string(uint8_t boot_mode) +{ + switch ((enum vb2_boot_mode)boot_mode) { + /* 0x00 */ case VB2_BOOT_MODE_UNDEFINED: + return "Undefined"; + /* 0x01 */ case VB2_BOOT_MODE_MANUAL_RECOVERY: + return "Manual recovery"; + /* 0x02 */ case VB2_BOOT_MODE_BROKEN_SCREEN: + return "Broken screen"; + /* 0x03 */ case VB2_BOOT_MODE_DIAGNOSTICS: + return "Diagnostic"; + /* 0x04 */ case VB2_BOOT_MODE_DEVELOPER: + return "Developer"; + /* 0x05 */ case VB2_BOOT_MODE_NORMAL: + return "Secure"; + } + + return "Unknown"; +} + +/** + * Convert Firmware Slot result into supported string + * + * @return char* firmware slot result string + */ +static inline const char *vb2_result_string(uint8_t result) +{ + switch ((enum vb2_fw_result)result) { + /* 0x00 */ case VB2_FW_RESULT_UNKNOWN: + return "Unknown"; + /* 0x01 */ case VB2_FW_RESULT_TRYING: + return "Trying"; + /* 0x02 */ case VB2_FW_RESULT_SUCCESS: + return "Success"; + /* 0x03 */ case VB2_FW_RESULT_FAILURE: + return "Failure"; + } + + return "Unknown"; +} + +/** + * Convert Firmware Slot into supported string + * + * @return char* firmware slot name string + */ +static inline const char *vb2_slot_string(uint8_t slot) +{ + if ((enum vb2_fw_slot)slot == VB2_FW_SLOT_A) + /* 0x00 */ return "A"; + else + /* 0x01 */ return "B"; +} + +#endif /* VBOOT_REFERENCE_2INFO_H_ */
diff --git a/firmware/2lib/include/2kernel.h b/firmware/2lib/include/2kernel.h deleted file mode 100644 index bed1a01..0000000 --- a/firmware/2lib/include/2kernel.h +++ /dev/null
@@ -1,21 +0,0 @@ -/* Copyright 2020 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. - * - * Kernel selection, loading, verification, and booting. - */ - -#ifndef VBOOT_REFERENCE_2KERNEL_H_ -#define VBOOT_REFERENCE_2KERNEL_H_ - -#include "2common.h" - -/** - * Handle a normal boot. - * - * @param ctx Vboot context. - * @return VB2_SUCCESS, or error code on error. - */ -vb2_error_t vb2_normal_boot(struct vb2_context *ctx); - -#endif /* VBOOT_REFERENCE_2KERNEL_H_ */
diff --git a/firmware/2lib/include/2nvstorage.h b/firmware/2lib/include/2nvstorage.h index fe75823..a457250 100644 --- a/firmware/2lib/include/2nvstorage.h +++ b/firmware/2lib/include/2nvstorage.h
@@ -129,21 +129,6 @@ VB2_NV_MINIOS_PRIORITY, }; -/* Firmware result codes for VB2_NV_FW_RESULT and VB2_NV_FW_PREV_RESULT */ -enum vb2_fw_result { - /* Unknown */ - VB2_FW_RESULT_UNKNOWN = 0, - - /* Trying a new slot, but haven't reached success/failure */ - VB2_FW_RESULT_TRYING = 1, - - /* Successfully booted to the OS */ - VB2_FW_RESULT_SUCCESS = 2, - - /* Known failure */ - VB2_FW_RESULT_FAILURE = 3, -}; - /* * Default value for VB2_NV_FIRMWARE_MAX_ROLLFORWARD on V1. This preserves the * existing behavior that V1 systems will always roll forward the firmware
diff --git a/firmware/2lib/include/2recovery_reasons.h b/firmware/2lib/include/2recovery_reasons.h index 30dbd2e..918e332 100644 --- a/firmware/2lib/include/2recovery_reasons.h +++ b/firmware/2lib/include/2recovery_reasons.h
@@ -205,7 +205,7 @@ /* Shared data error in rewritable firmware */ VB2_RECOVERY_RW_SHARED_DATA = 0x46, - /* Test error from LoadKernel() (deprecated) */ + /* Test error from vb2api_load_kernel() (deprecated) */ VB2_RECOVERY_DEPRECATED_RW_TEST_LK = 0x47, /* No bootable disk found (deprecated, see 0x5a) */
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h index 176c2c6..a7b7930 100644 --- a/firmware/2lib/include/2return_codes.h +++ b/firmware/2lib/include/2return_codes.h
@@ -754,29 +754,32 @@ * Deprecated: functionality removed with legacy UI (b/167643628) */ VB2_ERROR_DEPRECATED_EX_SET_VENDOR_DATA, - /* The memory test is running but the output buffer was unchanged. */ - VB2_ERROR_EX_DIAG_TEST_RUNNING, + /* The memory test is running but the output buffer was unchanged. + Deprecated with b/172339016. */ + VB2_ERROR_DEPRECATED_EX_DIAG_TEST_RUNNING, - /* The memory test is running and the output buffer was updated. */ - VB2_ERROR_EX_DIAG_TEST_UPDATED, + /* The memory test is running and the output buffer was updated. + Deprecated with b/172339016. */ + VB2_ERROR_DEPRECATED_EX_DIAG_TEST_UPDATED, - /* The memory test initialization failed. */ - VB2_ERROR_EX_DIAG_TEST_INIT_FAILED, + /* The memory test initialization failed. + Deprecated with b/172339016. */ + VB2_ERROR_DEPRECATED_EX_DIAG_TEST_INIT_FAILED, /********************************************************************** - * LoadKernel errors + * Kernel loading errors * * Should be ordered by specificity -- lower number means more specific. */ VB2_ERROR_LK = 0x100b0000, - /* Only an invalid kernel was found in LoadKernel() */ + /* Only an invalid kernel was found in vb2api_load_kernel() */ VB2_ERROR_LK_INVALID_KERNEL_FOUND = 0x100b1000, - /* No kernel partitions were found in LoadKernel() */ + /* No kernel partitions were found in vb2api_load_kernel() */ VB2_ERROR_LK_NO_KERNEL_FOUND = 0x100b2000, - /* No working block devices were found in VbTryLoadKernel() */ + /* No working block devices were found */ VB2_ERROR_LK_NO_DISK_FOUND = 0x100b3000, /********************************************************************** @@ -843,6 +846,9 @@ /* Flashrom exited with failure status */ VB2_ERROR_FLASHROM, + /* cbfstool exited with failure status */ + VB2_ERROR_CBFSTOOL, + /********************************************************************** * Errors generated by host library key functions */
diff --git a/firmware/include/gpt_misc.h b/firmware/include/gpt_misc.h index aa46094..e01e0dc 100644 --- a/firmware/include/gpt_misc.h +++ b/firmware/include/gpt_misc.h
@@ -76,9 +76,8 @@ * depthcharge does not have logic to properly setup stored_on_device and * gpt_drive_sectors, but it does do a memset(gpt, 0, sizeof(GptData)). And so, * GPT_STORED_ON_DEVICE should be 0 to make stored_on_device compatible with - * present behavior. At the same time, in vboot_kernel:LoadKernel(), and - * cgpt_common:GptLoad(), we need to have simple shims to set gpt_drive_sectors - * to drive_sectors. + * present behavior. At the same time, in vb2api_load_kernel() and GptLoad(), + * we need to have simple shims to set gpt_drive_sectors to drive_sectors. * * TODO(namnguyen): Remove those shims when the firmware can set these fields. */ @@ -157,12 +156,12 @@ * * Returns 0 if successful, 1 if error. */ -int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata); +int AllocAndReadGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata); /** * Write any changes for the GPT data back to the drive, then free the buffers. */ -int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata); +int WriteAndFreeGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata); /** * Return 1 if the entry is unused, 0 if it is used.
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h index ce3ac2d..c2fc0ad 100644 --- a/firmware/include/vboot_api.h +++ b/firmware/include/vboot_api.h
@@ -24,6 +24,7 @@ #include <stdint.h> #include <stdlib.h> +#include "../2lib/include/2constants.h" #include "../2lib/include/2return_codes.h" #include "gpt.h" @@ -32,192 +33,12 @@ #endif /* __cplusplus */ struct vb2_context; +struct vb2_disk_info; typedef struct VbSharedDataHeader VbSharedDataHeader; - -/*****************************************************************************/ -/* Main entry points from firmware into vboot_reference */ - -/* - * We use disk handles rather than indices. Using indices causes problems if - * a disk is removed/inserted in the middle of processing. - */ -typedef void *VbExDiskHandle_t; - -typedef struct VbSelectAndLoadKernelParams { - /* Inputs to VbSelectAndLoadKernel() */ - /* Destination buffer for kernel (normally at 0x100000 on x86) */ - void *kernel_buffer; - /* Size of kernel buffer in bytes */ - uint32_t kernel_buffer_size; - - /* - * Outputs from VbSelectAndLoadKernel(); valid only if it returns - * success. - */ - /* Handle of disk containing loaded kernel */ - VbExDiskHandle_t disk_handle; - /* Partition number on disk to boot (1...M) */ - uint32_t partition_number; - /* Address of bootloader image in RAM */ - uint64_t bootloader_address; - /* Size of bootloader image in bytes */ - uint32_t bootloader_size; - /* UniquePartitionGuid for boot partition */ - uint8_t partition_guid[16]; - /* Flags set by signer */ - uint32_t flags; -} VbSelectAndLoadKernelParams; - -/** - * Select and loads the kernel. - * - * Returns VB2_SUCCESS if success, non-zero if error; on error, caller - * should reboot. */ -vb2_error_t VbSelectAndLoadKernel(struct vb2_context *ctx, - VbSelectAndLoadKernelParams *kparams); - -/** - * Attempt loading a kernel from the specified type(s) of disks. - * - * If successful, sets kparams.disk_handle to the disk for the kernel and - * returns VB2_SUCCESS. - * - * @param ctx Vboot context - * @param disk_flags Flags to pass to VbExDiskGetInfo() - * @return VB2_SUCCESS or the most specific VB2_ERROR_LK error. - */ -vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t disk_flags); - -/* miniOS flags */ - -/* Boot from non-active miniOS partition only */ -#define VB_MINIOS_FLAG_NON_ACTIVE (1 << 0) - -/** - * Attempt loading a miniOS kernel from internal disk. - * - * Scans sectors at the start and end of the disk, and looks for miniOS kernels - * starting at the beginning of the sector. Attempts loading any miniOS - * kernels found. - * - * If successful, sets lkp.disk_handle to the disk for the kernel and returns - * VB2_SUCCESS. - * - * @param ctx Vboot context - * @param minios_flags Flags for miniOS - * @return VB2_SUCCESS or the most specific VB2_ERROR_LK error. - */ -vb2_error_t VbTryLoadMiniOsKernel(struct vb2_context *ctx, - uint32_t minios_flags); - /*****************************************************************************/ /* Disk access (previously in boot_device.h) */ -/* Flags for VbDisk APIs */ - -/* - * Disk selection in the lower 16 bits (where the disk lives), and disk - * attributes in the higher 16 bits (extra information about the disk - * needed to access it correctly). - */ -#define VB_DISK_FLAG_SELECT_MASK 0xffff -#define VB_DISK_FLAG_ATTRIBUTE_MASK (0xffff << 16) - -/* Disk is removable. Example removable disks: SD cards, USB keys. */ -#define VB_DISK_FLAG_REMOVABLE (1 << 0) -/* - * Disk is fixed. If this flag is present, disk is internal to the system and - * not removable. Example fixed disks: internal SATA SSD, eMMC. - */ -#define VB_DISK_FLAG_FIXED (1 << 1) -/* - * Note that VB_DISK_FLAG_REMOVABLE and VB_DISK_FLAG_FIXED are - * mutually-exclusive for a single disk. VbExDiskGetInfo() may specify both - * flags to request disks of both types in a single call. - * - * At some point we could specify additional flags, but we don't currently - * have a way to make use of these: - * - * USB Device is known to be attached to USB. Note that the SD - * card reader inside x86 systems is attached to USB so this - * isn't super useful. - * SD Device is known to be a SD card. Note that external card - * readers might not return this information, so also of - * questionable use. - * READ_ONLY Device is known to be read-only. Could be used by recovery - * when processing read-only recovery image. - */ - -/* - * Disks are used in two ways: - * - As a random-access device to read and write the GPT - * - As a streaming device to read the kernel - * These are implemented differently on raw NAND vs eMMC/SATA/USB - * - On eMMC/SATA/USB, both of these refer to the same underlying - * storage, so they have the same size and LBA size. In this case, - * the GPT should not point to the same address as itself. - * - On raw NAND, the GPT is held on a portion of the SPI flash. - * Random access GPT operations refer to the SPI and streaming - * operations refer to NAND. The GPT may therefore point into - * the same offsets as itself. - * These types are distinguished by the following flag and VbDiskInfo - * has separate fields to describe the random-access ("GPT") and - * streaming aspects of the disk. If a disk is random-access (i.e. - * not raw NAND) then these fields are equal. - */ -#define VB_DISK_FLAG_EXTERNAL_GPT (1 << 16) - -/* Information on a single disk */ -typedef struct VbDiskInfo { - /* Disk handle */ - VbExDiskHandle_t handle; - /* Size of a random-access LBA sector in bytes */ - uint64_t bytes_per_lba; - /* Number of random-access LBA sectors on the device. - * If streaming_lba_count is 0, this stands in for the size of the - * randomly accessed portion as well as the streaming portion. - * Otherwise, this is only the randomly-accessed portion. */ - uint64_t lba_count; - /* Number of streaming sectors on the device */ - uint64_t streaming_lba_count; - /* Flags (see VB_DISK_FLAG_* constants) */ - uint32_t flags; - /* - * Optional name string, for use in debugging. May be empty or null if - * not available. - */ - const char *name; -} VbDiskInfo; - -/** - * Store information into [info] for all disks (storage devices) attached to - * the system which match all of the disk_flags. - * - * On output, count indicates how many disks are present, and [infos_ptr] - * points to a [count]-sized array of VbDiskInfo structs with the information - * on those disks; this pointer must be freed by calling VbExDiskFreeInfo(). - * If count=0, infos_ptr may point to NULL. If [infos_ptr] points to NULL - * because count=0 or error, it is not necessary to call VbExDiskFreeInfo(). - * - * A multi-function device (such as a 4-in-1 card reader) should provide - * multiple disk handles. - * - * The firmware must not alter or free the list pointed to by [infos_ptr] until - * VbExDiskFreeInfo() is called. - */ -vb2_error_t VbExDiskGetInfo(VbDiskInfo **infos_ptr, uint32_t *count, - uint32_t disk_flags); - -/** - * Free a disk information list [infos] previously returned by - * VbExDiskGetInfo(). If [preserve_handle] != NULL, the firmware must ensure - * that handle remains valid after this call; all other handles from the info - * list need not remain valid after this call. - */ -vb2_error_t VbExDiskFreeInfo(VbDiskInfo *infos, - VbExDiskHandle_t preserve_handle); - /** * Read lba_count LBA sectors, starting at sector lba_start, from the disk, * into the buffer. @@ -229,7 +50,7 @@ * which as been removed), the function must return error but must not * crash. */ -vb2_error_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExDiskRead(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, void *buffer); /** @@ -243,7 +64,7 @@ * which as been removed), the function must return error but must not * crash. */ -vb2_error_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExDiskWrite(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, const void *buffer); /* Streaming read interface */ @@ -263,7 +84,7 @@ * device. It is not used to access the GPT. The size of the content addressed * is within streaming_lba_count. */ -vb2_error_t VbExStreamOpen(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExStreamOpen(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, VbExStream_t *stream_ptr); /**
diff --git a/firmware/lib/gpt_misc.c b/firmware/lib/gpt_misc.c index 641ef37..b42d466 100644 --- a/firmware/lib/gpt_misc.c +++ b/firmware/lib/gpt_misc.c
@@ -19,7 +19,7 @@ * * Returns 0 if successful, 1 if error. */ -int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata) +int AllocAndReadGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata) { int primary_valid = 0, secondary_valid = 0; @@ -126,7 +126,7 @@ * * Returns 0 if successful, 1 if error. */ -int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata) +int WriteAndFreeGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata) { int skip_primary = 0; GptHeader *header;
diff --git a/firmware/lib/include/load_kernel_fw.h b/firmware/lib/include/load_kernel_fw.h deleted file mode 100644 index 76d2556..0000000 --- a/firmware/lib/include/load_kernel_fw.h +++ /dev/null
@@ -1,41 +0,0 @@ -/* Copyright (c) 2013 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. - * - * High-level firmware API for loading and verifying kernel. - * (Firmware Portion) - */ - -#ifndef VBOOT_REFERENCE_LOAD_KERNEL_FW_H_ -#define VBOOT_REFERENCE_LOAD_KERNEL_FW_H_ - -#include "vboot_api.h" - -/** - * Attempt to load kernel from the specified device. - * - * @param ctx Vboot context - * @param params Params specific to loading the kernel - * @param disk_info Disk from which to read kernel - * - * Returns VB2_SUCCESS if successful. If unsuccessful, returns an error code. - */ -vb2_error_t LoadKernel(struct vb2_context *ctx, - VbSelectAndLoadKernelParams *params, - VbDiskInfo *disk_info); - -/** - * Attempt to load miniOS kernel from the specified device. - * - * @param ctx Vboot context - * @param params Params specific to loading the kernel - * @param disk_info Disk from which to read kernel - * @param minios_flags Flags for miniOS - * - * Returns VB2_SUCCESS if successful. If unsuccessful, returns an error code. - */ -vb2_error_t LoadMiniOsKernel(struct vb2_context *ctx, - VbSelectAndLoadKernelParams *params, - VbDiskInfo *disk_info, uint32_t minios_flags); - -#endif /* VBOOT_REFERENCE_LOAD_KERNEL_FW_H_ */
diff --git a/firmware/lib/include/vboot_struct.h b/firmware/lib/include/vboot_struct.h index 374dfd4..ea4a9ee 100644 --- a/firmware/lib/include/vboot_struct.h +++ b/firmware/lib/include/vboot_struct.h
@@ -35,9 +35,9 @@ Deprecated as part of chromium:1010389. */ #define VBSD_FWB_TRIED 0x00000001 /* - * LoadKernel() verified the good kernel keyblock using the kernel subkey from - * the firmware. If this flag is not present, it just used the hash of the - * kernel keyblock. + * vb2api_load_kernel() verified the good kernel keyblock using the kernel + * subkey from the firmware. If this flag is not present, it just used the + * hash of the kernel keyblock. */ #define VBSD_KERNEL_KEY_VERIFIED 0x00000002 /* Developer switch was enabled at boot time */ @@ -111,21 +111,8 @@ /* Firmware lowest version found */ uint32_t fw_version_lowest; - /* Debugging information from LoadKernel() */ - /* Number of times LoadKernel() called */ - uint32_t lk_call_count; /* Reserved for padding */ - uint8_t reserved3[896]; - - /* - * Offset and size of supplemental kernel data. Reserve space for - * these fields now, so that future LoadKernel() versions can store - * information there without needing to shift down whatever data the - * original LoadFirmware() might have put immediately following its - * VbSharedDataHeader. - */ - uint64_t kernel_supplemental_offset; - uint64_t kernel_supplemental_size; + uint8_t reserved3[916]; /* * Fields added in version 2. Before accessing, make sure that @@ -137,7 +124,7 @@ uint8_t reserved4[7]; /* Flags from firmware keyblock */ uint64_t fw_keyblock_flags; - /* Kernel TPM version at start of VbSelectAndLoadKernel() */ + /* Kernel TPM version at start of vb2api_kernel_phase1 */ uint32_t kernel_version_tpm_start; /* Kernel lowest version found */ uint32_t kernel_version_lowest;
diff --git a/firmware/lib/include/vboot_test.h b/firmware/lib/include/vboot_test.h deleted file mode 100644 index fb1f52a..0000000 --- a/firmware/lib/include/vboot_test.h +++ /dev/null
@@ -1,17 +0,0 @@ -/* Copyright 2019 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. - * - * This header is for APIs that are only used by test code. - */ - -#ifndef VBOOT_REFERENCE_TEST_API_H_ -#define VBOOT_REFERENCE_TEST_API_H_ - -/**************************************************************************** - * vboot_api_kernel.c */ - -struct VbSelectAndLoadKernelParams; -struct VbSelectAndLoadKernelParams **VbApiKernelGetParamsPtr(void); - -#endif /* VBOOT_REFERENCE_TEST_API_H_ */
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c deleted file mode 100644 index 9e89620..0000000 --- a/firmware/lib/vboot_api_kernel.c +++ /dev/null
@@ -1,264 +0,0 @@ -/* Copyright (c) 2013 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. - * - * High-level firmware wrapper API - entry points for kernel selection - */ - -#include "2api.h" -#include "2common.h" -#include "2kernel.h" -#include "2misc.h" -#include "2nvstorage.h" -#include "2rsa.h" -#include "2secdata.h" -#include "2sysincludes.h" -#include "load_kernel_fw.h" -#include "vboot_api.h" -#include "vboot_struct.h" -#include "vboot_test.h" - -/* Global variables */ -static VbSelectAndLoadKernelParams *kparams_ptr; - -#ifdef CHROMEOS_ENVIRONMENT -/* Global variable accessor for unit tests */ -struct VbSelectAndLoadKernelParams **VbApiKernelGetParamsPtr(void) -{ - return &kparams_ptr; -} -#endif - -static vb2_error_t handle_battery_cutoff(struct vb2_context *ctx) -{ - /* - * Check if we need to cut-off battery. This should be done after EC - * FW and auxfw are updated, and before the kernel is started. This - * is to make sure all firmware is up-to-date before shipping (which - * is the typical use-case for cutoff). - */ - if (vb2_nv_get(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST)) { - VB2_DEBUG("Request to cut-off battery\n"); - vb2_nv_set(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST, 0); - - /* May lose power immediately, so commit our update now. */ - VB2_TRY(vb2ex_commit_data(ctx)); - - vb2ex_ec_battery_cutoff(); - return VB2_REQUEST_SHUTDOWN; - } - - return VB2_SUCCESS; -} - -static int is_valid_disk(VbDiskInfo *info, uint32_t disk_flags) -{ - return info->bytes_per_lba >= 512 && - (info->bytes_per_lba & (info->bytes_per_lba - 1)) == 0 && - info->lba_count >= 16 && - (info->flags & disk_flags & VB_DISK_FLAG_SELECT_MASK) && - ((info->flags & VB_DISK_FLAG_SELECT_MASK) & - ((info->flags & VB_DISK_FLAG_SELECT_MASK) - 1)) == 0; -} - -static vb2_error_t VbTryLoadKernelImpl(struct vb2_context *ctx, - uint32_t disk_flags, int minios, - uint32_t minios_flags) -{ - vb2_error_t rv = VB2_ERROR_LK_NO_DISK_FOUND; - VbDiskInfo* disk_info = NULL; - uint32_t disk_count = 0; - uint32_t i; - vb2_error_t new_rv; - - /* TODO: Should have been set by VbSelectAndLoadKernel. Remove when - this global is no longer needed. */ - VB2_ASSERT(kparams_ptr); - - kparams_ptr->disk_handle = NULL; - - /* Find disks */ - if (VB2_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count, disk_flags)) - disk_count = 0; - - /* Loop over disks */ - for (i = 0; i < disk_count; i++) { - VB2_DEBUG("trying disk %d\n", (int)i); - - if (!is_valid_disk(&disk_info[i], disk_flags)) { - VB2_DEBUG(" skipping: bytes_per_lba=%" PRIu64 - " lba_count=%" PRIu64 " flags=%#x\n", - disk_info[i].bytes_per_lba, - disk_info[i].lba_count, - disk_info[i].flags); - continue; - } - kparams_ptr->disk_handle = disk_info[i].handle; - - if (minios) { - new_rv = LoadMiniOsKernel(ctx, kparams_ptr, - &disk_info[i], minios_flags); - VB2_DEBUG("LoadMiniOsKernel() = %#x\n", new_rv); - } else { - new_rv = LoadKernel(ctx, kparams_ptr, &disk_info[i]); - VB2_DEBUG("LoadKernel() = %#x\n", new_rv); - } - - /* Stop now if we found a kernel. */ - if (VB2_SUCCESS == new_rv) { - VbExDiskFreeInfo(disk_info, disk_info[i].handle); - return VB2_SUCCESS; - } - - /* Don't update error if we already have a more specific one. */ - if (VB2_ERROR_LK_INVALID_KERNEL_FOUND != rv) - rv = new_rv; - } - - /* If we drop out of the loop, we didn't find any usable kernel. */ - if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE) && - !(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE)) { - switch (rv) { - case VB2_ERROR_LK_INVALID_KERNEL_FOUND: - vb2api_fail(ctx, VB2_RECOVERY_RW_INVALID_OS, rv); - break; - case VB2_ERROR_LK_NO_KERNEL_FOUND: - vb2api_fail(ctx, VB2_RECOVERY_RW_NO_KERNEL, rv); - break; - case VB2_ERROR_LK_NO_DISK_FOUND: - vb2api_fail(ctx, VB2_RECOVERY_RW_NO_DISK, rv); - break; - default: - vb2api_fail(ctx, VB2_RECOVERY_LK_UNSPECIFIED, rv); - break; - } - } - - /* If we didn't find any good kernels, don't return a disk handle. */ - VbExDiskFreeInfo(disk_info, NULL); - - return rv; -} - -test_mockable -vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t disk_flags) -{ - return VbTryLoadKernelImpl(ctx, disk_flags, 0, 0); -} - -test_mockable -vb2_error_t VbTryLoadMiniOsKernel(struct vb2_context *ctx, - uint32_t minios_flags) -{ - return VbTryLoadKernelImpl(ctx, VB_DISK_FLAG_FIXED, 1, minios_flags); -} - -vb2_error_t VbSelectAndLoadKernel(struct vb2_context *ctx, - VbSelectAndLoadKernelParams *kparams) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - vb2_gbb_flags_t gbb_flags = vb2api_gbb_get_flags(ctx); - - /* TODO: Send this argument through subsequent function calls, rather - than relying on a global to pass it to VbTryLoadKernel. */ - kparams_ptr = kparams; - - /* Init nvstorage space. TODO(kitching): Remove once we add assertions - to vb2_nv_get and vb2_nv_set. */ - vb2_nv_init(ctx); - - VB2_TRY(vb2api_kernel_phase1(ctx)); - - VB2_DEBUG("GBB flags are %#x\n", gbb_flags); - - /* - * Do EC and auxfw software sync unless we're in recovery mode. This - * has UI but it's just a single non-interactive WAIT screen. - */ - if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { - VB2_TRY(vb2api_ec_sync(ctx)); - VB2_TRY(vb2api_auxfw_sync(ctx)); - VB2_TRY(handle_battery_cutoff(ctx)); - } - - /* - * If in the broken screen, save the recovery reason as subcode. - * Otherwise, clear any leftover recovery requests or subcodes. - */ - vb2_clear_recovery(ctx); - - /* Select boot path */ - switch (ctx->boot_mode) { - case VB2_BOOT_MODE_MANUAL_RECOVERY: - case VB2_BOOT_MODE_BROKEN_SCREEN: - /* If we're in recovery mode just to do memory retraining, all - we need to do is reboot. */ - if (sd->recovery_reason == VB2_RECOVERY_TRAIN_AND_REBOOT) { - VB2_DEBUG("Reboot after retraining in recovery\n"); - return VB2_REQUEST_REBOOT; - } - - /* - * Need to commit nvdata changes immediately, since we will be - * entering either manual recovery UI or BROKEN screen shortly. - */ - vb2ex_commit_data(ctx); - - /* - * In EFS2, recovery mode can be entered even when battery is - * drained or damaged. EC-RO sets NO_BOOT flag in such case and - * uses PD power to boot AP. - * - * TODO: Inform user why recovery failed to start. - */ - if (ctx->flags & VB2_CONTEXT_NO_BOOT) - VB2_DEBUG("NO_BOOT in RECOVERY mode\n"); - - /* Recovery boot. This has UI. */ - if (ctx->boot_mode == VB2_BOOT_MODE_MANUAL_RECOVERY) - VB2_TRY(vb2ex_manual_recovery_ui(ctx)); - else - VB2_TRY(vb2ex_broken_screen_ui(ctx)); - break; - case VB2_BOOT_MODE_DIAGNOSTICS: - /* - * Need to clear the request flag and commit nvdata changes - * immediately to avoid booting back into diagnostic tool when a - * forced system reset occurs. - */ - vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 0); - vb2ex_commit_data(ctx); - - /* Diagnostic boot. This has UI. */ - VB2_TRY(vb2ex_diagnostic_ui(ctx)); - /* - * The diagnostic menu should either boot a rom, or - * return either of reboot or shutdown. - */ - return VB2_REQUEST_REBOOT; - case VB2_BOOT_MODE_DEVELOPER: - /* Developer boot. This has UI. */ - VB2_TRY(vb2ex_developer_ui(ctx)); - break; - case VB2_BOOT_MODE_NORMAL: - /* Normal boot */ - VB2_TRY(vb2_normal_boot(ctx)); - break; - default: - return VB2_ERROR_ESCAPE_NO_BOOT; - } - - /* - * Stop all cases returning SUCCESS against NO_BOOT flag except when - * GBB flag disables software sync. - */ - if (!(gbb_flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC) - && (ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED) - && (ctx->flags & VB2_CONTEXT_NO_BOOT)) { - VB2_DEBUG("Blocking escape from NO_BOOT mode.\n"); - vb2api_fail(ctx, VB2_RECOVERY_ESCAPE_NO_BOOT, 0); - return VB2_ERROR_ESCAPE_NO_BOOT; - } - - return VB2_SUCCESS; -}
diff --git a/firmware/stub/vboot_api_stub.c b/firmware/stub/vboot_api_stub.c deleted file mode 100644 index 9335c8b..0000000 --- a/firmware/stub/vboot_api_stub.c +++ /dev/null
@@ -1,25 +0,0 @@ -/* Copyright (c) 2013 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. - * - * Stub implementations of firmware-provided API functions. - */ - -#include <stdint.h> - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/time.h> - -#include "2api.h" -#include "2common.h" -#include "vboot_api.h" -#include "vboot_test.h" - -__attribute__((weak)) -vb2_error_t vb2ex_run_altfw(uint32_t altfw_id) -{ - return VB2_SUCCESS; -}
diff --git a/firmware/stub/vboot_api_stub_disk.c b/firmware/stub/vboot_api_stub_disk.c index 3244dc6..b09388e 100644 --- a/firmware/stub/vboot_api_stub_disk.c +++ b/firmware/stub/vboot_api_stub_disk.c
@@ -15,35 +15,15 @@ #include "2common.h" #include "vboot_api.h" - __attribute__((weak)) -vb2_error_t VbExDiskGetInfo(VbDiskInfo** infos_ptr, uint32_t* count, - uint32_t disk_flags) -{ - *infos_ptr = NULL; - *count = 0; - return VB2_SUCCESS; -} - - -__attribute__((weak)) -vb2_error_t VbExDiskFreeInfo(VbDiskInfo* infos_ptr, - VbExDiskHandle_t preserve_handle) -{ - return VB2_SUCCESS; -} - - -__attribute__((weak)) -vb2_error_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExDiskRead(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, void* buffer) { return VB2_SUCCESS; } - __attribute__((weak)) -vb2_error_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExDiskWrite(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, const void* buffer) { return VB2_SUCCESS;
diff --git a/firmware/stub/vboot_api_stub_stream.c b/firmware/stub/vboot_api_stub_stream.c index 68e7ec7..1a6a65c 100644 --- a/firmware/stub/vboot_api_stub_stream.c +++ b/firmware/stub/vboot_api_stub_stream.c
@@ -16,7 +16,7 @@ /* Internal struct to simulate a stream for sector-based disks */ struct disk_stream { /* Disk handle */ - VbExDiskHandle_t handle; + vb2ex_disk_handle_t handle; /* Next sector to read */ uint64_t sector; @@ -26,7 +26,7 @@ }; __attribute__((weak)) -vb2_error_t VbExStreamOpen(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExStreamOpen(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, VbExStream_t *stream) { struct disk_stream *s;
diff --git a/futility/cmd_gscvd.c b/futility/cmd_gscvd.c index 7fff293..458c754 100644 --- a/futility/cmd_gscvd.c +++ b/futility/cmd_gscvd.c
@@ -40,9 +40,9 @@ * AP firmware file is ~/tmp/guybrush-signed: * ./build/futility/futility gscvd --outfile ~/tmp/guybrush-signed \ - -R 818100:10000,f00000:100,f80000:2000,f8c000:1000,0x00804000:0x00000800 \ - -k ~/tmp/packed -p tests/devkeys/arv_platform.vbprivk -b 5a5a4352 \ - -r tests/devkeys/arv_root.vbpubk ~/tmp/image-guybrush.serial.bin + -R 818100:10000,f00000:100,f80000:2000,f8c000:1000,0x00804000:0x00000800 \ + -k ~/tmp/packed -p tests/devkeys/arv_platform.vbprivk -b 5a5a4352 \ + -r tests/devkeys/arv_root.vbpubk ~/tmp/image-guybrush.serial.bin *------------ * Command to validate a previously signed AP firmware file. The hash is the * sha256sum of tests/devkeys/kernel_subkey.vbpubk: @@ -60,6 +60,7 @@ /* name hasarg *flag val */ {"outfile", 1, NULL, OPT_OUTFILE}, {"ranges", 1, NULL, 'R'}, + {"add_gbb", 0, NULL, 'G'}, {"board_id", 1, NULL, 'b'}, {"root_pub_key", 1, NULL, 'r'}, {"keyblock", 1, NULL, 'k'}, @@ -68,7 +69,7 @@ {} }; -static const char *short_opts = "R:b:hk:p:r:"; +static const char *short_opts = "R:Gb:hk:p:r:"; static const char usage[] = "\n" @@ -82,8 +83,15 @@ " hex tuples <offset>:<size>, the\n" " areas of the RO covered by the\n" " signature\n" - " -b|--board_id <hex value> The Board ID of the board for which\n" - " the image is being signed\n" + " -G|--add_gbb Add the `GBB` FMAP section to the\n" + " ranges covered by the signature.\n" + " This option takes special care\n" + " to exclude the HWID (and its\n" + " digest) from this range.\n" + " -b|--board_id <string|hex> The Board ID of the board for\n" + " which the image is signed.\n" + " Can be passed as a 4-letter\n" + " string or a hexadecimal number.\n" " -r|--root_pub_key <file> The main public key, in .vbpubk\n" " format, used to verify platform\n" " key\n" @@ -140,36 +148,25 @@ * * @return 0 on success 1 on failure. */ -static int load_ap_firmware(const char *file_name, struct file_buf *file) +static int load_ap_firmware(const char *file_name, struct file_buf *file, + int mode) { - int fd; - int rv; + if (futil_open_and_map_file(file_name, &file->fd, mode, &file->data, + &file->len)) + return 1; - fd = open(file_name, O_RDWR); - if (fd < 0) { - ERROR("Can't open %s: %s\n", file_name, - strerror(errno)); + if (!fmap_find_by_name(file->data, file->len, NULL, "RO_GSCVD", + &file->ro_gscvd)) { + ERROR("Could not find RO_GSCVD in the FMAP\n"); + futil_unmap_and_close_file(file->fd, mode, file->data, + file->len); + file->fd = -1; + file->data = NULL; + file->len = 0; return 1; } - file->fd = fd; - do { - rv = 1; - - if (futil_map_file(fd, MAP_RW, &file->data, &file->len)) { - file->data = NULL; - break; - } - - if (!fmap_find_by_name(file->data, file->len, NULL, "RO_GSCVD", - &file->ro_gscvd)) { - ERROR("Could not find RO_GSCVD in the FMAP\n"); - break; - } - rv = 0; - } while (false); - - return rv; + return 0; } /** @@ -191,9 +188,6 @@ in_range(range->offset + range->size, ah)) return true; - ERROR("Range %#x..+%#x does not fit in %s\n", range->offset, - range->size, ah->area_name); - return false; } @@ -237,6 +231,7 @@ { size_t i; FmapAreaHeader *wp_ro; + FmapAreaHeader *si_all; int errorcount; if (!fmap_find_by_name(file->data, file->len, NULL, "WP_RO", &wp_ro)) { @@ -244,13 +239,24 @@ return 1; } + /* Intel boards can have an SI_ALL region that's not in WP_RO but is + protected by platform-specific mechanisms, and may still contain + components that we want to protect from physical attack. */ + if (!fmap_find_by_name(file->data, file->len, NULL, "SI_ALL", &si_all)) + si_all = NULL; + errorcount = 0; for (i = 0; i < ranges->range_count; i++) { size_t j; - /* Must fit into WP_RO. */ - if (!range_fits(ranges->ranges + i, wp_ro)) + /* Must fit into WP_RO or SI_ALL. */ + if (!range_fits(ranges->ranges + i, wp_ro) && + (!si_all || !range_fits(ranges->ranges + i, si_all))) { + ERROR("Range %#x..+%#x does not fit in WP_RO/SI_ALL\n", + ranges->ranges[i].offset, + ranges->ranges[i].size); errorcount++; + } /* Must not overlap with RO_GSCVD. */ if (range_overlaps(ranges->ranges + i, @@ -296,7 +302,6 @@ return -1; } - output->range_count = 0; cursor = str; do { char *colon; @@ -346,6 +351,71 @@ } /** + * Add GBB to ranges. + * + * Splits the `GBB` FMAP section into separate ranges to exclude the HWID string + * and the `hwid_digest` field in the header. Will also exclude the empty area + * behind the end of the actual GBB data. + * + * @param ranges pointer to the ranges container + * @param file pointer to the AP firmware file layout descriptor + */ +static int add_gbb(struct gscvd_ro_ranges *ranges, const struct file_buf *file) +{ + FmapAreaHeader *area; + + if (!fmap_find_by_name(file->data, file->len, NULL, "GBB", &area)) { + ERROR("Could not find a GBB area in the FMAP.\n"); + return 1; + } + + struct vb2_gbb_header *gbb = (void *)file->data + area->area_offset; + uint32_t maxlen; + + if (!futil_valid_gbb_header(gbb, area->area_size, &maxlen)) { + ERROR("GBB is invalid.\n"); + return 1; + } + + /* + * This implementation relies on the fact that no meaningful fields come + * after the `hwid_digest` field in the header. If we ever make new GBB + * versions that add more fields, the code below needs to be adapted. + * Older versions than 1.2 or GBBs with a bmpblk are not expected with + * GSCVD images. + */ + if (gbb->major_version != 1 || gbb->minor_version != 2 || + gbb->bmpfv_size != 0) { + ERROR("Unsupported GBB version.\n"); + return 1; + } + + uint32_t lower_key_offset = VB2_MIN(gbb->rootkey_offset, + gbb->recovery_key_offset); + if (gbb->hwid_offset > lower_key_offset) { + ERROR("Weird GBB layout (HWID should come first)\n"); + return 1; + } + + if (ranges->range_count >= ARRAY_SIZE(ranges->ranges) - 2) { + ERROR("Too many ranges, can't fit GBB!\n"); + return 1; + } + + ranges->ranges[ranges->range_count].offset = area->area_offset; + ranges->ranges[ranges->range_count].size = + offsetof(struct vb2_gbb_header, hwid_digest); + ranges->range_count++; + + ranges->ranges[ranges->range_count].offset = area->area_offset + + lower_key_offset; + ranges->ranges[ranges->range_count].size = maxlen - lower_key_offset; + ranges->range_count++; + + return 0; +} + +/** * Calculate hash of the RO ranges. * * @param ap_firmware_file pointer to the AP firmware file layout descriptor @@ -807,7 +877,7 @@ rv = -1; /* Speculative, will be cleared on success. */ - if (load_ap_firmware(file_name, &ap_firmware_file)) + if (load_ap_firmware(file_name, &ap_firmware_file, FILE_RO)) break; /* Copy ranges from gscvd to local structure. */ @@ -842,16 +912,24 @@ break; } - if (validate_pubk_signature(&gvd->root_key_header, - kblock)) + if (validate_pubk_signature(&gvd->root_key_header, kblock)) { + ERROR("Keyblock not signed by root key\n"); break; + } - if (validate_gvd_signature(gvd, &kblock->data_key)) + if (validate_gvd_signature(gvd, &kblock->data_key)) { + ERROR("GVD not signed by platform key\n"); break; + } rv = 0; } while (false); + if (ap_firmware_file.fd != -1) + futil_unmap_and_close_file(ap_firmware_file.fd, FILE_RO, + ap_firmware_file.data, + ap_firmware_file.len); + return rv; } @@ -890,6 +968,7 @@ { int i; int longindex; + bool do_gbb = false; char *infile = NULL; char *outfile = NULL; char *work_file = NULL; @@ -918,13 +997,24 @@ errorcount++; } break; + case 'G': + do_gbb = true; + break; case 'b': { char *e; long long bid; + if (strlen(optarg) == 4) { + board_id = optarg[0] << 24 | + optarg[1] << 16 | + optarg[2] << 8 | + optarg[3]; + break; + } + bid = strtoull(optarg, &e, 16); if (*e || (bid >= UINT32_MAX)) { - ERROR("Board ID value '%s' is invalid\n", + ERROR("Cannot parse Board ID '%s'\n", optarg); errorcount++; } else { @@ -980,15 +1070,36 @@ return validate_gscvd(argc - 1, argv + 1); if (optind != (argc - 1)) { - ERROR("Misformatted command line\n%s\n", usage); - return 1; + ERROR("Misformatted command line\n"); + goto usage_out; } - if (errorcount || !ranges.range_count || !root_pubk || !kblock || - !plat_privk || (board_id == UINT32_MAX)) { - /* Error message(s) should have been printed by now. */ - ERROR("%s\n", usage); - return 1; + if (errorcount) /* Error message(s) should have been printed by now. */ + goto usage_out; + + if (!root_pubk) { + ERROR("Missing --root_pub_key argument\n"); + goto usage_out; + } + + if (!kblock) { + ERROR("Missing --keyblock argument\n"); + goto usage_out; + } + + if (!plat_privk) { + ERROR("Missing --platform_priv argument\n"); + goto usage_out; + } + + if (board_id == UINT32_MAX) { + ERROR("Missing --board_id argument\n"); + goto usage_out; + } + + if (!ranges.range_count && !do_gbb) { + ERROR("Missing --ranges argument\n"); + goto usage_out; } infile = argv[optind]; @@ -1009,7 +1120,10 @@ if (validate_privk(kblock, plat_privk)) break; - if (load_ap_firmware(work_file, &ap_firmware_file)) + if (load_ap_firmware(work_file, &ap_firmware_file, FILE_RW)) + break; + + if (do_gbb && add_gbb(&ranges, &ap_firmware_file)) break; if (verify_ranges(&ranges, &ap_firmware_file)) @@ -1033,17 +1147,16 @@ free(kblock); vb2_private_key_free(plat_privk); - /* Now flush the file. */ - if (ap_firmware_file.data) { - rv |= futil_unmap_file(ap_firmware_file.fd, true, - ap_firmware_file.data, - ap_firmware_file.len); - } - if (ap_firmware_file.fd != -1) - close(ap_firmware_file.fd); + futil_unmap_and_close_file(ap_firmware_file.fd, FILE_RW, + ap_firmware_file.data, + ap_firmware_file.len); return rv; + +usage_out: + fputs(usage, stderr); + return 1; } DECLARE_FUTIL_COMMAND(gscvd, do_gscvd, VBOOT_VERSION_2_1,
diff --git a/futility/cmd_load_fmap.c b/futility/cmd_load_fmap.c index 818fda8..4ab194e 100644 --- a/futility/cmd_load_fmap.c +++ b/futility/cmd_load_fmap.c
@@ -149,22 +149,16 @@ else outfile = infile; - fd = open(outfile, O_RDWR); - if (fd < 0) { - fprintf(stderr, "Can't open %s: %s\n", - outfile, strerror(errno)); - return 1; - } + errorcnt |= futil_open_and_map_file(outfile, &fd, FILE_RW, &buf, &len); - errorcnt |= futil_map_file(fd, MAP_RW, &buf, &len); if (errorcnt) - goto done_file; + goto done; fmap = fmap_find(buf, len); if (!fmap) { fprintf(stderr, "Can't find an FMAP in %s\n", infile); errorcnt++; - goto done_map; + goto done; } for (i = optind; i < argc; i++) { @@ -190,20 +184,10 @@ } } -done_map: - errorcnt |= futil_unmap_file(fd, 1, buf, len); - -done_file: - - if (0 != close(fd)) { - fprintf(stderr, "Error closing %s: %s\n", - outfile, strerror(errno)); - errorcnt++; - } - +done: + errorcnt |= futil_unmap_and_close_file(fd, FILE_RW, buf, len); return !!errorcnt; } DECLARE_FUTIL_COMMAND(load_fmap, do_load_fmap, VBOOT_VERSION_ALL, "Replace the contents of specified FMAP areas"); -
diff --git a/futility/cmd_show.c b/futility/cmd_show.c index dbe6edd..9816106 100644 --- a/futility/cmd_show.c +++ b/futility/cmd_show.c
@@ -86,31 +86,49 @@ packed_key_sha1_string(data_key)); } -int ft_show_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data) +int ft_show_pubkey(const char *name, void *data) { - struct vb2_packed_key *pubkey = (struct vb2_packed_key *)buf; + int fd = -1; + struct vb2_packed_key *pubkey; + uint32_t len; + int rv = 0; + + if (futil_open_and_map_file(name, &fd, FILE_RO, (uint8_t **)&pubkey, + &len)) + return 1; if (vb2_packed_key_looks_ok(pubkey, len)) { printf("%s looks bogus\n", name); - return 1; + rv = 1; + goto done; } printf("Public Key file: %s\n", name); show_pubkey(pubkey, " "); - return 0; +done: + futil_unmap_and_close_file(fd, FILE_RO, (uint8_t *)pubkey, len); + return rv; } -int ft_show_privkey(const char *name, uint8_t *buf, uint32_t len, void *data) +int ft_show_privkey(const char *name, void *data) { - struct vb2_packed_private_key *pkey = - (struct vb2_packed_private_key *)buf; + int fd = -1; + int rv = 0; + struct vb2_packed_private_key *pkey = NULL; + uint32_t len; struct vb2_private_key key; - const unsigned char *start = pkey->key_data; + const unsigned char *start; + if (futil_open_and_map_file(name, &fd, FILE_RO, (uint8_t **)&pkey, + &len)) + return 1; + + start = pkey->key_data; if (len <= sizeof(*pkey)) { printf("%s looks bogus\n", name); - return 1; + rv = 1; + goto done; } len -= sizeof(*pkey); key.rsa_private_key = d2i_RSAPrivateKey(NULL, &start, len); @@ -122,20 +140,30 @@ printf(" Key sha1sum: %s\n", private_key_sha1_string(&key)); - return 0; +done: + futil_unmap_and_close_file(fd, FILE_RO, (uint8_t *)pkey, len); + return rv; } -int ft_show_keyblock(const char *name, uint8_t *buf, uint32_t len, void *data) +int ft_show_keyblock(const char *name, void *data) { - struct vb2_keyblock *block = (struct vb2_keyblock *)buf; + struct vb2_keyblock *block; struct vb2_public_key *sign_key = show_option.k; int good_sig = 0; int retval = 0; + int fd = -1; + uint32_t len; + + retval = futil_open_and_map_file(name, &fd, FILE_RO, (uint8_t **)&block, + &len); + if (retval) + return 1; /* Check the hash only first */ if (0 != vb2_verify_keyblock_hash(block, len, &wb)) { printf("%s is invalid\n", name); - return 1; + retval = 1; + goto done; } /* Check the signature if we have one */ @@ -148,11 +176,13 @@ show_keyblock(block, name, !!sign_key, good_sig); +done: + futil_unmap_and_close_file(fd, FILE_RO, (uint8_t *)block, len); return retval; } -int ft_show_fw_preamble(const char *name, uint8_t *buf, uint32_t len, - void *data) +int show_fw_preamble_buf(const char *name, uint8_t *buf, uint32_t len, + void *data) { struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf; struct bios_state_s *state = (struct bios_state_s *)data; @@ -282,17 +312,40 @@ return retval; } -int ft_show_kernel_preamble(const char *name, uint8_t *buf, uint32_t len, - void *data) +int ft_show_fw_preamble(const char *name, void *data) { - struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf; + int rv = 0; + int fd = -1; + uint8_t *buf; + uint32_t len; + + if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len)) + return 1; + + rv = show_fw_preamble_buf(name, buf, len, data); + + futil_unmap_and_close_file(fd, FILE_RO, buf, len); + return rv; +} + +int ft_show_kernel_preamble(const char *name, void *data) +{ + struct vb2_keyblock *keyblock; struct vb2_public_key *sign_key = show_option.k; - int retval = 0; + int retval = 1; + int fd = -1; + uint8_t *buf; + uint32_t len; + + if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len)) + return 1; + + keyblock = (struct vb2_keyblock *)buf; /* Check the hash... */ if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) { printf("%s keyblock component is invalid\n", name); - return 1; + goto done; } /* If we have a key, check the signature too */ @@ -304,13 +357,10 @@ printf("Kernel partition: %s\n", name); show_keyblock(keyblock, NULL, !!sign_key, good_sig); - if (show_option.strict && (!sign_key || !good_sig)) - retval = 1; - struct vb2_public_key data_key; if (VB2_SUCCESS != vb2_unpack_key(&data_key, &keyblock->data_key)) { fprintf(stderr, "Error parsing data key in %s\n", name); - return 1; + goto done; } uint32_t more = keyblock->keyblock_size; @@ -320,7 +370,7 @@ if (VB2_SUCCESS != vb2_verify_kernel_preamble(pre2, len - more, &data_key, &wb)) { printf("%s is invalid\n", name); - return 1; + goto done; } printf("Kernel Preamble:\n"); @@ -367,20 +417,24 @@ if (!kernel_blob) { /* TODO: Is this always a failure? The preamble is okay. */ fprintf(stderr, "No kernel blob available to verify.\n"); - return 1; + goto done; } if (VB2_SUCCESS != vb2_verify_data(kernel_blob, kernel_size, &pre2->body_signature, &data_key, &wb)) { fprintf(stderr, "Error verifying kernel body.\n"); - return 1; + goto done; } printf("Body verification succeeded.\n"); printf("Config:\n%s\n", kernel_blob + kernel_cmd_line_offset(pre2)); + if (!show_option.strict || (sign_key && good_sig)) + retval = 0; +done: + futil_unmap_and_close_file(fd, FILE_RO, buf, len); return retval; } @@ -476,9 +530,8 @@ uint8_t *pubkbuf = NULL; struct vb2_public_key pubk2; char *infile = 0; - int ifd, i; + int i; int errorcnt = 0; - uint8_t *buf; uint32_t len; char *e = 0; int type_override = 0; @@ -585,34 +638,14 @@ for (i = optind; i < argc; i++) { infile = argv[i]; - ifd = open(infile, O_RDONLY); - if (ifd < 0) { - errorcnt++; - fprintf(stderr, "Can't open %s: %s\n", - infile, strerror(errno)); - continue; - } - - if (0 != futil_map_file(ifd, MAP_RO, &buf, &len)) { - errorcnt++; - goto boo; - } /* Allow the user to override the type */ if (type_override) type = show_option.type; else - type = futil_file_type_buf(buf, len); + futil_file_type(infile, &type); - errorcnt += futil_file_type_show(type, infile, buf, len); - - errorcnt += futil_unmap_file(ifd, MAP_RO, buf, len); -boo: - if (close(ifd)) { - errorcnt++; - fprintf(stderr, "Error when closing %s: %s\n", - infile, strerror(errno)); - } + errorcnt += futil_file_type_show(type, infile); } done: @@ -635,4 +668,5 @@ DECLARE_FUTIL_COMMAND(verify, do_verify, VBOOT_VERSION_ALL, - "Verify the signatures of various binary components"); + "Verify the signatures of various binary components. " + "This does not verify GSCVD contents.");
diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c index be8b634..2f9a017 100644 --- a/futility/cmd_sign.c +++ b/futility/cmd_sign.c
@@ -29,8 +29,11 @@ #include "util_misc.h" #include "vb1_helper.h" +#define DEFAULT_KEYSETDIR "/usr/share/vboot/devkeys" + /* Options */ struct sign_option_s sign_option = { + .keysetdir = DEFAULT_KEYSETDIR, .version = 1, .arch = ARCH_UNSPECIFIED, .kloadaddr = CROS_32BIT_ENTRY_ADDR, @@ -55,14 +58,21 @@ } /* This wraps/signs a public key, producing a keyblock. */ -int ft_sign_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data) +int ft_sign_pubkey(const char *name, void *data) { - struct vb2_packed_key *data_key = (struct vb2_packed_key *)buf; + struct vb2_packed_key *data_key; + uint32_t data_len; struct vb2_keyblock *block; + int rv = 1; + int fd = -1; - if (vb2_packed_key_looks_ok(data_key, len)) { - fprintf(stderr, "Public key looks bad.\n"); + if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option), + (uint8_t **)&data_key, &data_len)) return 1; + + if (vb2_packed_key_looks_ok(data_key, data_len)) { + fprintf(stderr, "Public key looks bad.\n"); + goto done; } if (sign_option.pem_signpriv) { @@ -82,7 +92,7 @@ fprintf(stderr, "Unable to read PEM signing key: %s\n", strerror(errno)); - return 1; + goto done; } block = vb2_create_keyblock(data_key, sign_option.signprivate, @@ -95,20 +105,24 @@ } /* Write it out */ - return WriteSomeParts(sign_option.outfile, - block, block->keyblock_size, - NULL, 0); + rv = WriteSomeParts(sign_option.outfile, block, block->keyblock_size, + NULL, 0); +done: + futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), + (uint8_t *)data_key, data_len); + return rv; } -int ft_sign_raw_kernel(const char *name, uint8_t *buf, uint32_t len, - void *data) +int ft_sign_raw_kernel(const char *name, void *data) { - uint8_t *vmlinuz_data, *kblob_data, *vblock_data; + uint8_t *vmlinuz_data = NULL, *kblob_data = NULL, *vblock_data = NULL; uint32_t vmlinuz_size, kblob_size, vblock_size; - int rv; + int rv = 1; + int fd = -1; - vmlinuz_data = buf; - vmlinuz_size = len; + if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option), + &vmlinuz_data, &vmlinuz_size)) + return 1; kblob_data = CreateKernelBlob( vmlinuz_data, vmlinuz_size, @@ -118,7 +132,7 @@ &kblob_size); if (!kblob_data) { fprintf(stderr, "Unable to create kernel blob\n"); - return 1; + goto done; } VB2_DEBUG("kblob_size = %#x\n", kblob_size); @@ -131,8 +145,7 @@ sign_option.flags, &vblock_size); if (!vblock_data) { fprintf(stderr, "Unable to sign kernel blob\n"); - free(kblob_data); - return 1; + goto done; } VB2_DEBUG("vblock_size = %#x\n", vblock_size); @@ -150,22 +163,26 @@ vblock_data, vblock_size, kblob_data, kblob_size); +done: + futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), + vmlinuz_data, vmlinuz_size); free(vblock_data); free(kblob_data); return rv; } -int ft_sign_kern_preamble(const char *name, uint8_t *buf, uint32_t len, - void *data) +int ft_sign_kern_preamble(const char *name, void *data) { - uint8_t *kpart_data, *kblob_data, *vblock_data; + uint8_t *kpart_data = NULL, *kblob_data = NULL, *vblock_data = NULL; uint32_t kpart_size, kblob_size, vblock_size; struct vb2_keyblock *keyblock = NULL; struct vb2_kernel_preamble *preamble = NULL; - int rv = 0; + int rv = 1; + int fd = -1; - kpart_data = buf; - kpart_size = len; + if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option), + &kpart_data, &kpart_size)) + return 1; /* Note: This just sets some static pointers. It doesn't malloc. */ kblob_data = unpack_kernel_partition(kpart_data, kpart_size, @@ -174,7 +191,7 @@ if (!kblob_data) { fprintf(stderr, "Unable to unpack kernel partition\n"); - return 1; + goto done; } /* @@ -192,7 +209,7 @@ sign_option.config_data, sign_option.config_size)) { fprintf(stderr, "Unable to update config\n"); - return 1; + goto done; } /* Preserve the version unless a new one is given */ @@ -219,7 +236,7 @@ &vblock_size); if (!vblock_data) { fprintf(stderr, "Unable to sign kernel blob\n"); - return 1; + goto done; } VB2_DEBUG("vblock_size = %#x\n", vblock_size); @@ -238,24 +255,33 @@ * all our modifications to the buffer will get flushed to * disk when we close it. */ memcpy(kpart_data, vblock_data, vblock_size); + rv = 0; } - +done: + futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), kpart_data, + kpart_size); free(vblock_data); return rv; } -int ft_sign_raw_firmware(const char *name, uint8_t *buf, uint32_t len, - void *data) +int ft_sign_raw_firmware(const char *name, void *data) { - struct vb2_signature *body_sig; - struct vb2_fw_preamble *preamble; - int rv; + struct vb2_signature *body_sig = NULL; + struct vb2_fw_preamble *preamble = NULL; + uint8_t *buf; + uint32_t len; + int rv = 1; + int fd = -1; + + if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option), + &buf, &len)) + return 1; body_sig = vb2_calculate_signature(buf, len, sign_option.signprivate); if (!body_sig) { fprintf(stderr, "Error calculating body signature\n"); - return 1; + goto done; } preamble = vb2_create_fw_preamble( @@ -267,7 +293,7 @@ if (!preamble) { fprintf(stderr, "Error creating firmware preamble.\n"); free(body_sig); - return 1; + goto done; } rv = WriteSomeParts(sign_option.outfile, @@ -275,12 +301,94 @@ sign_option.keyblock->keyblock_size, preamble, preamble->preamble_size); +done: + futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len); free(preamble); free(body_sig); return rv; } +static int load_keyset(void) +{ + char *buf = NULL; + int errorcnt = 0; + const char *s = NULL; + const char *b = NULL; + const char *k = NULL; + const char *format; + struct stat sb; + + if (!sign_option.keysetdir) + FATAL("Keyset should never be NULL. Aborting\n"); + + /* Failure means this is not a directory */ + if (stat(sign_option.keysetdir, &sb) == -1 || + (sb.st_mode & S_IFMT) != S_IFDIR) + format = "%s%s.%s"; + else + format = "%s/%s.%s"; + + switch (sign_option.type) { + case FILE_TYPE_BIOS_IMAGE: + case FILE_TYPE_RAW_FIRMWARE: + s = "firmware_data_key"; + b = "firmware"; + k = "kernel_subkey"; + break; + case FILE_TYPE_RAW_KERNEL: + s = "kernel_data_key"; + b = "kernel"; + break; + case FILE_TYPE_KERN_PREAMBLE: + s = "kernel_data_key"; + break; + default: + return 0; + } + + if (s && !sign_option.signprivate) { + if (asprintf(&buf, format, sign_option.keysetdir, s, + "vbprivk") <= 0) + FATAL("Failed to allocate string\n"); + INFO("Loading private data key from default keyset: %s\n", buf); + sign_option.signprivate = vb2_read_private_key(buf); + if (!sign_option.signprivate) { + ERROR("Error reading %s\n", buf); + errorcnt++; + } + free(buf); + } + + if (b && !sign_option.keyblock) { + if (asprintf(&buf, format, sign_option.keysetdir, b, + "keyblock") <= 0) + FATAL("Failed to allocate string\n"); + INFO("Loading keyblock from default keyset: %s\n", buf); + sign_option.keyblock = vb2_read_keyblock(buf); + if (!sign_option.keyblock) { + ERROR("Error reading %s\n", buf); + errorcnt++; + } + free(buf); + } + + if (k && !sign_option.kernel_subkey) { + if (asprintf(&buf, format, sign_option.keysetdir, k, + "vbpubk") <= 0) + FATAL("Failed to allocate string\n"); + INFO("Loading kernel subkey from default keyset: %s\n", buf); + sign_option.kernel_subkey = vb2_read_packed_key(buf); + if (!sign_option.kernel_subkey) { + ERROR("Error reading %s\n", buf); + errorcnt++; + } + free(buf); + } + + return errorcnt; +} + static const char usage_pubkey[] = "\n" "To sign a public key / create a new keyblock:\n" "\n" @@ -313,41 +421,46 @@ "To sign a raw firmware blob (FW_MAIN_A/B):\n" "\n" "Required PARAMS:\n" - " -s|--signprivate FILE.vbprivk The private firmware data key\n" - " -b|--keyblock FILE.keyblock The keyblock containing the\n" - " public firmware data key\n" - " -k|--kernelkey FILE.vbpubk The public kernel subkey\n" " -v|--version NUM The firmware version number\n" " [--fv] INFILE" " The raw firmware blob (FW_MAIN_A/B)\n" " [--outfile] OUTFILE Output VBLOCK_A/B\n" "\n" "Optional PARAMS:\n" + " -s|--signprivate FILE.vbprivk The private firmware data key\n" + " -b|--keyblock FILE.keyblock The keyblock containing the\n" + " public firmware data key\n" + " -k|--kernelkey FILE.vbpubk The public kernel subkey\n" " -f|--flags NUM The preamble flags value" " (default is 0)\n" + " -K|--keyset PATH Prefix of private firmware data" + " key,\n" + " keyblock and public kernel" + " subkey.\n" + " Prefix must be valid path with\n" + " optional file name prefix.\n" + " Used as defaults for -s, -b and" + " -k,\n" + " if not passed expliticly\n" + " (default is '%s')\n" "\n"; static void print_help_raw_firmware(int argc, char *argv[]) { - puts(usage_fw_main); + printf(usage_fw_main, DEFAULT_KEYSETDIR); } static const char usage_bios[] = "\n" "To sign a complete firmware image (bios.bin):\n" "\n" "Required PARAMS:\n" + " [--infile] INFILE Input firmware image (modified\n" + " in place if no OUTFILE given)\n" + "\n" + "Optional PARAMS:\n" " -s|--signprivate FILE.vbprivk The private firmware data key\n" " -b|--keyblock FILE.keyblock The keyblock containing the\n" " public firmware data key\n" " -k|--kernelkey FILE.vbpubk The public kernel subkey\n" - " [--infile] INFILE Input firmware image (modified\n" - " in place if no OUTFILE given)\n" - "\n" - "These are required if the A and B firmware differ:\n" - " -S|--devsign FILE.vbprivk The DEV private firmware data key\n" - " -B|--devkeyblock FILE.keyblock The keyblock containing the\n" - " DEV public firmware data key\n" - "\n" - "Optional PARAMS:\n" " -v|--version NUM The firmware version number" " (default %d)\n" " -f|--flags NUM The preamble flags value" @@ -355,21 +468,27 @@ " unchanged, or 0 if unknown)\n" " -d|--loemdir DIR Local OEM output vblock directory\n" " -l|--loemid STRING Local OEM vblock suffix\n" + " -K|--keyset PATH Prefix of private firmware data" + " key,\n" + " keyblock and public kernel" + " subkey.\n" + " Prefix must be valid path with\n" + " optional file name prefix.\n" + " Used as defaults for -s, -b and" + " -k,\n" + " if not passed expliticly\n" + " (default is '%s')\n" " [--outfile] OUTFILE Output firmware image\n" "\n"; static void print_help_bios_image(int argc, char *argv[]) { - printf(usage_bios, sign_option.version); + printf(usage_bios, sign_option.version, DEFAULT_KEYSETDIR); } static const char usage_new_kpart[] = "\n" "To create a new kernel partition image (/dev/sda2, /dev/mmcblk0p2):\n" "\n" "Required PARAMS:\n" - " -s|--signprivate FILE.vbprivk" - " The private key to sign the kernel blob\n" - " -b|--keyblock FILE.keyblock Keyblock containing the public\n" - " key to verify the kernel blob\n" " -v|--version NUM The kernel version number\n" " --bootloader FILE Bootloader stub\n" " --config FILE The kernel commandline file\n" @@ -379,6 +498,10 @@ " [--outfile] OUTFILE Output kernel partition or vblock\n" "\n" "Optional PARAMS:\n" + " -s|--signprivate FILE.vbprivk" + " The private key to sign the kernel blob\n" + " -b|--keyblock FILE.keyblock Keyblock containing the public\n" + " key to verify the kernel blob\n" " --kloadaddr NUM" " RAM address to load the kernel body\n" " (default %#x)\n" @@ -387,22 +510,33 @@ " --vblockonly Emit just the vblock (requires a\n" " distinct outfile)\n" " -f|--flags NUM The preamble flags value\n" + " -K|--keyset DIR Path to directory containing" + " private\n" + " kernel data key, and keyblock\n" + " -K|--keyset PATH Prefix of private kernel data key\n" + " and keyblock.\n" + " Prefix must be valid path with\n" + " optional file name prefix.\n" + " Used as defaults for -s and -b,\n" + " if not passed expliticly\n" + " (default is '%s')\n" "\n"; static void print_help_raw_kernel(int argc, char *argv[]) { - printf(usage_new_kpart, sign_option.kloadaddr, sign_option.padding); + printf(usage_new_kpart, sign_option.kloadaddr, sign_option.padding, + DEFAULT_KEYSETDIR); } static const char usage_old_kpart[] = "\n" "To resign an existing kernel partition (/dev/sda2, /dev/mmcblk0p2):\n" "\n" "Required PARAMS:\n" - " -s|--signprivate FILE.vbprivk" - " The private key to sign the kernel blob\n" " [--infile] INFILE Input kernel partition (modified\n" " in place if no OUTFILE given)\n" "\n" "Optional PARAMS:\n" + " -s|--signprivate FILE.vbprivk" + " The private key to sign the kernel blob\n" " -b|--keyblock FILE.keyblock Keyblock containing the public\n" " key to verify the kernel blob\n" " -v|--version NUM The kernel version number\n" @@ -413,10 +547,17 @@ " --vblockonly Emit just the vblock (requires a\n" " distinct OUTFILE)\n" " -f|--flags NUM The preamble flags value\n" + " -K|--keyset PATH Prefix of private kernel data" + " key.\n" + " Prefix must be valid path with\n" + " optional file name prefix.\n" + " Used as default for -s,\n" + " if not passed expliticly\n" + " (default is '%s')\n" "\n"; static void print_help_kern_preamble(int argc, char *argv[]) { - printf(usage_old_kpart, sign_option.padding); + printf(usage_old_kpart, sign_option.padding, DEFAULT_KEYSETDIR); } static void print_help_usbpd1(int argc, char *argv[]) @@ -595,12 +736,11 @@ {"signprivate", 1, NULL, 's'}, {"keyblock", 1, NULL, 'b'}, {"kernelkey", 1, NULL, 'k'}, - {"devsign", 1, NULL, 'S'}, - {"devkeyblock", 1, NULL, 'B'}, {"version", 1, NULL, 'v'}, {"flags", 1, NULL, 'f'}, {"loemdir", 1, NULL, 'd'}, {"loemid", 1, NULL, 'l'}, + {"keyset", 1, NULL, 'K'}, {"fv", 1, NULL, OPT_FV}, {"infile", 1, NULL, OPT_INFILE}, {"datapubkey", 1, NULL, OPT_INFILE}, /* alias */ @@ -629,7 +769,7 @@ {"help", 0, NULL, OPT_HELP}, {NULL, 0, NULL, 0}, }; -static const char *short_opts = ":s:b:k:S:B:v:f:d:l:"; +static const char *short_opts = ":s:b:k:v:f:d:l:K:"; /* Return zero on success */ static int parse_number_opt(const char *arg, const char *name, uint32_t *dest) @@ -648,12 +788,8 @@ { char *infile = 0; int i; - int ifd = -1; int errorcnt = 0; - uint8_t *buf; - uint32_t buf_len; char *e = 0; - int mapping; int helpind = 0; int longindex; @@ -682,21 +818,6 @@ errorcnt++; } break; - case 'S': - sign_option.devsignprivate = - vb2_read_private_key(optarg); - if (!sign_option.devsignprivate) { - fprintf(stderr, "Error reading %s\n", optarg); - errorcnt++; - } - break; - case 'B': - sign_option.devkeyblock = vb2_read_keyblock(optarg); - if (!sign_option.devkeyblock) { - fprintf(stderr, "Error reading %s\n", optarg); - errorcnt++; - } - break; case 'v': sign_option.version_specified = 1; sign_option.version = strtoul(optarg, &e, 0); @@ -718,6 +839,9 @@ case 'l': sign_option.loemid = optarg; break; + case 'K': + sign_option.keysetdir = optarg; + break; case OPT_FV: sign_option.fv_specified = 1; VBOOT_FALLTHROUGH; @@ -909,6 +1033,10 @@ sign_option.type = FILE_TYPE_RAW_FIRMWARE; } + /* Load keys and keyblocks from keyset path, if they were not provided + earlier. */ + errorcnt += load_keyset(); + VB2_DEBUG("type=%s\n", futil_file_type_name(sign_option.type)); /* Check the arguments for the type of thing we want to sign */ @@ -938,7 +1066,6 @@ * may want to read it instead. */ break; case FILE_TYPE_BIOS_IMAGE: - case FILE_TYPE_OLD_BIOS_IMAGE: errorcnt += no_opt_if(!sign_option.signprivate, "signprivate"); errorcnt += no_opt_if(!sign_option.keyblock, "keyblock"); errorcnt += no_opt_if(!sign_option.kernel_subkey, "kernelkey"); @@ -1010,56 +1137,18 @@ if (errorcnt) goto done; - if (sign_option.create_new_outfile) { - /* The input is read-only, the output is write-only. */ - mapping = MAP_RO; - VB2_DEBUG("open RO %s\n", infile); - ifd = open(infile, O_RDONLY); - if (ifd < 0) { - errorcnt++; - fprintf(stderr, "Can't open %s for reading: %s\n", - infile, strerror(errno)); - goto done; - } - } else { + if (!sign_option.create_new_outfile) { /* We'll read-modify-write the output file */ - mapping = MAP_RW; if (sign_option.inout_file_count > 1) futil_copy_file_or_die(infile, sign_option.outfile); - VB2_DEBUG("open RW %s\n", sign_option.outfile); infile = sign_option.outfile; - ifd = open(sign_option.outfile, O_RDWR); - if (ifd < 0) { - errorcnt++; - fprintf(stderr, "Can't open %s for writing: %s\n", - sign_option.outfile, strerror(errno)); - goto done; - } } - if (0 != futil_map_file(ifd, mapping, &buf, &buf_len)) { - errorcnt++; - goto done; - } - - errorcnt += futil_file_type_sign(sign_option.type, infile, - buf, buf_len); - - errorcnt += futil_unmap_file(ifd, mapping, buf, buf_len); - + errorcnt += futil_file_type_sign(sign_option.type, infile); done: - if (ifd >= 0 && close(ifd)) { - errorcnt++; - fprintf(stderr, "Error when closing ifd: %s\n", - strerror(errno)); - } - - if (sign_option.signprivate) - free(sign_option.signprivate); - if (sign_option.keyblock) - free(sign_option.keyblock); - if (sign_option.kernel_subkey) - free(sign_option.kernel_subkey); + free(sign_option.signprivate); + free(sign_option.keyblock); + free(sign_option.kernel_subkey); if (sign_option.prikey) vb2_private_key_free(sign_option.prikey);
diff --git a/futility/cmd_update.c b/futility/cmd_update.c index e4b3765..a77b224 100644 --- a/futility/cmd_update.c +++ b/futility/cmd_update.c
@@ -57,7 +57,6 @@ {"ccd", 0, NULL, OPT_CCD}, {"servo", 0, NULL, OPT_SERVO}, - {"servo_noreset", 0, NULL, OPT_SERVO_NORESET}, {"servo_port", 1, NULL, OPT_SERVO_PORT}, {"emulate", 1, NULL, OPT_EMULATE}, {"factory", 0, NULL, OPT_FACTORY}, @@ -112,14 +111,17 @@ " --pd_image=FILE \tPD firmware image (i.e, pd.bin)\n" "-t, --try \tTry A/B update on reboot if possible\n" "-a, --archive=PATH \tRead resources from archive\n" - " --manifest \tPrint out a JSON manifest and exit\n" - " --repack=DIR \tUpdates archive from DIR\n" " --unpack=DIR \tExtracts archive to DIR\n" "-p, --programmer=PRG\tChange AP (host) flashrom programmer\n" " --fast \tReduce read cycles and do not verify\n" " --quirks=LIST \tSpecify the quirks to apply\n" " --list-quirks \tPrint all available quirks\n" - "-m, --mode=MODE \tRun updater in specified mode\n" + "-m, --mode=MODE \tRun updater in the specified mode\n" + " --manifest \tScan the archive to print a manifest in JSON\n" + "\n" + " * If both --manifest and --fast are specified, the updater\n" + " will not scan the archive and simply dump the previously\n" + " cached manifest (may be out-dated) from the archive.\n" "\n" "Legacy and compatibility options:\n" " --factory \tAlias for --mode=factory\n" @@ -134,7 +136,6 @@ " --gbb_flags=FLAG\tOverride new GBB flags\n" " --ccd \tDo fast,force,wp=0,p=raiden_debug_spi\n" " --servo \tFlash using Servo (v2, v4, micro, ...)\n" - " --servo_noreset \tLike servo but with 'custom_rst=true'\n" " --servo_port=PRT\tOverride servod port, implies --servo\n" " --signature_id=S\tOverride signature ID for key files\n" " --sys_props=LIST\tList of system properties to override\n" @@ -144,21 +145,15 @@ argv[0]); } -static char *add_servo_noreset(char *programmer) +static void prepare_servo_control(const char *control_name, int on) { - char *ret; + char *cmd; + if (!control_name) + return; - if (strstr(programmer, "raiden_debug_spi:target=AP") == NULL) { - ERROR("servo_noreset only works for AP flashing over CCD.\n"); - free(programmer); - - return NULL; - } - - ASPRINTF(&ret, "%s,custom_rst=true", programmer); - free(programmer); - - return ret; + ASPRINTF(&cmd, "dut-control %s:%s", control_name, on ? "on" : "off"); + free(host_shell(cmd)); + free(cmd); } static int do_update(int argc, char *argv[]) @@ -166,7 +161,8 @@ struct updater_config *cfg; struct updater_config_arguments args = {0}; int i, errorcnt = 0, do_update = 1; - int detect_servo = 0, do_servo_cpu_fw_spi = 0, servo_noreset = 0; + int detect_servo = 0; + const char *prepare_ctrl_name = NULL; char *servo_programmer = NULL; char *endptr; @@ -211,6 +207,8 @@ break; case OPT_REPACK: args.repack = optarg; + ERROR("Sorry, --repack is only for the script.\n"); + errorcnt ++; break; case OPT_UNPACK: args.unpack = optarg; @@ -277,14 +275,6 @@ args.host_only = 1; detect_servo = 1; break; - case OPT_SERVO_NORESET: - args.fast_update = 1; - args.force_update = 1; - args.write_protection = "0"; - args.host_only = 1; - detect_servo = 1; - servo_noreset = 1; - break; case OPT_SERVO_PORT: setenv(ENV_SERVOD_PORT, optarg, 1); args.fast_update = 1; @@ -318,10 +308,7 @@ } if (!errorcnt && detect_servo) { - servo_programmer = host_detect_servo(&do_servo_cpu_fw_spi); - - if (servo_programmer && servo_noreset) - servo_programmer = add_servo_noreset(servo_programmer); + servo_programmer = host_detect_servo(&prepare_ctrl_name); if (!servo_programmer) errorcnt++; @@ -333,8 +320,7 @@ * update (i.e., in updater_setup_config) so we want to turn on * cpu_fw_spi mode now. */ - if (do_servo_cpu_fw_spi) - free(host_shell("dut-control cpu_fw_spi:on")); + prepare_servo_control(prepare_ctrl_name, 1); if (!errorcnt) errorcnt += updater_setup_config(cfg, &args, &do_update); @@ -353,8 +339,7 @@ errorcnt ? "aborted" : "exits successfully"); } - if (do_servo_cpu_fw_spi) - free(host_shell("dut-control cpu_fw_spi:off")); + prepare_servo_control(prepare_ctrl_name, 0); free(servo_programmer); updater_delete_config(cfg);
diff --git a/futility/cmd_validate_rec_mrc.c b/futility/cmd_validate_rec_mrc.c index 1d35bed..7ba5931 100644 --- a/futility/cmd_validate_rec_mrc.c +++ b/futility/cmd_validate_rec_mrc.c
@@ -222,31 +222,21 @@ infile = argv[optind++]; - fd = open(infile, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "Cannot open %s:%s\n", infile, strerror(errno)); + if (futil_open_and_map_file(infile, &fd, FILE_RO, &buff, &file_size) != + FILE_ERR_NONE) return 1; - } - - if (futil_map_file(fd, MAP_RO, &buff, &file_size) != FILE_ERR_NONE) { - fprintf(stderr, "Cannot map file %s\n", infile); - close(fd); - return 1; - } if (offset > file_size) { fprintf(stderr, "File size(%#x) smaller than offset(%#x)\n", file_size, offset); - futil_unmap_file(fd, MAP_RO, buff, file_size); - close(fd); + futil_unmap_and_close_file(fd, FILE_RO, buff, file_size); return 1; } if (get_mrc_data_slot((uint16_t *)(buff + offset), &data_offset, &data_size)) { fprintf(stderr, "Metadata block error\n"); - futil_unmap_file(fd, MAP_RO, buff, file_size); - close(fd); + futil_unmap_and_close_file(fd, FILE_RO, buff, file_size); return 1; } offset += data_offset; @@ -259,12 +249,10 @@ "offset=%#x, file size=%#x, data_size=%#x\n", offset, file_size, data_size); - if (futil_unmap_file(fd, MAP_RO, buff, file_size) != FILE_ERR_NONE) { - fprintf(stderr, "Failed to unmap file %s\n", infile); - ret = 1; - } + if (futil_unmap_and_close_file(fd, FILE_RO, buff, file_size) != + FILE_ERR_NONE) + return 1; - close(fd); return ret; }
diff --git a/futility/file_type.c b/futility/file_type.c index b55d13f..29c4667 100644 --- a/futility/file_type.c +++ b/futility/file_type.c
@@ -24,8 +24,8 @@ const char *desc; /* Functions to identify, display, and sign this type of file. */ enum futil_file_type (*recognize)(uint8_t *buf, uint32_t len); - int (*show)(const char *name, uint8_t *buf, uint32_t len, void *data); - int (*sign)(const char *name, uint8_t *buf, uint32_t len, void *data); + int (*show)(const char *name, void *data); + int (*sign)(const char *name, void *data); }; /* Populate a list of file types and operator functions. */ @@ -99,42 +99,29 @@ enum futil_file_err futil_file_type(const char *filename, enum futil_file_type *type) { - int ifd; - uint8_t *buf; - uint32_t buf_len; + int ifd = -1; + uint8_t *buf = NULL; + uint32_t buf_len = 0; struct stat sb; enum futil_file_err err = FILE_ERR_NONE; *type = FILE_TYPE_UNKNOWN; - ifd = open(filename, O_RDONLY); - if (ifd < 0) { - fprintf(stderr, "Can't open %s: %s\n", - filename, strerror(errno)); - return FILE_ERR_OPEN; - } + err = futil_open_file(filename, &ifd, FILE_RO); + if (err != FILE_ERR_NONE) + goto done; if (0 != fstat(ifd, &sb)) { - fprintf(stderr, "Can't stat input file: %s\n", - strerror(errno)); - close(ifd); - return FILE_ERR_STAT; + fprintf(stderr, "Can't stat input file: %s\n", strerror(errno)); + err = FILE_ERR_STAT; + goto done; } if (S_ISREG(sb.st_mode) || S_ISBLK(sb.st_mode)) { - err = futil_map_file(ifd, MAP_RO, &buf, &buf_len); - if (err) { - close(ifd); - return err; - } - + err = futil_map_file(ifd, FILE_RO, &buf, &buf_len); + if (err) + goto done; *type = futil_file_type_buf(buf, buf_len); - - err = futil_unmap_file(ifd, MAP_RO, buf, buf_len); - if (err) { - close(ifd); - return err; - } } else if (S_ISDIR(sb.st_mode)) { err = FILE_ERR_DIR; } else if (S_ISCHR(sb.st_mode)) { @@ -144,37 +131,27 @@ } else if (S_ISSOCK(sb.st_mode)) { err = FILE_ERR_SOCK; } - - if (close(ifd)) { - fprintf(stderr, "Error when closing %s: %s\n", - filename, strerror(errno)); - return FILE_ERR_CLOSE; - } - +done: + futil_unmap_and_close_file(ifd, FILE_RO, buf, buf_len); return err; } -int futil_file_type_show(enum futil_file_type type, - const char *filename, - uint8_t *buf, uint32_t len) +int futil_file_type_show(enum futil_file_type type, const char *filename) { if (futil_file_types[type].show) - return futil_file_types[type].show(filename, buf, len, 0); + return futil_file_types[type].show(filename, 0); fprintf(stderr, "Don't know how to show %s (type %s)\n", filename, futil_file_type_name(type)); return 1; } -int futil_file_type_sign(enum futil_file_type type, - const char *filename, - uint8_t *buf, uint32_t len) +int futil_file_type_sign(enum futil_file_type type, const char *filename) { if (futil_file_types[type].sign) - return futil_file_types[type].sign(filename, buf, len, 0); + return futil_file_types[type].sign(filename, 0); fprintf(stderr, "Don't know how to sign %s (type %s)\n", filename, futil_file_type_name(type)); return 1; } -
diff --git a/futility/file_type.h b/futility/file_type.h index e1efe76..5a074b3 100644 --- a/futility/file_type.h +++ b/futility/file_type.h
@@ -40,22 +40,18 @@ enum futil_file_type *type); /* - * Call the show() method on a buffer containing a specific file type. + * Call the show() method on a file containing a specific file type. * Returns zero on success. It's up to the caller to ensure that only valid * file types are invoked. */ -int futil_file_type_show(enum futil_file_type type, - const char *filename, - uint8_t *buf, uint32_t len); +int futil_file_type_show(enum futil_file_type type, const char *filename); /* - * Call the sign() method on a buffer containing a specific file type. + * Call the sign() method on a file with specific file type. * Returns zero on success. It's up to the caller to ensure that only valid * file types are invoked. */ -int futil_file_type_sign(enum futil_file_type type, - const char *filename, - uint8_t *buf, uint32_t len); +int futil_file_type_sign(enum futil_file_type type, const char *filename); /* * Declare the file_type functions. Certain functions are reused for more than @@ -66,14 +62,21 @@ #define R_(FOO) \ enum futil_file_type FOO(uint8_t *buf, uint32_t len); #define S_(FOO) \ - int FOO(const char *name, uint8_t *buf, uint32_t len, void *data); + int FOO(const char *name, void *data); #define NONE #define FILE_TYPE(A, B, C, D, E, F) D E F #include "file_type.inc" #undef FILE_TYPE #undef NONE +#undef SG_ #undef S_ #undef R_ #pragma GCC diagnostic pop +/* Declared for use inside other show functions. */ +int show_fw_preamble_buf(const char *name, uint8_t *buf, uint32_t len, + void *data); +int show_vb21_pubkey_buf(const char *name, uint8_t *buf, uint32_t len, + void *data); + #endif /* VBOOT_REFERENCE_FILE_TYPE_H_ */
diff --git a/futility/file_type.inc b/futility/file_type.inc index 0d3acc9..7a32f9b 100644 --- a/futility/file_type.inc +++ b/futility/file_type.inc
@@ -19,10 +19,6 @@ R_(ft_recognize_bios_image), S_(ft_show_bios), S_(ft_sign_bios)) -FILE_TYPE(OLD_BIOS_IMAGE, "oldbios", "Cr-48 Chrome OS BIOS image", - R_(ft_recognize_bios_image), - S_(ft_show_bios), - S_(ft_sign_bios)) FILE_TYPE(GBB, "gbb", "GBB", R_(ft_recognize_gbb), S_(ft_show_gbb),
diff --git a/futility/file_type_bios.c b/futility/file_type_bios.c index fe0b223..29ecfd4 100644 --- a/futility/file_type_bios.c +++ b/futility/file_type_bios.c
@@ -5,10 +5,12 @@ #include <errno.h> #include <limits.h> +#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <string.h> +#include "cbfstool.h" #include "file_type_bios.h" #include "file_type.h" #include "fmap.h" @@ -27,21 +29,11 @@ _Static_assert(ARRAY_SIZE(fmap_name) == NUM_BIOS_COMPONENTS, "Size of fmap_name[] should match NUM_BIOS_COMPONENTS"); -static const char * const fmap_oldname[] = { - "GBB Area", /* BIOS_FMAP_GBB */ - "Firmware A Data", /* BIOS_FMAP_FW_MAIN_A */ - "Firmware B Data", /* BIOS_FMAP_FW_MAIN_B */ - "Firmware A Key", /* BIOS_FMAP_VBLOCK_A */ - "Firmware B Key", /* BIOS_FMAP_VBLOCK_B */ -}; -_Static_assert(ARRAY_SIZE(fmap_oldname) == NUM_BIOS_COMPONENTS, - "Size of fmap_oldname[] should match NUM_BIOS_COMPONENTS"); - static void fmap_limit_area(FmapAreaHeader *ah, uint32_t len) { uint32_t sum = ah->area_offset + ah->area_size; if (sum < ah->area_size || sum > len) { - VB2_DEBUG("%s %#x + %#x > %#x\n", + VB2_DEBUG("%.*s %#x + %#x > %#x\n", FMAP_NAMELEN, ah->area_name, ah->area_offset, ah->area_size, len); ah->area_offset = 0; ah->area_size = 0; @@ -50,7 +42,8 @@ /** Show functions **/ -int ft_show_gbb(const char *name, uint8_t *buf, uint32_t len, void *data) +static int show_gbb_buf(const char *name, uint8_t *buf, uint32_t len, + void *data) { struct vb2_gbb_header *gbb = (struct vb2_gbb_header *)buf; struct bios_state_s *state = (struct bios_state_s *)data; @@ -85,7 +78,7 @@ if (retval) { printf("GBB header is invalid, ignoring content\n"); - return 1; + return retval; } printf("GBB content:\n"); @@ -135,6 +128,23 @@ return retval; } +int ft_show_gbb(const char *name, void *data) +{ + int retval = 0; + int fd = -1; + uint8_t *buf; + uint32_t len; + + retval = futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len); + if (retval) + return 1; + + retval = show_gbb_buf(name, buf, len, data); + + futil_unmap_and_close_file(fd, FILE_RO, buf, len); + return retval; +} + /* * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image. * @@ -165,16 +175,16 @@ /* Functions to call to show the bios components */ static int (*fmap_show_fn[])(const char *name, uint8_t *buf, uint32_t len, void *data) = { - ft_show_gbb, + show_gbb_buf, fmap_show_fw_main, fmap_show_fw_main, - ft_show_fw_preamble, - ft_show_fw_preamble, + show_fw_preamble_buf, + show_fw_preamble_buf, }; _Static_assert(ARRAY_SIZE(fmap_show_fn) == NUM_BIOS_COMPONENTS, "Size of fmap_show_fn[] should match NUM_BIOS_COMPONENTS"); -int ft_show_bios(const char *name, uint8_t *buf, uint32_t len, void *data) +int ft_show_bios(const char *name, void *data) { FmapHeader *fmap; FmapAreaHeader *ah = 0; @@ -182,6 +192,13 @@ enum bios_component c; int retval = 0; struct bios_state_s state; + int fd = -1; + uint8_t *buf; + uint32_t len; + + retval = futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len); + if (retval) + return 1; memset(&state, 0, sizeof(state)); @@ -191,8 +208,7 @@ fmap = fmap_find(buf, len); for (c = 0; c < NUM_BIOS_COMPONENTS; c++) { /* We know one of these will work, too */ - if (fmap_find_by_name(buf, len, fmap, fmap_name[c], &ah) || - fmap_find_by_name(buf, len, fmap, fmap_oldname[c], &ah)) { + if (fmap_find_by_name(buf, len, fmap, fmap_name[c], &ah)) { /* But the file might be truncated */ fmap_limit_area(ah, len); /* The name is not necessarily null-terminated */ @@ -217,119 +233,41 @@ } } + futil_unmap_and_close_file(fd, FILE_RO, buf, len); return retval; } /** Sign functions **/ -/* - * This handles FW_MAIN_A and FW_MAIN_B while signing a BIOS image. The data is - * just the RW firmware blob so there's nothing useful to do with it, but we'll - * mark it as valid so that we'll know that this FMAP area exists and can - * be signed. - */ -static int fmap_sign_fw_main(const char *name, uint8_t *buf, uint32_t len, - void *data) -{ - struct bios_state_s *state = (struct bios_state_s *)data; - state->area[state->c].is_valid = 1; - return 0; -} - -/* - * This handles VBLOCK_A and VBLOCK_B while processing a BIOS image. We don't - * do any signing here. We just check to see if the existing FMAP area contains - * a firmware preamble so we can preserve its contents. We do the signing once - * we've looked over all the components. - */ -static int fmap_sign_fw_preamble(const char *name, uint8_t *buf, uint32_t len, - void *data) -{ - static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] - __attribute__((aligned(VB2_WORKBUF_ALIGN))); - static struct vb2_workbuf wb; - vb2_workbuf_init(&wb, workbuf, sizeof(workbuf)); - - struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf; - struct bios_state_s *state = (struct bios_state_s *)data; - - /* - * If we have a valid keyblock and fw_preamble, then we can use them to - * determine the size of the firmware body. Otherwise, we'll have to - * just sign the whole region. - */ - if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) { - fprintf(stderr, "Warning: %s keyblock is invalid. " - "Signing the entire FW FMAP region...\n", name); - goto whatever; - } - - if (vb2_packed_key_looks_ok(&keyblock->data_key, - keyblock->data_key.key_offset + - keyblock->data_key.key_size)) { - fprintf(stderr, "Warning: %s public key is invalid. " - "Signing the entire FW FMAP region...\n", name); - goto whatever; - } - uint32_t more = keyblock->keyblock_size; - struct vb2_fw_preamble *preamble = - (struct vb2_fw_preamble *)(buf + more); - uint32_t fw_size = preamble->body_signature.data_size; - struct bios_area_s *fw_body_area = 0; - - switch (state->c) { - case BIOS_FMAP_VBLOCK_A: - fw_body_area = &state->area[BIOS_FMAP_FW_MAIN_A]; - /* Preserve the flags if they're not specified */ - if (!sign_option.flags_specified) - sign_option.flags = preamble->flags; - break; - case BIOS_FMAP_VBLOCK_B: - fw_body_area = &state->area[BIOS_FMAP_FW_MAIN_B]; - break; - default: - FATAL("Can only handle VBLOCK_A or VBLOCK_B\n"); - } - - if (fw_size > fw_body_area->len) { - fprintf(stderr, - "%s says the firmware is larger than we have\n", - name); - return 1; - } - - /* Update the firmware size */ - fw_body_area->len = fw_size; - -whatever: - state->area[state->c].is_valid = 1; - - return 0; -} - static int write_new_preamble(struct bios_area_s *vblock, struct bios_area_s *fw_body, struct vb2_private_key *signkey, struct vb2_keyblock *keyblock) { - struct vb2_signature *body_sig; - struct vb2_fw_preamble *preamble; + struct vb2_signature *body_sig = NULL; + struct vb2_fw_preamble *preamble = NULL; + int retval = 1; body_sig = vb2_calculate_signature(fw_body->buf, fw_body->len, signkey); if (!body_sig) { - fprintf(stderr, "Error calculating body signature\n"); - return 1; + ERROR("Error calculating body signature\n"); + goto end; } - preamble = vb2_create_fw_preamble(sign_option.version, + preamble = vb2_create_fw_preamble(vblock->version, (struct vb2_packed_key *)sign_option.kernel_subkey, body_sig, signkey, - sign_option.flags); + vblock->flags); if (!preamble) { - fprintf(stderr, "Error creating firmware preamble.\n"); + ERROR("Error creating firmware preamble.\n"); free(body_sig); - return 1; + goto end; + } + + if (keyblock->keyblock_size + preamble->preamble_size > vblock->len) { + ERROR("Keyblock and preamble do not fit in VBLOCK.\n"); + goto end; } /* Write the new keyblock */ @@ -337,11 +275,13 @@ memcpy(vblock->buf, keyblock, more); /* and the new preamble */ memcpy(vblock->buf + more, preamble, preamble->preamble_size); + retval = 0; +end: free(preamble); free(body_sig); - return 0; + return retval; } static int write_loem(const char *ab, struct bios_area_s *vblock) @@ -387,123 +327,230 @@ struct bios_area_s *fw_b = &state->area[BIOS_FMAP_FW_MAIN_B]; int retval = 0; - if (!vblock_a->is_valid || !vblock_b->is_valid || - !fw_a->is_valid || !fw_b->is_valid) { + if (!vblock_a->is_valid || !fw_a->is_valid) { fprintf(stderr, "Something's wrong. Not changing anything\n"); return 1; } - /* Do A & B differ ? */ - if (fw_a->len != fw_b->len || - memcmp(fw_a->buf, fw_b->buf, fw_a->len)) { - /* Yes, must use DEV keys for A */ - if (!sign_option.devsignprivate || !sign_option.devkeyblock) { - fprintf(stderr, - "FW A & B differ. DEV keys are required.\n"); - return 1; - } - retval |= write_new_preamble(vblock_a, fw_a, - sign_option.devsignprivate, - sign_option.devkeyblock); - } else { - retval |= write_new_preamble(vblock_a, fw_a, - sign_option.signprivate, - sign_option.keyblock); - } - - /* FW B is always normal keys */ - retval |= write_new_preamble(vblock_b, fw_b, - sign_option.signprivate, + retval |= write_new_preamble(vblock_a, fw_a, sign_option.signprivate, sign_option.keyblock); - - + if (vblock_b->is_valid && fw_b->is_valid) + retval |= write_new_preamble(vblock_b, fw_b, + sign_option.signprivate, + sign_option.keyblock); + else + INFO("BIOS image does not have %s. Signing only %s\n", + fmap_name[BIOS_FMAP_FW_MAIN_B], + fmap_name[BIOS_FMAP_FW_MAIN_A]); if (sign_option.loemid) { retval |= write_loem("A", vblock_a); - retval |= write_loem("B", vblock_b); + if (vblock_b->is_valid) + retval |= write_loem("B", vblock_b); } return retval; } -/* Functions to call while preparing to sign the bios */ -static int (*fmap_sign_fn[])(const char *name, uint8_t *buf, uint32_t len, - void *data) = { - 0, - fmap_sign_fw_main, - fmap_sign_fw_main, - fmap_sign_fw_preamble, - fmap_sign_fw_preamble, -}; -_Static_assert(ARRAY_SIZE(fmap_sign_fn) == NUM_BIOS_COMPONENTS, - "Size of fmap_sign_fn[] should match NUM_BIOS_COMPONENTS"); - -int ft_sign_bios(const char *name, uint8_t *buf, uint32_t len, void *data) +/* Prepare firmware slot for signing. + If fw_size is not zero, then it will be used as new length of signed area, + for zero the length will be taken form FlashMap or preamble. */ +static int prepare_slot(uint8_t *buf, uint32_t len, size_t fw_size, + enum bios_component fw_c, enum bios_component vblock_c, + struct bios_state_s *state) { FmapHeader *fmap; - FmapAreaHeader *ah = 0; - char ah_name[FMAP_NAMELEN + 1]; - enum bios_component c; - int retval = 0; - struct bios_state_s state; + FmapAreaHeader *ah; + const char *fw_main_name = fmap_name[fw_c]; + const char *vblock_name = fmap_name[vblock_c]; + static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] + __attribute__((aligned(VB2_WORKBUF_ALIGN))); + static struct vb2_workbuf wb; - memset(&state, 0, sizeof(state)); - - /* We've already checked, so we know this will work. */ fmap = fmap_find(buf, len); - for (c = 0; c < NUM_BIOS_COMPONENTS; c++) { - /* We know one of these will work, too */ - if (fmap_find_by_name(buf, len, fmap, fmap_name[c], &ah) || - fmap_find_by_name(buf, len, fmap, fmap_oldname[c], &ah)) { - /* But the file might be truncated */ - fmap_limit_area(ah, len); - /* The name is not necessarily null-terminated */ - snprintf(ah_name, sizeof(ah_name), "%s", ah->area_name); + vb2_workbuf_init(&wb, workbuf, sizeof(workbuf)); - /* Update the state we're passing around */ - state.c = c; - state.area[c].buf = buf + ah->area_offset; - state.area[c].len = ah->area_size; + VB2_DEBUG("Preparing areas: %s and %s\n", fw_main_name, vblock_name); - VB2_DEBUG("examining FMAP area %d (%s)," - " offset=0x%08x len=0x%08x\n", - c, ah_name, ah->area_offset, ah->area_size); + /* FW_MAIN */ + if (!fmap_find_by_name(buf, len, fmap, fw_main_name, &ah)) { + ERROR("%s area not found in FMAP\n", fw_main_name); + return 1; + } + fmap_limit_area(ah, len); + state->area[fw_c].buf = buf + ah->area_offset; + state->area[fw_c].is_valid = 1; + if (fw_size > ah->area_size) { + ERROR("%s size is incorrect.\n", fmap_name[fw_c]); + return 1; + } else if (fw_size) { + state->area[fw_c].len = fw_size; + } else { + WARN("%s does not contain CBFS. Trying to sign entire area.\n", + fmap_name[fw_c]); + state->area[fw_c].len = ah->area_size; + } - /* Go look at it, but abort on error */ - if (fmap_sign_fn[c]) - retval += fmap_sign_fn[c](ah_name, - state.area[c].buf, - state.area[c].len, - &state); + /* Corresponding VBLOCK */ + if (!fmap_find_by_name(buf, len, fmap, vblock_name, &ah)) { + ERROR("%s area not found in FMAP\n", vblock_name); + return 1; + } + fmap_limit_area(ah, len); + state->area[vblock_c].buf = buf + ah->area_offset; + state->area[vblock_c].len = ah->area_size; + + struct vb2_keyblock *keyblock = + (struct vb2_keyblock *)state->area[vblock_c].buf; + int keyblock_valid = 0; + + if (vb2_verify_keyblock_hash(keyblock, state->area[vblock_c].len, + &wb) != VB2_SUCCESS) { + WARN("%s keyblock is invalid.\n", vblock_name); + goto end; + } + + if (vb2_packed_key_looks_ok(&keyblock->data_key, + keyblock->data_key.key_offset + + keyblock->data_key.key_size)) { + WARN("%s public key is invalid.\n", vblock_name); + goto end; + } + + struct vb2_public_key data_key; + if (vb2_unpack_key(&data_key, &keyblock->data_key) != VB2_SUCCESS) { + WARN("%s data key is invalid. Failed to parse.\n", vblock_name); + goto end; + } + + if (keyblock->keyblock_size + sizeof(struct vb2_fw_preamble) > + state->area[vblock_c].len) { + ERROR("%s is invalid. Keyblock and preamble do not fit.\n", + vblock_name); + goto end; + } + + struct vb2_fw_preamble *preamble = + (struct vb2_fw_preamble *)(state->area[vblock_c].buf + + keyblock->keyblock_size); + if (vb2_verify_fw_preamble(preamble, + state->area[vblock_c].len - + keyblock->keyblock_size, + &data_key, &wb)) { + WARN("%s preamble is invalid.\n", vblock_name); + goto end; + } + + if (fw_size == 0) { + if (preamble->body_signature.data_size > + state->area[fw_c].len) { + ERROR("%s says the firmware is larger than we have.\n", + vblock_name); + goto end; + } else { + state->area[fw_c].len = + preamble->body_signature.data_size; } } - retval += sign_bios_at_end(&state); + keyblock_valid = 1; +end: + if (sign_option.flags_specified) + state->area[vblock_c].flags = sign_option.flags; + else if (keyblock_valid) + state->area[vblock_c].flags = preamble->flags; + else + state->area[vblock_c].flags = 0; + + if (sign_option.version_specified) + state->area[vblock_c].version = sign_option.version; + else if (keyblock_valid) + state->area[vblock_c].version = preamble->firmware_version; + else + state->area[vblock_c].version = 1; + + state->area[vblock_c].is_valid = 1; + + return 0; +} + +int ft_sign_bios(const char *name, void *data) +{ + int retval = 0; + struct bios_state_s state; + int fd = -1; + uint8_t *buf = NULL; + uint32_t len = 0; + size_t fw_main_a_size = 0; + size_t fw_main_b_size = 0; + + bool fw_main_a_in_cbfs_mode = + cbfstool_truncate(name, fmap_name[BIOS_FMAP_FW_MAIN_A], + &fw_main_a_size) == VB2_SUCCESS; + + bool fw_main_b_in_cbfs_mode = + cbfstool_truncate(name, fmap_name[BIOS_FMAP_FW_MAIN_B], + &fw_main_b_size) == VB2_SUCCESS; + + if (fw_main_a_in_cbfs_mode) + VB2_DEBUG("CBFS found in area %s\n", + fmap_name[BIOS_FMAP_FW_MAIN_A]); + else + VB2_DEBUG("CBFS not found in area %s\n", + fmap_name[BIOS_FMAP_FW_MAIN_A]); + + if (fw_main_b_in_cbfs_mode) + VB2_DEBUG("CBFS found in area %s\n", + fmap_name[BIOS_FMAP_FW_MAIN_B]); + else + VB2_DEBUG("CBFS not found in area %s\n", + fmap_name[BIOS_FMAP_FW_MAIN_B]); + + if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option), + &buf, &len)) + return 1; + + memset(&state, 0, sizeof(state)); + + retval = prepare_slot(buf, len, fw_main_a_size, BIOS_FMAP_FW_MAIN_A, + BIOS_FMAP_VBLOCK_A, &state); + if (retval) + goto done; + + retval = prepare_slot(buf, len, fw_main_b_size, BIOS_FMAP_FW_MAIN_B, + BIOS_FMAP_VBLOCK_B, &state); + if (retval && state.area[BIOS_FMAP_FW_MAIN_B].is_valid) + goto done; + + retval = sign_bios_at_end(&state); +done: + futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len); return retval; } enum futil_file_type ft_recognize_bios_image(uint8_t *buf, uint32_t len) { FmapHeader *fmap; - enum bios_component c; fmap = fmap_find(buf, len); if (!fmap) return FILE_TYPE_UNKNOWN; - for (c = 0; c < NUM_BIOS_COMPONENTS; c++) - if (!fmap_find_by_name(buf, len, fmap, fmap_name[c], 0)) - break; - if (c == NUM_BIOS_COMPONENTS) - return FILE_TYPE_BIOS_IMAGE; + /* Correct BIOS image should contain at least GBB, FW_MAIN_A and + VBLOCK_A areas. FW_MAIN_B and VBLOCK_B are optional, but will be + signed or shown if present. */ + const int gbb_and_a_slot_ok = + fmap_find_by_name(buf, len, fmap, fmap_name[BIOS_FMAP_GBB], + 0) != NULL && + fmap_find_by_name(buf, len, fmap, + fmap_name[BIOS_FMAP_FW_MAIN_A], 0) != NULL && + fmap_find_by_name(buf, len, fmap, fmap_name[BIOS_FMAP_VBLOCK_A], + 0) != NULL; - for (c = 0; c < NUM_BIOS_COMPONENTS; c++) - if (!fmap_find_by_name(buf, len, fmap, fmap_oldname[c], 0)) - break; - if (c == NUM_BIOS_COMPONENTS) - return FILE_TYPE_OLD_BIOS_IMAGE; + if (gbb_and_a_slot_ok) + return FILE_TYPE_BIOS_IMAGE; return FILE_TYPE_UNKNOWN; }
diff --git a/futility/file_type_bios.h b/futility/file_type_bios.h index ef40107..8aa2d63 100644 --- a/futility/file_type_bios.h +++ b/futility/file_type_bios.h
@@ -28,6 +28,10 @@ uint8_t *buf; uint32_t len; uint32_t is_valid; + + /* VBLOCK only */ + uint32_t flags; + uint32_t version; }; /* State to track as we visit all components */
diff --git a/futility/file_type_rwsig.c b/futility/file_type_rwsig.c index a09782c..b595e25 100644 --- a/futility/file_type_rwsig.c +++ b/futility/file_type_rwsig.c
@@ -58,7 +58,7 @@ sig->data_size); } -int ft_show_rwsig(const char *name, uint8_t *buf, uint32_t len, void *nuthin) +int ft_show_rwsig(const char *name, void *nuthin) { const struct vb21_signature *sig = 0; const struct vb21_packed_key *pkey = show_option.pkey; @@ -71,6 +71,15 @@ uint8_t *data; FmapHeader *fmap; int i; + int fd = -1; + uint8_t *buf; + uint32_t len; + int rv; + + if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len)) + return 1; + + rv = 1; VB2_DEBUG("name %s len 0x%08x (%d)\n", name, len, len); @@ -81,7 +90,8 @@ show_sig(name, sig); if (!show_option.fv) { printf("No data available to verify\n"); - return show_option.strict; + rv = show_option.strict; + goto done; } data = show_option.fv; data_size = show_option.fv_size; @@ -99,15 +109,15 @@ fmap_find_by_name(buf, len, fmap, "KEY_RO", 0); if (pkey) - ft_show_vb21_pubkey(name, (uint8_t *)pkey, - pkey->c.total_size, NULL); + show_vb21_pubkey_buf(name, (uint8_t *)pkey, + pkey->c.total_size, NULL); } sig = (const struct vb21_signature *) fmap_find_by_name(buf, len, fmap, "SIG_RW", &fmaparea); if (!sig) { VB2_DEBUG("No SIG_RW in FMAP.\n"); - return 1; + goto done; } sig_size = fmaparea->area_size; @@ -116,7 +126,7 @@ (uint8_t*)sig - buf, sig_size); if (VB2_SUCCESS != vb21_verify_signature(sig, sig_size)) - return 1; + goto done; show_sig(name, sig); data = fmap_find_by_name(buf, len, fmap, "EC_RW", &fmaparea); @@ -129,7 +139,7 @@ if (!data) { VB2_DEBUG("No EC_RW in FMAP.\n"); - return 1; + goto done; } } else { /* Or maybe this is just the RW portion, that does not @@ -141,7 +151,7 @@ if (len < sig_size) { VB2_DEBUG("File is too small\n"); - return 1; + goto done; } sig = (const struct vb21_signature *)(buf + len - sig_size); @@ -151,13 +161,14 @@ data_size = sig->data_size; total_data_size = len - sig_size; } else { - return 1; + goto done; } } if (!pkey) { printf("No public key available to verify with\n"); - return show_option.strict; + rv = show_option.strict; + goto done; } /* We already did this once, so it should work again */ @@ -165,12 +176,12 @@ (const uint8_t *)pkey, pkey->c.total_size)) { VB2_DEBUG("Can't unpack pubkey\n"); - return 1; + goto done; } if (data_size > total_data_size) { VB2_DEBUG("Invalid signature data_size: bigger than total area size.\n"); - return 1; + goto done; } /* The sig is destroyed by the verify operation, so make a copy */ @@ -185,7 +196,7 @@ (const struct vb2_public_key *)&key, &wb)) { fprintf(stderr, "Signature verification failed\n"); - return 1; + goto done; } } @@ -193,33 +204,46 @@ for (i = data_size; i < total_data_size; i++) { if (data[i] != 0xff) { fprintf(stderr, "Padding verification failed\n"); - return 1; + goto done; } } printf("Signature verification succeeded.\n"); - return 0; + rv = 0; +done: + futil_unmap_and_close_file(fd, FILE_RO, buf, len); + return rv; } -int ft_sign_rwsig(const char *name, uint8_t *buf, uint32_t len, void *nuthin) +int ft_sign_rwsig(const char *name, void *nuthin) { struct vb21_signature *tmp_sig = 0; struct vb2_public_key *pubkey = 0; struct vb21_packed_key *packedkey = 0; uint8_t *keyb_data = 0; uint32_t keyb_size; - uint8_t* data = buf; /* data to be signed */ - uint32_t r, data_size = len, sig_size = SIGNATURE_RSVD_SIZE; + uint8_t *data; /* data to be signed */ + uint32_t r, data_size, sig_size = SIGNATURE_RSVD_SIZE; int retval = 1; FmapHeader *fmap = NULL; FmapAreaHeader *fmaparea; struct vb21_signature *old_sig = 0; + uint8_t *buf = NULL; + uint32_t len; + int fd = -1; + + if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option), + &buf, &len)) + return 1; + + data = buf; + data_size = len; VB2_DEBUG("name %s len 0x%08x (%d)\n", name, len, len); /* If we don't have a distinct OUTFILE, look for an existing sig */ if (sign_option.inout_file_count < 2) { - fmap = fmap_find(buf, len); + fmap = fmap_find(data, len); if (fmap) { /* This looks like a full image. */ @@ -395,14 +419,12 @@ /* Finally */ retval = 0; done: - if (tmp_sig) - free(tmp_sig); + futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len); + free(tmp_sig); if (pubkey) vb2_public_key_free(pubkey); - if (packedkey) - free(packedkey); - if (keyb_data) - free(keyb_data); + free(packedkey); + free(keyb_data); return retval; }
diff --git a/futility/file_type_usbpd1.c b/futility/file_type_usbpd1.c index 9379188..a128a99 100644 --- a/futility/file_type_usbpd1.c +++ b/futility/file_type_usbpd1.c
@@ -78,7 +78,7 @@ return 1; } -int ft_sign_usbpd1(const char *name, uint8_t *buf, uint32_t len, void *data) +int ft_sign_usbpd1(const char *name, void *data) { struct vb2_private_key *key_ptr = 0; struct vb21_signature *sig_ptr = 0; @@ -94,6 +94,13 @@ uint32_t ro_offset; uint32_t rw_offset; uint32_t r; + uint8_t *buf = NULL; + uint32_t len; + int fd = -1; + + if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option), + &buf, &len)) + return 1; VB2_DEBUG("name %s len %#.8x (%d)\n", name, len, len); @@ -237,6 +244,7 @@ /* Finally */ retval = 0; done: + futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len); if (key_ptr) vb2_private_key_free(key_ptr); if (keyb_data) @@ -425,35 +433,47 @@ } -int ft_show_usbpd1(const char *name, uint8_t *buf, uint32_t len, void *data) +int ft_show_usbpd1(const char *name, void *data) { uint32_t ro_size, rw_size, ro_offset, rw_offset; int s, h; + int fd = -1; + uint8_t *buf; + uint32_t len; + int rv = 1; + + if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len)) + return 1; VB2_DEBUG("name %s len 0x%08x (%d)\n", name, len, len); /* Get image locations */ if (!parse_size_opts(len, &ro_size, &rw_size, &ro_offset, &rw_offset)) - return 1; + goto done; /* TODO: If we don't have a RO image, ask for a public key * TODO: If we're given an external public key, use it (and its alg) */ if (!ro_size) { printf("Can't find the public key\n"); - return 1; + goto done; } /* TODO: Only loop through the numbers we haven't been given */ - for (s = 0; s < ARRAY_SIZE(sigs); s++) - for (h = 0; h < ARRAY_SIZE(hashes); h++) - if (!check_self_consistency(buf, name, - ro_size, rw_size, + for (s = 0; s < ARRAY_SIZE(sigs); s++) { + for (h = 0; h < ARRAY_SIZE(hashes); h++) { + if (!check_self_consistency(buf, name, ro_size, rw_size, ro_offset, rw_offset, - sigs[s], hashes[h])) - return 0; + sigs[s], hashes[h])) { + rv = 0; + goto done; + } + } + } printf("This doesn't appear to be a complete usbpd1 image\n"); - return 1; +done: + futil_unmap_and_close_file(fd, FILE_RO, buf, len); + return rv; } enum futil_file_type ft_recognize_usbpd1(uint8_t *buf, uint32_t len)
diff --git a/futility/futility.h b/futility/futility.h index 9d40ba7..fa4d3de 100644 --- a/futility/futility.h +++ b/futility/futility.h
@@ -132,13 +132,26 @@ FILE_ERR_SOCK, }; +enum file_mode { + FILE_RO, + FILE_RW, +}; + +enum futil_file_err futil_open_file(const char *infile, int *fd, + enum file_mode mode); +enum futil_file_err futil_close_file(int fd); + /* Wrapper for mmap/munmap. Skips stupidly large files. */ -#define MAP_RO 0 -#define MAP_RW 1 -enum futil_file_err futil_map_file(int fd, int writeable, - uint8_t **buf, uint32_t *len); -enum futil_file_err futil_unmap_file(int fd, int writeable, - uint8_t *buf, uint32_t len); +enum futil_file_err futil_map_file(int fd, enum file_mode mode, uint8_t **buf, + uint32_t *len); +enum futil_file_err futil_unmap_file(int fd, enum file_mode mode, uint8_t *buf, + uint32_t len); + +enum futil_file_err futil_open_and_map_file(const char *infile, int *fd, + enum file_mode mode, uint8_t **buf, + uint32_t *len); +enum futil_file_err futil_unmap_and_close_file(int fd, enum file_mode mode, + uint8_t *buf, uint32_t len); /* * Parse input string as a hex representation of size len, exit with error if
diff --git a/futility/futility_options.h b/futility/futility_options.h index a79505c..32f240a 100644 --- a/futility/futility_options.h +++ b/futility/futility_options.h
@@ -34,8 +34,7 @@ struct vb2_private_key *signprivate; struct vb2_keyblock *keyblock; struct vb2_packed_key *kernel_subkey; - struct vb2_private_key *devsignprivate; - struct vb2_keyblock *devkeyblock; + const char *keysetdir; uint32_t version; int version_specified; uint32_t flags; @@ -67,4 +66,7 @@ }; extern struct sign_option_s sign_option; +#define FILE_MODE_SIGN(sign_options) \ + (sign_options.create_new_outfile ? FILE_RO : FILE_RW) + #endif /* VBOOT_REFERENCE_FUTILITY_OPTIONS_H_ */
diff --git a/futility/misc.c b/futility/misc.c index 76b8ad1..4aec13a 100644 --- a/futility/misc.c +++ b/futility/misc.c
@@ -5,6 +5,7 @@ #include <assert.h> #include <errno.h> +#include <fcntl.h> #if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__) #include <linux/fs.h> /* For BLKGETSIZE64 */ #endif @@ -258,8 +259,40 @@ exit(1); } +enum futil_file_err futil_open_file(const char *infile, int *fd, + enum file_mode mode) +{ + if (mode == FILE_RW) { + VB2_DEBUG("open RW %s\n", infile); + *fd = open(infile, O_RDWR); + if (*fd < 0) { + fprintf(stderr, "Can't open %s for writing: %s\n", + infile, strerror(errno)); + return FILE_ERR_OPEN; + } + } else { + VB2_DEBUG("open RO %s\n", infile); + *fd = open(infile, O_RDONLY); + if (*fd < 0) { + fprintf(stderr, "Can't open %s for reading: %s\n", + infile, strerror(errno)); + return FILE_ERR_OPEN; + } + } + return FILE_ERR_NONE; +} -enum futil_file_err futil_map_file(int fd, int writeable, +enum futil_file_err futil_close_file(int fd) +{ + if (fd >= 0 && close(fd)) { + fprintf(stderr, "Error when closing ifd: %s\n", + strerror(errno)); + return FILE_ERR_CLOSE; + } + return FILE_ERR_NONE; +} + +enum futil_file_err futil_map_file(int fd, enum file_mode mode, uint8_t **buf, uint32_t *len) { struct stat sb; @@ -284,7 +317,7 @@ } reasonable_len = (uint32_t)sb.st_size; - if (writeable) + if (mode == FILE_RW) mmap_ptr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); else @@ -293,7 +326,7 @@ if (mmap_ptr == (void *)-1) { fprintf(stderr, "Can't mmap %s file: %s\n", - writeable ? "output" : "input", + mode == FILE_RW ? "output" : "input", strerror(errno)); return FILE_ERR_MMAP; } @@ -303,14 +336,14 @@ return FILE_ERR_NONE; } -enum futil_file_err futil_unmap_file(int fd, int writeable, +enum futil_file_err futil_unmap_file(int fd, enum file_mode mode, uint8_t *buf, uint32_t len) { void *mmap_ptr = buf; enum futil_file_err err = FILE_ERR_NONE; - if (writeable && - (0 != msync(mmap_ptr, len, MS_SYNC|MS_INVALIDATE))) { + if (mode == FILE_RW && + (0 != msync(mmap_ptr, len, MS_SYNC | MS_INVALIDATE))) { fprintf(stderr, "msync failed: %s\n", strerror(errno)); err = FILE_ERR_MSYNC; } @@ -325,6 +358,36 @@ return err; } +enum futil_file_err futil_open_and_map_file(const char *infile, int *fd, + enum file_mode mode, uint8_t **buf, + uint32_t *len) +{ + enum futil_file_err rv = futil_open_file(infile, fd, mode); + if (rv != FILE_ERR_NONE) + return rv; + + rv = futil_map_file(*fd, mode, buf, len); + if (rv != FILE_ERR_NONE) + futil_close_file(*fd); + + return rv; +} + +enum futil_file_err futil_unmap_and_close_file(int fd, enum file_mode mode, + uint8_t *buf, uint32_t len) +{ + enum futil_file_err rv = FILE_ERR_NONE; + + if (buf) + rv = futil_unmap_file(fd, mode, buf, len); + if (rv != FILE_ERR_NONE) + return rv; + + if (fd != -1) + return futil_close_file(fd); + else + return FILE_ERR_NONE; +} #define DISK_SECTOR_SIZE 512 enum futil_file_type ft_recognize_gpt(uint8_t *buf, uint32_t len)
diff --git a/futility/updater.c b/futility/updater.c index 06a696c..1a5e99d 100644 --- a/futility/updater.c +++ b/futility/updater.c
@@ -20,6 +20,13 @@ static const char ROOTKEY_HASH_DEV[] = "b11d74edd286c144e1135b49e7f0bc20cf041f10"; +enum try_update_type { + TRY_UPDATE_OFF = 0, + TRY_UPDATE_AUTO, + TRY_UPDATE_DEFERRED_HOLD, + TRY_UPDATE_DEFERRED_APPLY, +}; + enum target_type { TARGET_SELF, TARGET_UPDATE, @@ -323,132 +330,6 @@ } /* - * Emulates writing to firmware. - * Returns 0 if success, non-zero if error. - */ -static int emulate_write_firmware(const char *filename, - const struct firmware_image *image, - const char *section_name) -{ - struct firmware_image to_image = {0}; - struct firmware_section from, to; - int errorcnt = 0; - - INFO("(emulation) Writing %s from %s to %s (emu=%s).\n", - section_name ? section_name : "the whole image", - image->file_name, image->programmer, filename); - - from.data = image->data; - from.size = image->size; - - if (load_firmware_image(&to_image, filename, NULL)) { - ERROR("Cannot load image from %s.\n", filename); - return -1; - } - - if (section_name) { - find_firmware_section(&from, image, section_name); - if (!from.data) { - ERROR("No section %s in source image %s.\n", - section_name, image->file_name); - errorcnt++; - } - find_firmware_section(&to, &to_image, section_name); - if (!to.data) { - ERROR("No section %s in destination image %s.\n", - section_name, filename); - errorcnt++; - } - } else if (image->size != to_image.size) { - ERROR("Image size is different (%s:%d != %s:%d)\n", - image->file_name, image->size, to_image.file_name, - to_image.size); - errorcnt++; - } else { - to.data = to_image.data; - to.size = to_image.size; - } - - if (!errorcnt) { - size_t to_write = VB2_MIN(to.size, from.size); - - assert(from.data && to.data); - VB2_DEBUG("Writing %zu bytes\n", to_write); - memcpy(to.data, from.data, to_write); - } - - if (!errorcnt && vb2_write_file( - filename, to_image.data, to_image.size)) { - ERROR("Failed writing to file: %s\n", filename); - errorcnt++; - } - - free_firmware_image(&to_image); - return errorcnt; -} - -/* - * Returns the number of retries when reading or writing to flash. - */ -static int get_io_retries(struct updater_config *cfg) -{ - return 1 + get_config_quirk(QUIRK_EXTRA_RETRIES, cfg); -} - -/* - * Returns 1 if the programmers in image1 and image2 are the same. - */ -static int is_the_same_programmer(const struct firmware_image *image1, - const struct firmware_image *image2) -{ - assert(image1 && image2); - - /* Including if both are NULL. */ - if (image1->programmer == image2->programmer) - return 1; - - /* Not the same if either one is NULL. */ - if (!image1->programmer || !image2->programmer) - return 0; - - return strcmp(image1->programmer, image2->programmer) == 0; -} - -/* - * Writes multiple sections from the given firmware image to the system. - * The 'sections' should be NULL (write the whole image) or a list of section - * names to write, and ended with NULL. - * Returns 0 if success, non-zero if error. - */ -static int write_firmware_sections(struct updater_config *cfg, - const struct firmware_image *image, - const char * const sections[]) -{ - int r = 0; - struct firmware_image *diff_image = NULL; - - if (cfg->emulation) { - int i; - if (!sections) - return emulate_write_firmware( - cfg->emulation, image, NULL); - for (i = 0; sections[i] && !r; i++) { - r |= emulate_write_firmware( - cfg->emulation, image, sections[i]); - } - return r; - } - - if (cfg->use_diff_image && cfg->image_current.data && - is_the_same_programmer(&cfg->image_current, image)) - diff_image = &cfg->image_current; - - return write_system_firmware(image, diff_image, sections, - &cfg->tempfiles, cfg->do_verify, - get_io_retries(cfg), cfg->verbosity + 1); -} - -/* * Writes a single section from the given firmware image to the system. * Writes the whole firmware image if the section_name is NULL. * Returns 0 if success, non-zero if error. @@ -460,8 +341,8 @@ const char *sections[2] = {0}; sections[0] = section_name; - return write_firmware_sections(cfg, image, - section_name ? sections : NULL); + return write_system_firmware( + cfg, image, section_name ? sections : NULL); } /* @@ -1077,7 +958,7 @@ struct firmware_image *image_to, int wp_enabled) { - const char *target; + const char *target, *self_target; int has_update = 1; int is_vboot2 = get_system_property(SYS_PROP_FW_VBOOT2, cfg); @@ -1093,7 +974,7 @@ return UPDATE_ERR_TPM_ROLLBACK; VB2_DEBUG("Firmware %s vboot2.\n", is_vboot2 ? "is" : "is NOT"); - target = decide_rw_target(cfg, TARGET_SELF, is_vboot2); + self_target = target = decide_rw_target(cfg, TARGET_SELF, is_vboot2); if (target == NULL) { ERROR("TRY-RW update needs system to boot in RW firmware.\n"); return UPDATE_ERR_TARGET; @@ -1105,7 +986,7 @@ target, image_to->file_name); return UPDATE_ERR_INVALID_IMAGE; } - if (!cfg->force_update) + if (!(cfg->force_update || cfg->try_update == TRY_UPDATE_DEFERRED_HOLD)) has_update = section_needs_update(image_from, image_to, target); if (has_update) { @@ -1115,6 +996,24 @@ if (write_firmware(cfg, image_to, target)) return UPDATE_ERR_WRITE_FIRMWARE; + + /* + * If the firmware update requested is part of a deferred update + * HOLD action, the autoupdater/postinstall will later call + * defer update APPLY action to set the correct cookies. So here + * it is valid to keep the self slot as the active firmware even + * though the target slot is always updated (whether the current + * active firmware is the same version or not). + */ + if (cfg->try_update == TRY_UPDATE_DEFERRED_HOLD) { + STATUS( + "DEFERRED UPDATE: Defer setting cookies for %s\n", + target); + target = self_target; + has_update = 0; + } + } else { + STATUS("NO RW UPDATE: No update for RW firmware.\n"); } /* Always set right cookies for next boot. */ @@ -1128,9 +1027,6 @@ write_firmware(cfg, image_to, FMAP_RW_LEGACY); } - if (!has_update) - STATUS("NO UPDATE: No need to update.\n"); - return UPDATE_ERR_DONE; } @@ -1144,14 +1040,17 @@ struct firmware_image *image_from, struct firmware_image *image_to) { - int sections_start = 0; - static const char * const sections[] = { - FMAP_RW_LEGACY, + int i, num = 0; + static const char * const required_sections[] = { FMAP_RW_SECTION_A, FMAP_RW_SECTION_B, - FMAP_RW_SHARED, - NULL, }; + static const char * const optional_sections[] = { + FMAP_RW_LEGACY, + FMAP_RW_SHARED, + }; + const char *sections[ARRAY_SIZE(required_sections) + + ARRAY_SIZE(optional_sections) + 1]; STATUS("RW UPDATE: Updating RW sections (%s, %s, %s, and %s).\n", FMAP_RW_SECTION_A, FMAP_RW_SECTION_B, FMAP_RW_SHARED, @@ -1163,17 +1062,29 @@ if (check_compatible_tpm_keys(cfg, image_to)) return UPDATE_ERR_TPM_ROLLBACK; + for (i = 0; i < ARRAY_SIZE(required_sections); i++) + sections[num++] = required_sections[i]; + /* + * The FMAP_RW_LEGACY is a special optional section. * We may also consider only updating legacy if legacy_needs_update() * returns true. However, given this is for 'recovery', it is probably * better to restore everything to the default states. We may revisit * this if a new scenario is found. */ - if (!firmware_section_exists(image_from, sections[sections_start]) || - !firmware_section_exists(image_to, sections[sections_start])) - sections_start++; + for (i = 0; i < ARRAY_SIZE(optional_sections); i++) { + const char *name = optional_sections[i]; + if (!firmware_section_exists(image_from, name) || + !firmware_section_exists(image_to, name)) { + VB2_DEBUG("Skipped optional section: %s\n", name); + continue; + } + sections[num++] = name; + } + assert(num < ARRAY_SIZE(sections)); + sections[num] = NULL; - if (write_firmware_sections(cfg, image_to, §ions[sections_start])) + if (write_system_firmware(cfg, image_to, sections)) return UPDATE_ERR_WRITE_FIRMWARE; return UPDATE_ERR_DONE; @@ -1260,6 +1171,23 @@ int wp_enabled, done = 0; enum updater_error_codes r = UPDATE_ERR_UNKNOWN; + /* + * For deferred update APPLY action, the only requirement is to set the + * correct cookies to the update target slot. + */ + if (cfg->try_update == TRY_UPDATE_DEFERRED_APPLY) { + INFO("Apply deferred updates, only setting cookies for the " + "next boot slot.\n"); + int vboot2 = get_system_property(SYS_PROP_FW_VBOOT2, cfg); + if (set_try_cookies( + cfg, + decide_rw_target(cfg, TARGET_UPDATE, vboot2), + /*has_update=*/1, + vboot2)) + return UPDATE_ERR_SET_COOKIES; + return UPDATE_ERR_DONE; + } + struct firmware_image *image_from = &cfg->image_current, *image_to = &cfg->image; if (!image_to->data) @@ -1280,8 +1208,7 @@ int ret; INFO("Loading current system firmware...\n"); - ret = load_system_firmware(image_from, &cfg->tempfiles, - get_io_retries(cfg), cfg->verbosity); + ret = load_system_firmware(cfg, image_from); if (ret == IMAGE_PARSE_FAILURE && cfg->force_update) { WARN("No compatible firmware in system.\n"); cfg->check_platform = 0; @@ -1344,7 +1271,7 @@ * Allocates and initializes a updater_config object with default values. * Returns the newly allocated object, or NULL on error. */ -struct updater_config *updater_new_config() +struct updater_config *updater_new_config(void) { struct updater_config *cfg = (struct updater_config *)calloc( 1, sizeof(struct updater_config)); @@ -1402,7 +1329,7 @@ const char *pd_image) { int errorcnt = 0; - struct archive *ar = cfg->archive; + struct u_archive *ar = cfg->archive; if (!cfg->image.data && image) { if (image && strcmp(image, "-") == 0) { @@ -1450,23 +1377,20 @@ } /* - * Applies white label information to an existing model config. + * Applies custom label information to an existing model config. * Returns 0 on success, otherwise failure. */ -static int updater_apply_white_label(struct updater_config *cfg, +static int updater_apply_custom_label(struct updater_config *cfg, struct model_config *model, const char *signature_id) { const char *tmp_image = NULL; - assert(model->is_white_label); + assert(model->is_custom_label); if (!signature_id) { if (!cfg->image_current.data) { - INFO("Loading system firmware for white label...\n"); - load_system_firmware(&cfg->image_current, - &cfg->tempfiles, - get_io_retries(cfg), - cfg->verbosity); + INFO("Loading system firmware for custom label...\n"); + load_system_firmware(cfg, &cfg->image_current); } tmp_image = get_firmware_image_temp_file( &cfg->image_current, &cfg->tempfiles); @@ -1479,7 +1403,7 @@ quirk_override_signature_id( cfg, model, &signature_id); } - return !!model_apply_white_label( + return !!model_apply_custom_label( model, cfg->archive, signature_id, tmp_image); } @@ -1494,7 +1418,7 @@ int is_factory) { int errorcnt = 0; - struct archive *ar = cfg->archive; + struct u_archive *ar = cfg->archive; const struct model_config *model; if (arg->do_manifest) { @@ -1508,33 +1432,34 @@ if (!model) return ++errorcnt; - /* Load images now so we can get quirks in WL checks. */ + /* Load images now so we can get quirks in custom label checks. */ errorcnt += updater_load_images( cfg, arg, model->image, model->ec_image, model->pd_image); - if (model->is_white_label && !manifest->has_keyset) { + if (model->is_custom_label && !manifest->has_keyset) { /* * Developers running unsigned updaters (usually local build) - * won't be able match any white label tags. + * won't be able match any custom label tags. */ WARN("No keysets found - this is probably a local build of \n" - "unsigned firmware updater. Skip applying white label."); - } else if (model->is_white_label) { + "unsigned firmware updater. Skip applying custom label."); + } else if (model->is_custom_label) { /* - * It is fine to fail in updater_apply_white_label for factory + * It is fine to fail in updater_apply_custom_label for factory * mode so we are not checking the return value; instead we * verify if the patches do contain new root key. */ - updater_apply_white_label(cfg, (struct model_config *)model, + updater_apply_custom_label(cfg, (struct model_config *)model, arg->signature_id); if (!model->patches.rootkey) { if (is_factory || is_write_protection_enabled(cfg) || - get_config_quirk(QUIRK_ALLOW_EMPTY_WLTAG, cfg)) { - WARN("No VPD for white label.\n"); + get_config_quirk(QUIRK_ALLOW_EMPTY_CUSTOM_LABEL_TAG, + cfg)) { + WARN("No VPD for custom label.\n"); } else { - ERROR("Need VPD set for white label.\n"); + ERROR("Need VPD set for custom label.\n"); return ++errorcnt; } } @@ -1587,12 +1512,16 @@ /* Setup update mode. */ if (arg->try_update) - cfg->try_update = 1; + cfg->try_update = TRY_UPDATE_AUTO; if (arg->mode) { if (strcmp(arg->mode, "autoupdate") == 0) { - cfg->try_update = 1; + cfg->try_update = TRY_UPDATE_AUTO; + } else if (strcmp(arg->mode, "deferupdate_hold") == 0) { + cfg->try_update = TRY_UPDATE_DEFERRED_HOLD; + } else if (strcmp(arg->mode, "deferupdate_apply") == 0) { + cfg->try_update = TRY_UPDATE_DEFERRED_APPLY; } else if (strcmp(arg->mode, "recovery") == 0) { - cfg->try_update = 0; + cfg->try_update = TRY_UPDATE_OFF; } else if (strcmp(arg->mode, "legacy") == 0) { cfg->legacy_update = 1; } else if (strcmp(arg->mode, "factory") == 0 || @@ -1608,7 +1537,7 @@ if (cfg->factory_update) { /* factory_update must be processed after arg->mode. */ check_wp_disabled = 1; - cfg->try_update = 0; + cfg->try_update = TRY_UPDATE_OFF; } cfg->gbb_flags = arg->gbb_flags; cfg->override_gbb_flags = arg->override_gbb_flags; @@ -1654,7 +1583,7 @@ /* Process archives which may not have valid contents. */ if (arg->repack || arg->unpack) { const char *work_name = arg->repack ? arg->repack : arg->unpack; - struct archive *from, *to, *work; + struct u_archive *from, *to, *work; work = archive_open(work_name); if (arg->repack) { @@ -1674,8 +1603,25 @@ return errorcnt; } - /* Load images from archive. */ - if (arg->archive) { + /* Process the manifest and load images from the archive. */ + if (arg->archive && arg->do_manifest && arg->fast_update) { + /* Quickly load and dump the manifest file from the archive. */ + const char *manifest_name = "manifest.json"; + uint8_t *data = NULL; + uint32_t size = 0; + + if (archive_has_entry(cfg->archive, manifest_name) && + archive_read_file(cfg->archive, manifest_name, &data, &size, + NULL) == 0) { + /* data is NUL-terminated. */ + printf("%s\n", data); + free(data); + } else { + ERROR("Failed to read the cached manifest: %s\n", + manifest_name); + errorcnt++; + } + } else if (arg->archive) { struct manifest *m = new_manifest_from_archive(cfg->archive); if (m) { errorcnt += updater_setup_archive(
diff --git a/futility/updater.h b/futility/updater.h index 6dda928..cf03465 100644 --- a/futility/updater.h +++ b/futility/updater.h
@@ -42,13 +42,14 @@ QUIRK_UNLOCK_ME_FOR_UPDATE, QUIRK_UNLOCK_WILCO_ME_FOR_UPDATE, QUIRK_EVE_SMM_STORE, - QUIRK_ALLOW_EMPTY_WLTAG, + QUIRK_ALLOW_EMPTY_CUSTOM_LABEL_TAG, QUIRK_EC_PARTIAL_RECOVERY, QUIRK_OVERRIDE_SIGNATURE_ID, QUIRK_PRESERVE_ME, QUIRK_NO_CHECK_PLATFORM, QUIRK_NO_VERIFY, QUIRK_EXTRA_RETRIES, + QUIRK_EXTERNAL_FLASHROM, QUIRK_MAX, }; @@ -64,7 +65,7 @@ struct firmware_image ec_image, pd_image; struct system_property system_properties[SYS_PROP_MAX]; struct quirk_entry quirks[QUIRK_MAX]; - struct archive *archive; + struct u_archive *archive; struct tempfile tempfiles; int try_update; int force_update; @@ -105,13 +106,13 @@ char *image, *ec_image, *pd_image; struct patch_config patches; char *signature_id; - int is_white_label; + int is_custom_label; }; struct manifest { int num; struct model_config *models; - struct archive *archive; + struct u_archive *archive; int default_model; int has_keyset; }; @@ -207,26 +208,26 @@ * Returns a pointer to reference to archive (must be released by archive_close * when not used), otherwise NULL on error. */ -struct archive *archive_open(const char *path); +struct u_archive *archive_open(const char *path); /* * Closes an archive reference. * Returns 0 on success, otherwise non-zero as failure. */ -int archive_close(struct archive *ar); +int archive_close(struct u_archive *ar); /* * Checks if an entry (either file or directory) exists in archive. * Returns 1 if exists, otherwise 0 */ -int archive_has_entry(struct archive *ar, const char *name); +int archive_has_entry(struct u_archive *ar, const char *name); /* * Reads a file from archive. * Returns 0 on success (data and size reflects the file content), * otherwise non-zero as failure. */ -int archive_read_file(struct archive *ar, const char *fname, +int archive_read_file(struct u_archive *ar, const char *fname, uint8_t **data, uint32_t *size, int64_t *mtime); /* @@ -235,20 +236,30 @@ * file system. * Returns 0 on success, otherwise non-zero as failure. */ -int archive_write_file(struct archive *ar, const char *fname, +int archive_write_file(struct u_archive *ar, const char *fname, uint8_t *data, uint32_t size, int64_t mtime); /* + * Traverses all files within archive (directories are ignored). + * For every entry, the path (relative the archive root) will be passed to + * callback function, until the callback returns non-zero. + * The arg argument will also be passed to callback. + * Returns 0 on success otherwise non-zero as failure. + */ +int archive_walk(struct u_archive *ar, void *arg, + int (*callback)(const char *path, void *arg)); + +/* * Copies all entries from one archive to another. * Returns 0 on success, otherwise non-zero as failure. */ -int archive_copy(struct archive *from, struct archive *to); +int archive_copy(struct u_archive *from, struct u_archive *to); /* * Creates a new manifest object by scanning files in archive. * Returns the manifest on success, otherwise NULL for failure. */ -struct manifest *new_manifest_from_archive(struct archive *archive); +struct manifest *new_manifest_from_archive(struct u_archive *archive); /* Releases all resources allocated by given manifest object. */ void delete_manifest(struct manifest *manifest); @@ -262,7 +273,7 @@ */ int patch_image_by_model( struct firmware_image *image, const struct model_config *model, - struct archive *archive); + struct u_archive *archive); /* * Finds the existing model_config from manifest that best matches current @@ -273,14 +284,14 @@ const char *model_name); /* - * Applies white label information to an existing model configuration. + * Applies custom label information to an existing model configuration. * Collects signature ID information from either parameter signature_id or * image file (via VPD) and updates model.patches for key files. * Returns 0 on success, otherwise failure. */ -int model_apply_white_label( +int model_apply_custom_label( struct model_config *model, - struct archive *archive, + struct u_archive *archive, const char *signature_id, const char *image);
diff --git a/futility/updater_archive.c b/futility/updater_archive.c index 9c3a608..c6e8f28 100644 --- a/futility/updater_archive.c +++ b/futility/updater_archive.c
@@ -6,19 +6,20 @@ */ #include <assert.h> -#include <ctype.h> #include <errno.h> #if defined(__OpenBSD__) #include <sys/types.h> #endif #include <fts.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> #include <sys/stat.h> #include <sys/time.h> #include <unistd.h> +#ifdef HAVE_LIBARCHIVE +#include <archive.h> +#include <archive_entry.h> +#endif + #ifdef HAVE_LIBZIP #ifndef __clang__ /* If libzip headers were built for Clang but later get included with GCC you @@ -30,62 +31,16 @@ #include <zip.h> #endif -#ifdef HAVE_CROSID -#include <crosid.h> -#endif - #include "host_misc.h" #include "updater.h" -#include "util_misc.h" /* * A firmware update package (archive) is a file packed by either shar(1) or * zip(1). See https://chromium.googlesource.com/chromiumos/platform/firmware/ * for more information. - * - * A package for single board (i.e., not Unified Build) will have all the image - * files in top folder: - * - host: 'image.bin' (or 'bios.bin' as legacy name before CL:1318712) - * - ec: 'ec.bin' - * - pd: 'pd.bin' - * If white label is supported, a 'keyset/' folder will be available, with key - * files in it: - * - rootkey.$WLTAG - * - vblock_A.$WLTAG - * - vblock_B.$WLTAG - * The $WLTAG should come from VPD value 'whitelabel_tag', or the - * 'customization_id'. Note 'customization_id' is in format LOEM[-VARIANT] and - * we can only take LOEM as $WLTAG, for example A-B => $WLTAG=A. - * - * A package for Unified Build is more complicated. There will be a models/ - * folder, and each model (by $(mosys platform model) ) should appear as a sub - * folder, with a 'setvars.sh' file inside. The 'setvars.sh' is a shell script - * describing what files should be used and the signature ID ($SIGID) to use. - * - * Similar to write label in non-Unified-Build, the keys and vblock files will - * be in 'keyset/' folder: - * - rootkey.$SIGID - * - vblock_A.$SIGID - * - vblock_B.$SIGID - * If $SIGID starts with 'sig-id-in-*' then we have to replace it by VPD value - * 'whitelabel_tag' as '$MODEL-$WLTAG'. */ -static const char * const SETVARS_IMAGE_MAIN = "IMAGE_MAIN", - * const SETVARS_IMAGE_EC = "IMAGE_EC", - * const SETVARS_IMAGE_PD = "IMAGE_PD", - * const SETVARS_SIGNATURE_ID = "SIGNATURE_ID", - * const SIG_ID_IN_VPD_PREFIX = "sig-id-in", - * const DIR_KEYSET = "keyset", - * const DIR_MODELS = "models", - * const DEFAULT_MODEL_NAME = "default", - * const VPD_WHITELABEL_TAG = "whitelabel_tag", - * const VPD_CUSTOMIZATION_ID = "customization_id", - * const ENV_VAR_MODEL_DIR = "${MODEL_DIR}", - * const PATH_STARTSWITH_KEYSET = "keyset/", - * const PATH_ENDSWITH_SERVARS = "/setvars.sh"; - -struct archive { +struct u_archive { void *handle; void * (*open)(const char *name); @@ -101,7 +56,7 @@ }; /* - * -- Begin of archive implementations -- + * -- The fallback driver (using general file system). -- */ /* Callback for archive_open on a general file system. */ @@ -189,6 +144,7 @@ VB2_DEBUG("Reading %s\n", path); *data = NULL; *size = 0; + /* vb2_read_file already has an extra '\0' in the end. */ r = vb2_read_file(path, data, size) != VB2_SUCCESS; if (mtime) { if (stat(path, &st) == 0) @@ -234,6 +190,238 @@ return r; } +/* + * -- The cache driver (used by other drivers). -- + */ + +#ifdef HAVE_LIBARCHIVE + +/* + * For stream-based archives (e.g., tar+gz) we want to create a cache for + * storing the names and contents for later processing. + */ +struct archive_cache { + char *name; + uint8_t *data; + int64_t mtime; + size_t size; + int has_data; + struct archive_cache *next; +}; + +/* Add a new cache node to an existing cache list and return the new head. */ +static struct archive_cache *archive_cache_new(struct archive_cache *cache, + const char *name) +{ + struct archive_cache *c; + + c = (struct archive_cache *)calloc(sizeof(*c), 1); + if (!c) + return NULL; + + c->name = strdup(name); + if (!c->name) { + free(c); + return NULL; + } + + c->next = cache; + return c; +} + +/* Find and return an entry (by name) from the cache. */ +static struct archive_cache *archive_cache_find(struct archive_cache *c, + const char *name) +{ + for (; c; c = c->next) { + assert(c->name); + if (!strcmp(c->name, name)) + return c; + } + return NULL; +} + +/* Callback for archive_walk to process all entries in the cache. */ +static int archive_cache_walk( + struct archive_cache *c, void *arg, + int (*callback)(const char *name, void *arg)) +{ + for (; c; c = c->next) { + assert(c->name); + if (callback(c->name, arg)) + break; + } + return 0; +} + +/* Delete all entries in the cache. */ +static void *archive_cache_free(struct archive_cache *c) +{ + struct archive_cache *next; + + while (c) { + next = c->next; + free(c->name); + free(c->data); + free(c); + c = next; + } + return NULL; +} + +/* + * -- The libarchive driver (multiple formats but very slow). -- + */ + +enum { + FILTER_IGNORE, + FILTER_ABORT, + FILTER_NAME_ONLY, + FILTER_READ_ALL, +}; + +static struct archive_cache *libarchive_read_file_entries( + const char *fpath, int (*filter)(struct archive_entry *entry)) +{ + struct archive *a = archive_read_new(); + struct archive_entry *entry; + struct archive_cache *c, *cache = NULL; + int r; + + assert(a); + archive_read_support_filter_all(a); + archive_read_support_format_all(a); + r = archive_read_open_filename(a, fpath, 10240); + if (r != ARCHIVE_OK) { + ERROR("Failed parsing archive using libarchive: %s\n", fpath); + archive_read_free(a); + return NULL; + } + + WARN("Loading data from archive: %s ", fpath); + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { + fputc('.', stderr); + if (archive_entry_filetype(entry) != AE_IFREG) + continue; + if (filter) + r = filter(entry); + else + r = FILTER_READ_ALL; + + if (r == FILTER_ABORT) + break; + if (r == FILTER_IGNORE) + continue; + + c = archive_cache_new(cache, archive_entry_pathname(entry)); + if (!c) { + ERROR("Internal error: out of memory.\n"); + archive_cache_free(cache); + archive_read_free(a); + return NULL; + } + cache = c; + + if (r == FILTER_NAME_ONLY) + continue; + + assert(r == FILTER_READ_ALL); + c->size = archive_entry_size(entry); + c->mtime = archive_entry_mtime(entry); + c->data = (uint8_t *)calloc(1, c->size + 1); + if (!c->data) { + WARN("Out of memory when loading: %s\n", c->name); + continue; + } + if (archive_read_data(a, c->data, c->size) != c->size) { + WARN("Failed reading from archive: %s\n", c->name); + continue; + } + c->has_data = 1; + } + fputs("\r\n", stderr); /* Flush the '.' */ + VB2_DEBUG("Finished loading from archive: %s.\n", fpath); + + archive_read_free(a); + return cache; +} + +/* Callback for archive_open on an ARCHIVE file. */ +static void *archive_libarchive_open(const char *name) +{ + /* + * The firmware archives today can usually all load into memory + * so we are using a NULL filter. Change that to a specific list in + * future if the /build/$BOARD/firmware archive becomes too large. + */ + return libarchive_read_file_entries(name, NULL); +} + +/* Callback for archive_close on an ARCHIVE file. */ +static int archive_libarchive_close(void *handle) +{ + archive_cache_free(handle); + return 0; +} + +/* Callback for archive_has_entry on an ARCHIVE file. */ +static int archive_libarchive_has_entry(void *handle, const char *fname) +{ + return archive_cache_find(handle, fname) != NULL; +} + +/* Callback for archive_walk on an ARCHIVE file. */ +static int archive_libarchive_walk( + void *handle, void *arg, + int (*callback)(const char *name, void *arg)) +{ + return archive_cache_walk(handle, arg, callback); +} + +/* Callback for archive_read_file on an ARCHIVE file. */ +static int archive_libarchive_read_file( + void *handle, const char *fname, uint8_t **data, + uint32_t *size, int64_t *mtime) +{ + struct archive_cache *c = archive_cache_find(handle, fname); + + if (!c) + return 1; + + if (!c->has_data) { + /* TODO(hungte) Re-read. */ + ERROR("Not in the cache: %s\n", fname); + return 1; + } + + if (mtime) + *mtime = c->mtime; + if (size) + *size = c->size; + *data = (uint8_t *)malloc(c->size + 1); + if (!*data) { + ERROR("Out of memory when reading: %s\n", c->name); + return 1; + } + memcpy(*data, c->data, c->size); + (*data)[c->size] = '\0'; + return 0; +} + +/* Callback for archive_write_file on an ARCHIVE file. */ +static int archive_libarchive_write_file( + void *handle, const char *fname, uint8_t *data, uint32_t size, + int64_t mtime) +{ + ERROR("Not implemented!\n"); + return 1; +} +#endif + +/* + * -- The libzip driver (for ZIP, the official format for CrOS fw updater). -- + */ + #ifdef HAVE_LIBZIP /* Callback for archive_open on a ZIP file. */ @@ -303,12 +491,13 @@ ERROR("Failed to open entry in ZIP: %s\n", fname); return 1; } - *data = (uint8_t *)malloc(stat.size); + *data = (uint8_t *)malloc(stat.size + 1); if (*data) { if (zip_fread(fp, *data, stat.size) == stat.size) { if (mtime) *mtime = stat.mtime; *size = stat.size; + (*data)[stat.size] = '\0'; } else { ERROR("Failed to read entry in zip: %s\n", fname); free(*data); @@ -348,22 +537,26 @@ #endif /* + * -- The public functions for using u_archive. -- + */ + +/* * Opens an archive from given path. * The type of archive will be determined automatically. * Returns a pointer to reference to archive (must be released by archive_close * when not used), otherwise NULL on error. */ -struct archive *archive_open(const char *path) +struct u_archive *archive_open(const char *path) { struct stat path_stat; - struct archive *ar; + struct u_archive *ar; if (stat(path, &path_stat) != 0) { ERROR("Cannot identify type of path: %s\n", path); return NULL; } - ar = (struct archive *)malloc(sizeof(*ar)); + ar = (struct u_archive *)calloc(sizeof(*ar), 1); if (!ar) { ERROR("Internal error: allocation failure.\n"); return NULL; @@ -379,22 +572,48 @@ ar->has_entry = archive_fallback_has_entry; ar->read_file = archive_fallback_read_file; ar->write_file = archive_fallback_write_file; - } else { + } + + /* Format detection must try ZIP (the official format) first. */ #ifdef HAVE_LIBZIP - VB2_DEBUG("Found file, use ZIP driver: %s\n", path); - ar->open = archive_zip_open; - ar->close = archive_zip_close; - ar->walk = archive_zip_walk; - ar->has_entry = archive_zip_has_entry; - ar->read_file = archive_zip_read_file; - ar->write_file = archive_zip_write_file; -#else - ERROR("Found file, but no drivers were enabled: %s\n", path); + if (!ar->open) { + ar->handle = archive_zip_open(path); + + if (ar->handle) { + VB2_DEBUG("Found a ZIP file: %s\n", path); + ar->open = archive_zip_open; + ar->close = archive_zip_close; + ar->walk = archive_zip_walk; + ar->has_entry = archive_zip_has_entry; + ar->read_file = archive_zip_read_file; + ar->write_file = archive_zip_write_file; + } + } +#endif + + /* LIBARCHIVE must be the last driver. */ +#ifdef HAVE_LIBARCHIVE + if (!ar->open) { + VB2_DEBUG("Found a file, use libarchive: %s\n", path); + ar->open = archive_libarchive_open; + ar->close = archive_libarchive_close; + ar->walk = archive_libarchive_walk; + ar->has_entry = archive_libarchive_has_entry; + ar->read_file = archive_libarchive_read_file; + ar->write_file = archive_libarchive_write_file; + } +#endif + + if (!ar->open) { + ERROR("Found a file, but no drivers were selected: %s\n", path); free(ar); return NULL; -#endif } - ar->handle = ar->open(path); + + /* Some drivers may have already opened the archive. */ + if (!ar->handle) + ar->handle = ar->open(path); + if (!ar->handle) { ERROR("Failed to open archive: %s\n", path); free(ar); @@ -407,7 +626,7 @@ * Closes an archive reference. * Returns 0 on success, otherwise non-zero as failure. */ -int archive_close(struct archive *ar) +int archive_close(struct u_archive *ar) { int r = ar->close(ar->handle); free(ar); @@ -420,7 +639,7 @@ * with real file system. * Returns 1 if exists, otherwise 0 */ -int archive_has_entry(struct archive *ar, const char *name) +int archive_has_entry(struct u_archive *ar, const char *name) { if (!ar || *name == '/') return archive_fallback_has_entry(NULL, name); @@ -434,8 +653,8 @@ * The arg argument will also be passed to callback. * Returns 0 on success otherwise non-zero as failure. */ -static int archive_walk(struct archive *ar, void *arg, - int (*callback)(const char *path, void *arg)) +int archive_walk(struct u_archive *ar, void *arg, + int (*callback)(const char *path, void *arg)) { if (!ar) return archive_fallback_walk(NULL, arg, callback); @@ -446,10 +665,12 @@ * Reads a file from archive. * If entry name (fname) is an absolute path (/file), always read * from real file system. + * The returned data must always have one extra (not included by size) '\0' in + * the end of the allocated buffer for C string processing. * Returns 0 on success (data and size reflects the file content), * otherwise non-zero as failure. */ -int archive_read_file(struct archive *ar, const char *fname, +int archive_read_file(struct u_archive *ar, const char *fname, uint8_t **data, uint32_t *size, int64_t *mtime) { if (!ar || *fname == '/') @@ -463,7 +684,7 @@ * file system. * Returns 0 on success, otherwise non-zero as failure. */ -int archive_write_file(struct archive *ar, const char *fname, +int archive_write_file(struct u_archive *ar, const char *fname, uint8_t *data, uint32_t size, int64_t mtime) { if (!ar || *fname == '/') @@ -472,7 +693,7 @@ } struct _copy_arg { - struct archive *from, *to; + struct u_archive *from, *to; }; /* Callback for archive_copy. */ @@ -499,654 +720,8 @@ * Copies all entries from one archive to another. * Returns 0 on success, otherwise non-zero as failure. */ -int archive_copy(struct archive *from, struct archive *to) +int archive_copy(struct u_archive *from, struct u_archive *to) { struct _copy_arg arg = { .from = from, .to = to }; return archive_walk(from, &arg, archive_copy_callback); } - -/* - * -- End of archive implementations -- - */ - -/* Utility function to convert a string. */ -static void str_convert(char *s, int (*convert)(int c)) -{ - int c; - - for (; *s; s++) { - c = *s; - if (!isascii(c)) - continue; - *s = convert(c); - } -} - -/* Returns 1 if name ends by given pattern, otherwise 0. */ -static int str_endswith(const char *name, const char *pattern) -{ - size_t name_len = strlen(name), pattern_len = strlen(pattern); - if (name_len < pattern_len) - return 0; - return strcmp(name + name_len - pattern_len, pattern) == 0; -} - -/* Returns 1 if name starts by given pattern, otherwise 0. */ -static int str_startswith(const char *name, const char *pattern) -{ - return strncmp(name, pattern, strlen(pattern)) == 0; -} - -/* Returns the VPD value by given key name, or NULL on error (or no value). */ -static char *vpd_get_value(const char *fpath, const char *key) -{ - char *command, *result; - - assert(fpath); - ASPRINTF(&command, "vpd -g %s -f %s 2>/dev/null", key, fpath); - result = host_shell(command); - free(command); - - if (result && !*result) { - free(result); - result = NULL; - } - return result; -} - -/* - * Reads and parses a setvars type file from archive, then stores into config. - * Returns 0 on success (at least one entry found), otherwise failure. - */ -static int model_config_parse_setvars_file( - struct model_config *cfg, struct archive *archive, - const char *fpath) -{ - uint8_t *data; - uint32_t len; - - char *ptr_line, *ptr_token; - char *line, *k, *v; - int valid = 0; - - if (archive_read_file(archive, fpath, &data, &len, NULL) != 0) { - ERROR("Failed reading: %s\n", fpath); - return -1; - } - - /* Valid content should end with \n, or \"; ensure ASCIIZ for parsing */ - if (len) - data[len - 1] = '\0'; - - for (line = strtok_r((char *)data, "\n\r", &ptr_line); line; - line = strtok_r(NULL, "\n\r", &ptr_line)) { - char *expand_path = NULL; - int found_valid = 1; - - /* Format: KEY="value" */ - k = strtok_r(line, "=", &ptr_token); - if (!k) - continue; - v = strtok_r(NULL, "\"", &ptr_token); - if (!v) - continue; - - /* Some legacy updaters may be still using ${MODEL_DIR}. */ - if (str_startswith(v, ENV_VAR_MODEL_DIR)) { - ASPRINTF(&expand_path, "%s/%s%s", DIR_MODELS, cfg->name, - v + strlen(ENV_VAR_MODEL_DIR)); - } - - if (strcmp(k, SETVARS_IMAGE_MAIN) == 0) - cfg->image = strdup(v); - else if (strcmp(k, SETVARS_IMAGE_EC) == 0) - cfg->ec_image = strdup(v); - else if (strcmp(k, SETVARS_IMAGE_PD) == 0) - cfg->pd_image = strdup(v); - else if (strcmp(k, SETVARS_SIGNATURE_ID) == 0) { - cfg->signature_id = strdup(v); - if (str_startswith(v, SIG_ID_IN_VPD_PREFIX)) - cfg->is_white_label = 1; - } else - found_valid = 0; - free(expand_path); - valid += found_valid; - } - free(data); - return valid == 0; -} - -/* - * Changes the rootkey in firmware GBB to given new key. - * Returns 0 on success, otherwise failure. - */ -static int change_gbb_rootkey(struct firmware_image *image, - const char *section_name, - const uint8_t *rootkey, uint32_t rootkey_len) -{ - const struct vb2_gbb_header *gbb = find_gbb(image); - uint8_t *gbb_rootkey; - if (!gbb) { - ERROR("Cannot find GBB in image %s.\n", image->file_name); - return -1; - } - if (gbb->rootkey_size < rootkey_len) { - ERROR("New root key (%u bytes) larger than GBB (%u bytes).\n", - rootkey_len, gbb->rootkey_size); - return -1; - } - - gbb_rootkey = (uint8_t *)gbb + gbb->rootkey_offset; - /* See cmd_gbb_utility: root key must be first cleared with zero. */ - memset(gbb_rootkey, 0, gbb->rootkey_size); - memcpy(gbb_rootkey, rootkey, rootkey_len); - return 0; -} - -/* - * Changes the VBlock in firmware section to new data. - * Returns 0 on success, otherwise failure. - */ -static int change_vblock(struct firmware_image *image, const char *section_name, - const uint8_t *vblock, uint32_t vblock_len) -{ - struct firmware_section section; - - find_firmware_section(§ion, image, section_name); - if (!section.data) { - ERROR("Need section %s in image %s.\n", section_name, - image->file_name); - return -1; - } - if (section.size < vblock_len) { - ERROR("Section %s too small (%zu bytes) for vblock (%u bytes).\n", - section_name, section.size, vblock_len); - return -1; - } - memcpy(section.data, vblock, vblock_len); - return 0; -} - -/* - * Applies a key file to firmware image. - * Returns 0 on success, otherwise failure. - */ -static int apply_key_file( - struct firmware_image *image, const char *path, - struct archive *archive, const char *section_name, - int (*apply)(struct firmware_image *image, const char *section, - const uint8_t *data, uint32_t len)) -{ - int r = 0; - uint8_t *data = NULL; - uint32_t len; - - r = archive_read_file(archive, path, &data, &len, NULL); - if (r == 0) { - VB2_DEBUG("Loaded file: %s\n", path); - r = apply(image, section_name, data, len); - if (r) - ERROR("Failed applying %s to %s\n", path, section_name); - } else { - ERROR("Failed reading: %s\n", path); - } - free(data); - return r; -} - -/* - * Modifies a firmware image from patch information specified in model config. - * Returns 0 on success, otherwise number of failures. - */ -int patch_image_by_model( - struct firmware_image *image, const struct model_config *model, - struct archive *archive) -{ - int err = 0; - if (model->patches.rootkey) - err += !!apply_key_file( - image, model->patches.rootkey, archive, - FMAP_RO_GBB, change_gbb_rootkey); - if (model->patches.vblock_a) - err += !!apply_key_file( - image, model->patches.vblock_a, archive, - FMAP_RW_VBLOCK_A, change_vblock); - if (model->patches.vblock_b) - err += !!apply_key_file( - image, model->patches.vblock_b, archive, - FMAP_RW_VBLOCK_B, change_vblock); - return err; -} - -/* - * Finds available patch files by given model. - * Updates `model` argument with path of patch files. - */ -static void find_patches_for_model(struct model_config *model, - struct archive *archive, - const char *signature_id) -{ - char *path; - int i; - - const char *names[] = { - "rootkey", - "vblock_A", - "vblock_B", - }; - - char **targets[] = { - &model->patches.rootkey, - &model->patches.vblock_a, - &model->patches.vblock_b, - }; - - assert(ARRAY_SIZE(names) == ARRAY_SIZE(targets)); - for (i = 0; i < ARRAY_SIZE(names); i++) { - ASPRINTF(&path, "%s/%s.%s", DIR_KEYSET, names[i], signature_id); - if (archive_has_entry(archive, path)) - *targets[i] = path; - else - free(path); - } -} - -/* - * Adds and copies one new model config to the existing list of given manifest. - * Returns a pointer to the newly allocated config, or NULL on failure. - */ -static struct model_config *manifest_add_model( - struct manifest *manifest, - const struct model_config *cfg) -{ - struct model_config *model; - manifest->num++; - manifest->models = (struct model_config *)realloc( - manifest->models, manifest->num * sizeof(*model)); - if (!manifest->models) { - ERROR("Internal error: failed to allocate buffer.\n"); - return NULL; - } - model = &manifest->models[manifest->num - 1]; - memcpy(model, cfg, sizeof(*model)); - return model; -} - -/* - * A callback function for manifest to scan files in archive. - * Returns 0 to keep scanning, or non-zero to stop. - */ -static int manifest_scan_entries(const char *name, void *arg) -{ - struct manifest *manifest = (struct manifest *)arg; - struct archive *archive = manifest->archive; - struct model_config model = {0}; - char *slash; - - if (str_startswith(name, PATH_STARTSWITH_KEYSET)) - manifest->has_keyset = 1; - if (!str_endswith(name, PATH_ENDSWITH_SERVARS)) - return 0; - - /* name: models/$MODEL/setvars.sh */ - model.name = strdup(strchr(name, '/') + 1); - slash = strchr(model.name, '/'); - if (slash) - *slash = '\0'; - - VB2_DEBUG("Found model <%s> setvars: %s\n", model.name, name); - if (model_config_parse_setvars_file(&model, archive, name)) { - ERROR("Invalid setvars file: %s\n", name); - return 0; - } - - /* In legacy setvars.sh, the ec_image and pd_image may not exist. */ - if (model.ec_image && !archive_has_entry(archive, model.ec_image)) { - VB2_DEBUG("Ignore non-exist EC image: %s\n", model.ec_image); - free(model.ec_image); - model.ec_image = NULL; - } - if (model.pd_image && !archive_has_entry(archive, model.pd_image)) { - VB2_DEBUG("Ignore non-exist PD image: %s\n", model.pd_image); - free(model.pd_image); - model.pd_image = NULL; - } - - /* Find patch files. */ - if (model.signature_id) - find_patches_for_model(&model, archive, model.signature_id); - - return !manifest_add_model(manifest, &model); -} - -/** - * get_manifest_key() - Wrapper to get the firmware manifest key from crosid - * - * @manifest_key_out - Output parameter of the firmware manifest key. - * - * Returns: - * - <0 if libcrosid is unavailable or there was an error reading - * device data - * - >=0 (the matched device index) success - */ -static int get_manifest_key(char **manifest_key_out) -{ -#ifdef HAVE_CROSID - return crosid_get_firmware_manifest_key(manifest_key_out); -#else - ERROR("This version of futility was compiled without libcrosid " - "(perhaps compiled outside of the Chrome OS build system?) and " - "the update command is not fully supported. Either compile " - "from the Chrome OS build, or pass --model to manually specify " - "the machine model.\n"); - return -1; -#endif -} - -/* - * Finds the existing model_config from manifest that best matches current - * system (as defined by model_name). - * Returns a model_config from manifest, or NULL if not found. - */ -const struct model_config *manifest_find_model(const struct manifest *manifest, - const char *model_name) -{ - char *manifest_key = NULL; - const struct model_config *model = NULL; - int i; - int matched_index; - - /* - * For manifest with single model defined, we should just return because - * there are other mechanisms like platform name check to double confirm - * if the firmware is valid. - */ - if (manifest->num == 1) - return &manifest->models[0]; - - if (!model_name) { - matched_index = get_manifest_key(&manifest_key); - if (matched_index < 0) { - ERROR("Failed to get device identity. " - "Run \"crosid -v\" for explanation.\n"); - return NULL; - } - - INFO("Identified the device using libcrosid, " - "matched chromeos-config index: %d, " - "manifest key (model): %s\n", - matched_index, manifest_key); - model_name = manifest_key; - } - - for (i = 0; !model && i < manifest->num; i++) { - if (strcmp(model_name, manifest->models[i].name) == 0) - model = &manifest->models[i]; - } - if (!model) { - ERROR("Unsupported model: '%s'.\n", model_name); - - fprintf(stderr, - "The firmware manifest key '%s' is not present in this " - "updater archive. The known keys to this updater " - "archive are:\n", model_name); - - for (i = 0; i < manifest->num; i++) - fprintf(stderr, " %s", manifest->models[i].name); - fprintf(stderr, "\n\n"); - fprintf(stderr, - "Perhaps you are trying to use an updater archive for " - "the wrong board, or designed for an older OS version " - "before this model was supported.\n"); - fprintf(stderr, - "Hint: Read the FIRMWARE_MANIFEST_KEY from the output " - "of the crosid command.\n"); - } - - - free(manifest_key); - return model; -} - -/* - * Determines the signature ID to use for white label. - * Returns the signature ID for looking up rootkey and vblock files. - * Caller must free the returned string. - */ -static char *resolve_signature_id(struct model_config *model, const char *image) -{ - int is_unibuild = model->signature_id ? 1 : 0; - char *wl_tag = vpd_get_value(image, VPD_WHITELABEL_TAG); - char *sig_id = NULL; - - /* Unified build: $model.$wl_tag, or $model (b/126800200). */ - if (is_unibuild) { - if (!wl_tag) { - WARN("No VPD '%s' set for white label - use model name " - "'%s' as default.\n", VPD_WHITELABEL_TAG, - model->name); - return strdup(model->name); - } - - ASPRINTF(&sig_id, "%s-%s", model->name, wl_tag); - free(wl_tag); - return sig_id; - } - - /* Non-Unibuild: Upper($wl_tag), or Upper(${cid%%-*}). */ - if (!wl_tag) { - char *cid = vpd_get_value(image, VPD_CUSTOMIZATION_ID); - if (cid) { - /* customization_id in format LOEM[-VARIANT]. */ - char *dash = strchr(cid, '-'); - if (dash) - *dash = '\0'; - wl_tag = cid; - } - } - if (wl_tag) - str_convert(wl_tag, toupper); - return wl_tag; -} - -/* - * Applies white label information to an existing model configuration. - * Collects signature ID information from either parameter signature_id or - * image file (via VPD) and updates model.patches for key files. - * Returns 0 on success, otherwise failure. - */ -int model_apply_white_label( - struct model_config *model, - struct archive *archive, - const char *signature_id, - const char *image) -{ - char *sig_id = NULL; - int r = 0; - - if (!signature_id) { - sig_id = resolve_signature_id(model, image); - signature_id = sig_id; - } - - if (signature_id) { - VB2_DEBUG("Find white label patches by signature ID: '%s'.\n", - signature_id); - find_patches_for_model(model, archive, signature_id); - } else { - signature_id = ""; - WARN("No VPD '%s' set for white label - use default keys.\n", - VPD_WHITELABEL_TAG); - } - if (!model->patches.rootkey) { - ERROR("No keys found for signature_id: '%s'\n", signature_id); - r = 1; - } else { - INFO("Applied for white label: %s\n", signature_id); - } - free(sig_id); - return r; -} - -/* - * Creates a new manifest object by scanning files in archive. - * Returns the manifest on success, otherwise NULL for failure. - */ -struct manifest *new_manifest_from_archive(struct archive *archive) -{ - struct manifest manifest = {0}, *new_manifest; - struct model_config model = {0}; - const char * const host_image_name = "image.bin", - * const old_host_image_name = "bios.bin", - * const ec_name = "ec.bin", - * const pd_name = "pd.bin"; - - manifest.archive = archive; - manifest.default_model = -1; - archive_walk(archive, &manifest, manifest_scan_entries); - if (manifest.num == 0) { - const char *image_name = NULL; - struct firmware_image image = {0}; - - /* Try to load from current folder. */ - if (archive_has_entry(archive, old_host_image_name)) - image_name = old_host_image_name; - else if (archive_has_entry(archive, host_image_name)) - image_name = host_image_name; - else - return 0; - - model.image = strdup(image_name); - if (archive_has_entry(archive, ec_name)) - model.ec_image = strdup(ec_name); - if (archive_has_entry(archive, pd_name)) - model.pd_image = strdup(pd_name); - /* Extract model name from FWID: $Vendor_$Platform.$Version */ - if (!load_firmware_image(&image, image_name, archive)) { - char *token = NULL; - if (strtok(image.ro_version, "_")) - token = strtok(NULL, "."); - if (token && *token) { - str_convert(token, tolower); - model.name = strdup(token); - } - free_firmware_image(&image); - } - if (!model.name) - model.name = strdup(DEFAULT_MODEL_NAME); - if (manifest.has_keyset) - model.is_white_label = 1; - manifest_add_model(&manifest, &model); - manifest.default_model = manifest.num - 1; - } - VB2_DEBUG("%d model(s) loaded.\n", manifest.num); - if (!manifest.num) { - ERROR("No valid configurations found from archive.\n"); - return NULL; - } - - new_manifest = (struct manifest *)malloc(sizeof(manifest)); - if (!new_manifest) { - ERROR("Internal error: memory allocation error.\n"); - return NULL; - } - memcpy(new_manifest, &manifest, sizeof(manifest)); - return new_manifest; -} - -/* Releases all resources allocated by given manifest object. */ -void delete_manifest(struct manifest *manifest) -{ - int i; - assert(manifest); - for (i = 0; i < manifest->num; i++) { - struct model_config *model = &manifest->models[i]; - free(model->name); - free(model->signature_id); - free(model->image); - free(model->ec_image); - free(model->pd_image); - free(model->patches.rootkey); - free(model->patches.vblock_a); - free(model->patches.vblock_b); - } - free(manifest->models); - free(manifest); -} - -static const char *get_gbb_key_hash(const struct vb2_gbb_header *gbb, - int32_t offset, int32_t size) -{ - struct vb2_packed_key *key; - - if (!gbb) - return "<No GBB>"; - key = (struct vb2_packed_key *)((uint8_t *)gbb + offset); - if (vb2_packed_key_looks_ok(key, size)) - return "<Invalid key>"; - return packed_key_sha1_string(key); -} - -/* Prints the information of given image file in JSON format. */ -static void print_json_image( - const char *name, const char *fpath, struct model_config *m, - struct archive *archive, int indent, int is_host) -{ - struct firmware_image image = {0}; - const struct vb2_gbb_header *gbb = NULL; - if (!fpath) - return; - if (load_firmware_image(&image, fpath, archive)) - return; - if (!is_host) - printf(",\n"); - printf("%*s\"%s\": { \"versions\": { \"ro\": \"%s\", \"rw\": \"%s\" },", - indent, "", name, image.ro_version, image.rw_version_a); - indent += 2; - if (!is_host) { - /* No extra information to be printed */ - } else if (patch_image_by_model(&image, m, archive) != 0) { - ERROR("Failed to patch images by model: %s\n", m->name); - } else if (NULL != (gbb = find_gbb(&image))) { - printf("\n%*s\"keys\": { \"root\": \"%s\", ", - indent, "", - get_gbb_key_hash(gbb, gbb->rootkey_offset, - gbb->rootkey_size)); - printf("\"recovery\": \"%s\" },", - get_gbb_key_hash(gbb, gbb->recovery_key_offset, - gbb->recovery_key_size)); - } - printf("\n%*s\"image\": \"%s\" }", indent, "", fpath); - free_firmware_image(&image); -} - -/* Prints the information of objects in manifest (models and images) in JSON. */ -void print_json_manifest(const struct manifest *manifest) -{ - int i, indent; - struct archive *ar = manifest->archive; - - printf("{\n"); - for (i = 0, indent = 2; i < manifest->num; i++) { - struct model_config *m = &manifest->models[i]; - printf("%s%*s\"%s\": {\n", i ? ",\n" : "", indent, "", m->name); - indent += 2; - print_json_image("host", m->image, m, ar, indent, 1); - print_json_image("ec", m->ec_image, m, ar, indent, 0); - print_json_image("pd", m->pd_image, m, ar, indent, 0); - if (m->patches.rootkey) { - struct patch_config *p = &m->patches; - printf(",\n%*s\"patches\": { \"rootkey\": \"%s\", " - "\"vblock_a\": \"%s\", \"vblock_b\": \"%s\" }", - indent, "", p->rootkey, p->vblock_a, - p->vblock_b); - } - if (m->signature_id) - printf(",\n%*s\"signature_id\": \"%s\"", indent, "", - m->signature_id); - printf("\n }"); - indent -= 2; - assert(indent == 2); - } - printf("\n}\n"); -}
diff --git a/futility/updater_manifest.c b/futility/updater_manifest.c new file mode 100644 index 0000000..0760cb9 --- /dev/null +++ b/futility/updater_manifest.c
@@ -0,0 +1,890 @@ +/* Copyright 2022 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. + * + * Build up the list of updater resources from an archive. + */ + +#include <assert.h> +#if defined(__OpenBSD__) +#include <sys/types.h> +#endif + +#ifdef HAVE_CROSID +#include <crosid.h> +#endif + +#include "updater.h" +#include "util_misc.h" + +/* + * The updater reads image files from a package. The package is usually an + * archive (see updater_archive.c) with image files and configuration files, and + * the meta data is maintained by a "manifest" that described below. + * + * A package for single board (i.e., not Unified Build) will have all the image + * files in top folder: + * - host: 'image.bin' (or 'bios.bin' as legacy name before CL:1318712) + * - ec: 'ec.bin' + * - pd: 'pd.bin' + * If custom label is supported, a 'keyset/' folder will be available, with key + * files in it: + * - rootkey.$CLTAG + * - vblock_A.$CLTAG + * - vblock_B.$CLTAG + * The $CLTAG should come from VPD value 'custom_label_tag'. For legacy devices, + * the VPD name may be 'whitelabel_tag', or 'customization_id'. + * The 'customization_id' has a different format: LOEM[-VARIANT] and we can only + * take LOEM as $CLTAG, for example A-B => $CLTAG=A. + * + * A package for Unified Build is more complicated. There will be a models/ + * folder, and each model (by $(mosys platform model) ) should appear as a sub + * folder, with a 'setvars.sh' file inside. The 'setvars.sh' is a shell script + * describing what files should be used and the signature ID ($SIGID) to use. + * + * Similar to custom label in non-Unified-Build, the keys and vblock files will + * be in 'keyset/' folder: + * - rootkey.$SIGID + * - vblock_A.$SIGID + * - vblock_B.$SIGID + * If $SIGID starts with 'sig-id-in-*' then we have to replace it by VPD value + * 'custom_label_tag' as '$MODEL-$CLTAG'. + */ + +static const char * const SETVARS_IMAGE_MAIN = "IMAGE_MAIN", + * const SETVARS_IMAGE_EC = "IMAGE_EC", + * const SETVARS_IMAGE_PD = "IMAGE_PD", + * const SETVARS_SIGNATURE_ID = "SIGNATURE_ID", + * const SIG_ID_IN_VPD_PREFIX = "sig-id-in", + * const DIR_KEYSET = "keyset", + * const DIR_MODELS = "models", + * const DEFAULT_MODEL_NAME = "default", + * const VPD_CUSTOM_LABEL_TAG = "custom_label_tag", + * const VPD_CUSTOM_LABEL_TAG_LEGACY = "whitelabel_tag", + * const VPD_CUSTOMIZATION_ID = "customization_id", + * const ENV_VAR_MODEL_DIR = "${MODEL_DIR}", + * const PATH_STARTSWITH_KEYSET = "keyset/", + * const PATH_SIGNER_CONFIG = "signer_config.csv", + * const PATH_ENDSWITH_SETVARS = "/setvars.sh"; + +/* Utility function to convert a string. */ +static void str_convert(char *s, int (*convert)(int c)) +{ + int c; + + for (; *s; s++) { + c = *s; + if (!isascii(c)) + continue; + *s = convert(c); + } +} + +/* Returns 1 if name ends by given pattern, otherwise 0. */ +static int str_endswith(const char *name, const char *pattern) +{ + size_t name_len = strlen(name), pattern_len = strlen(pattern); + if (name_len < pattern_len) + return 0; + return strcmp(name + name_len - pattern_len, pattern) == 0; +} + +/* Returns 1 if name starts by given pattern, otherwise 0. */ +static int str_startswith(const char *name, const char *pattern) +{ + return strncmp(name, pattern, strlen(pattern)) == 0; +} + +/* Returns the VPD value by given key name, or NULL on error (or no value). */ +static char *vpd_get_value(const char *fpath, const char *key) +{ + char *command, *result; + + assert(fpath); + ASPRINTF(&command, "vpd -g %s -f %s 2>/dev/null", key, fpath); + result = host_shell(command); + free(command); + + if (result && !*result) { + free(result); + result = NULL; + } + return result; +} + +/* + * Reads and parses a setvars type file from archive, then stores into config. + * Returns 0 on success (at least one entry found), otherwise failure. + */ +static int model_config_parse_setvars_file( + struct model_config *cfg, struct u_archive *archive, + const char *fpath) +{ + uint8_t *data; + uint32_t len; + + char *ptr_line = NULL, *ptr_token = NULL; + char *line, *k, *v; + int valid = 0; + + if (archive_read_file(archive, fpath, &data, &len, NULL) != 0) { + ERROR("Failed reading: %s\n", fpath); + return -1; + } + + /* Valid content should end with \n, or \"; ensure ASCIIZ for parsing */ + if (len) + data[len - 1] = '\0'; + + for (line = strtok_r((char *)data, "\n\r", &ptr_line); line; + line = strtok_r(NULL, "\n\r", &ptr_line)) { + char *expand_path = NULL; + int found_valid = 1; + + /* Format: KEY="value" */ + k = strtok_r(line, "=", &ptr_token); + if (!k) + continue; + v = strtok_r(NULL, "\"", &ptr_token); + if (!v) + continue; + + /* Some legacy updaters may be still using ${MODEL_DIR}. */ + if (str_startswith(v, ENV_VAR_MODEL_DIR)) { + ASPRINTF(&expand_path, "%s/%s%s", DIR_MODELS, cfg->name, + v + strlen(ENV_VAR_MODEL_DIR)); + } + + if (strcmp(k, SETVARS_IMAGE_MAIN) == 0) + cfg->image = strdup(v); + else if (strcmp(k, SETVARS_IMAGE_EC) == 0) + cfg->ec_image = strdup(v); + else if (strcmp(k, SETVARS_IMAGE_PD) == 0) + cfg->pd_image = strdup(v); + else if (strcmp(k, SETVARS_SIGNATURE_ID) == 0) { + cfg->signature_id = strdup(v); + if (str_startswith(v, SIG_ID_IN_VPD_PREFIX)) + cfg->is_custom_label = 1; + } else + found_valid = 0; + free(expand_path); + valid += found_valid; + } + free(data); + return valid == 0; +} + +/* + * Changes the rootkey in firmware GBB to given new key. + * Returns 0 on success, otherwise failure. + */ +static int change_gbb_rootkey(struct firmware_image *image, + const char *section_name, + const uint8_t *rootkey, uint32_t rootkey_len) +{ + const struct vb2_gbb_header *gbb = find_gbb(image); + uint8_t *gbb_rootkey; + if (!gbb) { + ERROR("Cannot find GBB in image %s.\n", image->file_name); + return -1; + } + if (gbb->rootkey_size < rootkey_len) { + ERROR("New root key (%u bytes) larger than GBB (%u bytes).\n", + rootkey_len, gbb->rootkey_size); + return -1; + } + + gbb_rootkey = (uint8_t *)gbb + gbb->rootkey_offset; + /* See cmd_gbb_utility: root key must be first cleared with zero. */ + memset(gbb_rootkey, 0, gbb->rootkey_size); + memcpy(gbb_rootkey, rootkey, rootkey_len); + return 0; +} + +/* + * Changes the VBlock in firmware section to new data. + * Returns 0 on success, otherwise failure. + */ +static int change_vblock(struct firmware_image *image, const char *section_name, + const uint8_t *vblock, uint32_t vblock_len) +{ + struct firmware_section section; + + find_firmware_section(§ion, image, section_name); + if (!section.data) { + ERROR("Need section %s in image %s.\n", section_name, + image->file_name); + return -1; + } + if (section.size < vblock_len) { + ERROR("'%s' is too small (%zu bytes) for vblock (%u bytes).\n", + section_name, section.size, vblock_len); + return -1; + } + memcpy(section.data, vblock, vblock_len); + return 0; +} + +/* + * Applies a key file to firmware image. + * Returns 0 on success, otherwise failure. + */ +static int apply_key_file( + struct firmware_image *image, const char *path, + struct u_archive *archive, const char *section_name, + int (*apply)(struct firmware_image *image, const char *section, + const uint8_t *data, uint32_t len)) +{ + int r = 0; + uint8_t *data = NULL; + uint32_t len; + + r = archive_read_file(archive, path, &data, &len, NULL); + if (r == 0) { + VB2_DEBUG("Loaded file: %s\n", path); + r = apply(image, section_name, data, len); + if (r) + ERROR("Failed applying %s to %s\n", path, section_name); + } else { + ERROR("Failed reading: %s\n", path); + } + free(data); + return r; +} + +/* + * Modifies a firmware image from patch information specified in model config. + * Returns 0 on success, otherwise number of failures. + */ +int patch_image_by_model( + struct firmware_image *image, const struct model_config *model, + struct u_archive *archive) +{ + int err = 0; + if (model->patches.rootkey) + err += !!apply_key_file( + image, model->patches.rootkey, archive, + FMAP_RO_GBB, change_gbb_rootkey); + if (model->patches.vblock_a) + err += !!apply_key_file( + image, model->patches.vblock_a, archive, + FMAP_RW_VBLOCK_A, change_vblock); + if (model->patches.vblock_b) + err += !!apply_key_file( + image, model->patches.vblock_b, archive, + FMAP_RW_VBLOCK_B, change_vblock); + return err; +} + +/* + * Finds available patch files by given model. + * Updates `model` argument with path of patch files. + */ +static void find_patches_for_model(struct model_config *model, + struct u_archive *archive, + const char *signature_id) +{ + char *path; + int i; + + const char * const names[] = { + "rootkey", + "vblock_A", + "vblock_B", + }; + + char **targets[] = { + &model->patches.rootkey, + &model->patches.vblock_a, + &model->patches.vblock_b, + }; + + assert(ARRAY_SIZE(names) == ARRAY_SIZE(targets)); + for (i = 0; i < ARRAY_SIZE(names); i++) { + ASPRINTF(&path, "%s/%s.%s", DIR_KEYSET, names[i], signature_id); + if (archive_has_entry(archive, path)) + *targets[i] = path; + else + free(path); + } +} + +/* + * Adds and copies one new model config to the existing list of given manifest. + * Returns a pointer to the newly allocated config, or NULL on failure. + */ +static struct model_config *manifest_add_model( + struct manifest *manifest, + const struct model_config *cfg) +{ + struct model_config *model; + manifest->num++; + manifest->models = (struct model_config *)realloc( + manifest->models, manifest->num * sizeof(*model)); + if (!manifest->models) { + ERROR("Internal error: failed to allocate buffer.\n"); + return NULL; + } + model = &manifest->models[manifest->num - 1]; + memcpy(model, cfg, sizeof(*model)); + return model; +} + +/* + * A callback function for manifest to scan files in archive. + * Returns 0 to keep scanning, or non-zero to stop. + */ +static int manifest_scan_entries(const char *name, void *arg) +{ + struct manifest *manifest = (struct manifest *)arg; + struct u_archive *archive = manifest->archive; + struct model_config model = {0}; + char *slash; + + if (str_startswith(name, PATH_STARTSWITH_KEYSET)) + manifest->has_keyset = 1; + if (!str_endswith(name, PATH_ENDSWITH_SETVARS)) + return 0; + + /* name: models/$MODEL/setvars.sh */ + model.name = strdup(strchr(name, '/') + 1); + slash = strchr(model.name, '/'); + if (slash) + *slash = '\0'; + + VB2_DEBUG("Found model <%s> setvars: %s\n", model.name, name); + if (model_config_parse_setvars_file(&model, archive, name)) { + ERROR("Invalid setvars file: %s\n", name); + return 0; + } + + /* In legacy setvars.sh, the ec_image and pd_image may not exist. */ + if (model.ec_image && !archive_has_entry(archive, model.ec_image)) { + VB2_DEBUG("Ignore non-exist EC image: %s\n", model.ec_image); + free(model.ec_image); + model.ec_image = NULL; + } + if (model.pd_image && !archive_has_entry(archive, model.pd_image)) { + VB2_DEBUG("Ignore non-exist PD image: %s\n", model.pd_image); + free(model.pd_image); + model.pd_image = NULL; + } + + /* Find patch files. */ + if (model.signature_id) + find_patches_for_model(&model, archive, model.signature_id); + + return !manifest_add_model(manifest, &model); +} + +/* + * A callback function for manifest to scan files in raw /firmware archive. + * Returns 0 to keep scanning, or non-zero to stop. + */ +static int manifest_scan_raw_entries(const char *name, void *arg) +{ + struct manifest *manifest = (struct manifest *)arg; + struct u_archive *archive = manifest->archive; + struct model_config model = {0}; + char *ec_name = NULL; + int chars_read = 0; + + /* + * /build/$BOARD/firmware (or CPFE firmware archives) layout: + * - image-${MODEL}{,.serial,.dev...}.bin + * - ${MODEL}/ec.bin + */ + + if (sscanf(name, "image-%m[^.].bin%n", &model.name, &chars_read) != 1) + return 0; + + /* Ignore the names with extra modifiers like image-$MODEL.serial.bin */ + if (!chars_read || name[chars_read]) { + free(model.name); + return 0; + } + + VB2_DEBUG("Found model <%s>: %s\n", model.name, name); + model.image = strdup(name); + + ASPRINTF(&ec_name, "%s/ec.bin", model.name); + if (archive_has_entry(archive, ec_name)) + model.ec_image = strdup(ec_name); + free(ec_name); + + return !manifest_add_model(manifest, &model); +} + +/* Returns the matched model config from the manifest, or NULL if not found. */ +static struct model_config *manifest_get_model_config( + const struct manifest *manifest, const char *name) +{ + int i = 0; + + for (i = 0; i < manifest->num; i++) { + if (!strcmp(name, manifest->models[i].name)) + return &manifest->models[i]; + } + return NULL; +} + +/* + * Creates the manifest from the 'signer_config.csv' file. + * Returns 0 on success (loaded), otherwise failure. + */ +static int manifest_from_signer_config(struct manifest *manifest) +{ + struct u_archive *archive = manifest->archive; + uint32_t size; + uint8_t *data; + char *s, *tok_ptr = NULL; + + if (!archive_has_entry(archive, PATH_SIGNER_CONFIG)) + return -1; + + /* + * CSV format: model_name,firmware_image,key_id,ec_image + * + * Note the key_id is not signature_id and won't be used, and ec_image + * may be optional (for example sarien). + */ + + if (archive_read_file(archive, PATH_SIGNER_CONFIG, &data, &size,NULL)) { + ERROR("Failed reading: %s\n", PATH_SIGNER_CONFIG); + return -1; + } + + /* Skip headers. */ + s = strtok_r((char *)data, "\n", &tok_ptr); + if (!s || !strchr(s, ',')) { + ERROR("Invalid %s: missing header.\n", PATH_SIGNER_CONFIG); + free(data); + return -1; + } + + for (s = strtok_r(NULL, "\n", &tok_ptr); s != NULL; + s = strtok_r(NULL, "\n", &tok_ptr)) { + + struct model_config model = {0}; + int discard_model = 0; + + /* + * Both keyid (%3) and ec_image (%4) are optional so we want to + * read at least 2 fields. + */ + if (sscanf(s, "%m[^,],%m[^,],%*[^,],%m[^,]", + &model.name, &model.image, &model.ec_image) < 2) { + ERROR("Invalid entry(%s): %s\n", PATH_SIGNER_CONFIG, s); + discard_model = 1; + } else if (strchr(model.name, '-')) { + /* format: BaseModel-CustomLabel */ + char *tok_dash; + char *base_model; + struct model_config *base_model_config; + + VB2_DEBUG("Found custom-label: %s\n", model.name); + discard_model = 1; + base_model = strtok_r(model.name, "-", &tok_dash); + assert(base_model); + + /* + * Currently we assume the base model (e.g., base_model) + * is always listed before CL models in the CSV file - + * this is based on how the signerbot and the + * chromeos-config works today (validated on octopus). + */ + base_model_config = manifest_get_model_config( + manifest, base_model); + + if (!base_model_config) { + ERROR("Invalid CL-model: %s\n", base_model); + } else if (!base_model_config->is_custom_label) { + base_model_config->is_custom_label = 1; + /* + * Rewriting signature_id is not necessary, + * but in order to generate the same manifest + * from setvars, we want to temporarily use + * the special value. + */ + free(base_model_config->signature_id); + base_model_config->signature_id = strdup( + "sig-id-in-customization-id"); + } + } + + if (discard_model) { + free(model.name); + free(model.image); + free(model.ec_image); + continue; + } + + model.signature_id = strdup(model.name); + if (!manifest_add_model(manifest, &model)) + break; + } + free(data); + return 0; +} + +/* + * Creates the manifest from a simple (legacy) folder with only 1 set of + * firmware images. + * Returns 0 on success (loaded), otherwise failure. + */ +static int manifest_from_simple_folder(struct manifest *manifest) +{ + const char * const host_image_name = "image.bin", + * const old_host_image_name = "bios.bin", + * const ec_name = "ec.bin", + * const pd_name = "pd.bin"; + struct u_archive *archive = manifest->archive; + const char *image_name = NULL; + struct firmware_image image = {0}; + struct model_config model = {0}; + + /* Try to load from current folder. */ + if (archive_has_entry(archive, old_host_image_name)) + image_name = old_host_image_name; + else if (archive_has_entry(archive, host_image_name)) + image_name = host_image_name; + else + return 1; + + model.image = strdup(image_name); + if (archive_has_entry(archive, ec_name)) + model.ec_image = strdup(ec_name); + if (archive_has_entry(archive, pd_name)) + model.pd_image = strdup(pd_name); + /* Extract model name from FWID: $Vendor_$Platform.$Version */ + if (!load_firmware_image(&image, image_name, archive)) { + char *token = NULL; + if (strtok(image.ro_version, "_")) + token = strtok(NULL, "."); + if (token && *token) { + str_convert(token, tolower); + model.name = strdup(token); + } + free_firmware_image(&image); + } + if (!model.name) + model.name = strdup(DEFAULT_MODEL_NAME); + if (manifest->has_keyset) + model.is_custom_label = 1; + manifest_add_model(manifest, &model); + manifest->default_model = manifest->num - 1; + + return 0; +} + +/** + * get_manifest_key() - Wrapper to get the firmware manifest key from crosid + * + * @manifest_key_out - Output parameter of the firmware manifest key. + * + * Returns: + * - <0 if libcrosid is unavailable or there was an error reading + * device data + * - >=0 (the matched device index) success + */ +static int get_manifest_key(char **manifest_key_out) +{ +#ifdef HAVE_CROSID + return crosid_get_firmware_manifest_key(manifest_key_out); +#else + ERROR("This version of futility was compiled without libcrosid " + "(perhaps compiled outside of the Chrome OS build system?) and " + "the update command is not fully supported. Either compile " + "from the Chrome OS build, or pass --model to manually specify " + "the machine model.\n"); + return -1; +#endif +} + +/* + * Finds the existing model_config from manifest that best matches current + * system (as defined by model_name). + * Returns a model_config from manifest, or NULL if not found. + */ +const struct model_config *manifest_find_model(const struct manifest *manifest, + const char *model_name) +{ + char *manifest_key = NULL; + const struct model_config *model = NULL; + int i; + int matched_index; + + /* + * For manifest with single model defined, we should just return because + * there are other mechanisms like platform name check to double confirm + * if the firmware is valid. + */ + if (manifest->num == 1) + return &manifest->models[0]; + + if (!model_name) { + matched_index = get_manifest_key(&manifest_key); + if (matched_index < 0) { + ERROR("Failed to get device identity. " + "Run \"crosid -v\" for explanation.\n"); + return NULL; + } + + INFO("Identified the device using libcrosid, " + "matched chromeos-config index: %d, " + "manifest key (model): %s\n", + matched_index, manifest_key); + model_name = manifest_key; + } + + model = manifest_get_model_config(manifest, model_name); + + if (!model) { + ERROR("Unsupported model: '%s'.\n", model_name); + + fprintf(stderr, + "The firmware manifest key '%s' is not present in this " + "updater archive. The known keys to this updater " + "archive are:\n", model_name); + + for (i = 0; i < manifest->num; i++) + fprintf(stderr, " %s", manifest->models[i].name); + fprintf(stderr, "\n\n"); + fprintf(stderr, + "Perhaps you are trying to use an updater archive for " + "the wrong board, or designed for an older OS version " + "before this model was supported.\n"); + fprintf(stderr, + "Hint: Read the FIRMWARE_MANIFEST_KEY from the output " + "of the crosid command.\n"); + } + + + free(manifest_key); + return model; +} + +/* + * Determines the signature ID to use for custom label. + * Returns the signature ID for looking up rootkey and vblock files. + * Caller must free the returned string. + */ +static char *resolve_signature_id(struct model_config *model, const char *image) +{ + int is_unibuild = model->signature_id ? 1 : 0; + char *tag = vpd_get_value(image, VPD_CUSTOM_LABEL_TAG); + char *sig_id = NULL; + + if (tag == NULL) + tag = vpd_get_value(image, VPD_CUSTOM_LABEL_TAG_LEGACY); + + /* Unified build: $model.$tag, or $model (b/126800200). */ + if (is_unibuild) { + if (!tag) { + WARN("No VPD '%s' set for custom label. " + "Use model name '%s' as default.\n", + VPD_CUSTOM_LABEL_TAG, model->name); + return strdup(model->name); + } + + ASPRINTF(&sig_id, "%s-%s", model->name, tag); + free(tag); + return sig_id; + } + + /* Non-Unibuild: Upper($tag), or Upper(${cid%%-*}). */ + if (!tag) { + char *cid = vpd_get_value(image, VPD_CUSTOMIZATION_ID); + if (cid) { + /* customization_id in format LOEM[-VARIANT]. */ + char *dash = strchr(cid, '-'); + if (dash) + *dash = '\0'; + tag = cid; + } + } + if (tag) + str_convert(tag, toupper); + return tag; +} + +/* + * Applies custom label information to an existing model configuration. + * Collects signature ID information from either parameter signature_id or + * image file (via VPD) and updates model.patches for key files. + * Returns 0 on success, otherwise failure. + */ +int model_apply_custom_label( + struct model_config *model, + struct u_archive *archive, + const char *signature_id, + const char *image) +{ + char *sig_id = NULL; + int r = 0; + + if (!signature_id) { + sig_id = resolve_signature_id(model, image); + signature_id = sig_id; + } + + if (signature_id) { + VB2_DEBUG("Find custom label patches by signature ID: '%s'.\n", + signature_id); + find_patches_for_model(model, archive, signature_id); + } else { + signature_id = ""; + WARN("No VPD '%s' set for custom label - use default keys.\n", + VPD_CUSTOM_LABEL_TAG); + } + if (!model->patches.rootkey) { + ERROR("No keys found for signature_id: '%s'\n", signature_id); + r = 1; + } else { + INFO("Applied for custom label: %s\n", signature_id); + } + free(sig_id); + return r; +} + +/* + * Creates a new manifest object by scanning files in archive. + * Returns the manifest on success, otherwise NULL for failure. + */ +struct manifest *new_manifest_from_archive(struct u_archive *archive) +{ + struct manifest manifest = {0}, *new_manifest; + + manifest.archive = archive; + manifest.default_model = -1; + + VB2_DEBUG("Try to build a manifest from *%s\n", PATH_ENDSWITH_SETVARS); + archive_walk(archive, &manifest, manifest_scan_entries); + + if (manifest.num == 0) { + VB2_DEBUG("Try to build a manifest from %s\n", + PATH_SIGNER_CONFIG); + manifest_from_signer_config(&manifest); + } + if (manifest.num == 0) { + VB2_DEBUG("Try to build a manifest from a */firmware folder\n"); + archive_walk(archive, &manifest, manifest_scan_raw_entries); + } + if (manifest.num == 0) { + VB2_DEBUG("Try to build a manifest from a simple folder\n"); + manifest_from_simple_folder(&manifest); + } + + VB2_DEBUG("%d model(s) loaded.\n", manifest.num); + if (!manifest.num) { + ERROR("No valid configurations found from archive.\n"); + return NULL; + } + + new_manifest = (struct manifest *)malloc(sizeof(manifest)); + if (!new_manifest) { + ERROR("Internal error: memory allocation error.\n"); + return NULL; + } + memcpy(new_manifest, &manifest, sizeof(manifest)); + return new_manifest; +} + +/* Releases all resources allocated by given manifest object. */ +void delete_manifest(struct manifest *manifest) +{ + int i; + assert(manifest); + for (i = 0; i < manifest->num; i++) { + struct model_config *model = &manifest->models[i]; + free(model->name); + free(model->signature_id); + free(model->image); + free(model->ec_image); + free(model->pd_image); + free(model->patches.rootkey); + free(model->patches.vblock_a); + free(model->patches.vblock_b); + } + free(manifest->models); + free(manifest); +} + +static const char *get_gbb_key_hash(const struct vb2_gbb_header *gbb, + int32_t offset, int32_t size) +{ + struct vb2_packed_key *key; + + if (!gbb) + return "<No GBB>"; + key = (struct vb2_packed_key *)((uint8_t *)gbb + offset); + if (vb2_packed_key_looks_ok(key, size)) + return "<Invalid key>"; + return packed_key_sha1_string(key); +} + +/* Prints the information of given image file in JSON format. */ +static void print_json_image( + const char *name, const char *fpath, struct model_config *m, + struct u_archive *archive, int indent, int is_host) +{ + struct firmware_image image = {0}; + const struct vb2_gbb_header *gbb = NULL; + if (!fpath) + return; + if (load_firmware_image(&image, fpath, archive)) + return; + if (!is_host) + printf(",\n"); + printf("%*s\"%s\": { \"versions\": { \"ro\": \"%s\", \"rw\": \"%s\" },", + indent, "", name, image.ro_version, image.rw_version_a); + indent += 2; + if (is_host) { + if (patch_image_by_model(&image, m, archive)) + ERROR("Failed to patch images by model: %s\n", m->name); + else + gbb = find_gbb(&image); + } + if (gbb != NULL) { + printf("\n%*s\"keys\": { \"root\": \"%s\", ", + indent, "", + get_gbb_key_hash(gbb, gbb->rootkey_offset, + gbb->rootkey_size)); + printf("\"recovery\": \"%s\" },", + get_gbb_key_hash(gbb, gbb->recovery_key_offset, + gbb->recovery_key_size)); + } + printf("\n%*s\"image\": \"%s\" }", indent, "", fpath); + free_firmware_image(&image); +} + +/* Prints the information of objects in manifest (models and images) in JSON. */ +void print_json_manifest(const struct manifest *manifest) +{ + int i, indent; + struct u_archive *ar = manifest->archive; + + printf("{\n"); + for (i = 0, indent = 2; i < manifest->num; i++) { + struct model_config *m = &manifest->models[i]; + printf("%s%*s\"%s\": {\n", i ? ",\n" : "", indent, "", m->name); + indent += 2; + print_json_image("host", m->image, m, ar, indent, 1); + print_json_image("ec", m->ec_image, m, ar, indent, 0); + print_json_image("pd", m->pd_image, m, ar, indent, 0); + if (m->patches.rootkey) { + struct patch_config *p = &m->patches; + printf(",\n%*s\"patches\": { \"rootkey\": \"%s\", " + "\"vblock_a\": \"%s\", \"vblock_b\": \"%s\" }", + indent, "", p->rootkey, p->vblock_a, + p->vblock_b); + } + if (m->signature_id) + printf(",\n%*s\"signature_id\": \"%s\"", indent, "", + m->signature_id); + printf("\n }"); + indent -= 2; + assert(indent == 2); + } + printf("\n}\n"); +}
diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c index c8140c1..73b7c2f 100644 --- a/futility/updater_quirks.c +++ b/futility/updater_quirks.c
@@ -56,18 +56,23 @@ { .match = "Google_Scarlet.", .quirks = "min_platform_version=1" }, { .match = "Google_Trogdor.", .quirks = "min_platform_version=2" }, - /* Legacy white label units. */ - { .match = "Google_Enguarde.", .quirks = "allow_empty_wltag" }, - { .match = "Google_Expresso.", .quirks = "allow_empty_wltag" }, - { .match = "Google_Hana.", .quirks = "allow_empty_wltag" }, - { .match = "Google_Veyron_Jaq.", .quirks = "allow_empty_wltag" }, - { .match = "Google_Veyron_Jerry.", .quirks = "allow_empty_wltag" }, - { .match = "Google_Veyron_Mighty.", .quirks = "allow_empty_wltag" }, - { .match = "Google_Reks.", .quirks = "allow_empty_wltag" }, - { .match = "Google_Relm.", .quirks = "allow_empty_wltag" }, - { .match = "Google_Wizpig.", .quirks = "allow_empty_wltag" }, + /* Legacy custom label units. */ + { .match = "Google_Hana.", .quirks = "allow_empty_custom_label_tag" }, + { .match = "Google_Reks.", .quirks = "allow_empty_custom_label_tag" }, + { .match = "Google_Relm.", .quirks = "allow_empty_custom_label_tag" }, + { .match = "Google_Wizpig.", .quirks = "allow_empty_custom_label_tag" }, + { .match = "Google_Enguarde.", + .quirks = "allow_empty_custom_label_tag" }, + { .match = "Google_Expresso.", + .quirks = "allow_empty_custom_label_tag" }, + { .match = "Google_Veyron_Jaq.", + .quirks = "allow_empty_custom_label_tag" }, + { .match = "Google_Veyron_Jerry.", + .quirks = "allow_empty_custom_label_tag" }, + { .match = "Google_Veyron_Mighty.", + .quirks = "allow_empty_custom_label_tag" }, - { .match = "Google_Phaser.", .quirks = "override_signature_id" }, + { .match = "Google_Phaser.", .quirks = "override_signature_id" }, }; /* Preserves meta data and reload image contents from given file path. */ @@ -479,9 +484,9 @@ "dedicated FMAP section."; quirks->apply = quirk_eve_smm_store; - quirks = &cfg->quirks[QUIRK_ALLOW_EMPTY_WLTAG]; - quirks->name = "allow_empty_wltag"; - quirks->help = "chromium/906962; allow devices without white label " + quirks = &cfg->quirks[QUIRK_ALLOW_EMPTY_CUSTOM_LABEL_TAG]; + quirks->name = "allow_empty_custom_label_tag"; + quirks->help = "chromium/906962; allow devices without custom label " "tags set to use default keys."; quirks->apply = NULL; /* Simple config. */ @@ -516,6 +521,11 @@ quirks->name = "extra_retries"; quirks->help = "Extra retries when writing to system firmware."; quirks->apply = NULL; /* Simple config. */ + + quirks = &cfg->quirks[QUIRK_EXTERNAL_FLASHROM]; + quirks->name = "external_flashrom"; + quirks->help = "Use external flashrom to access the system firmware."; + quirks->apply = NULL; /* Simple config. */ } /*
diff --git a/futility/updater_utils.c b/futility/updater_utils.c index 18e4000..d879f78 100644 --- a/futility/updater_utils.c +++ b/futility/updater_utils.c
@@ -209,7 +209,7 @@ * failure, or IMAGE_PARSE_FAILURE for non-vboot images. */ int load_firmware_image(struct firmware_image *image, const char *file_name, - struct archive *archive) + struct u_archive *archive) { if (!file_name) { ERROR("No file name given\n"); @@ -419,7 +419,7 @@ static int host_get_wp_hw(void) { /* wpsw refers to write protection 'switch', not 'software'. */ - return VbGetSystemPropertyInt("wpsw_cur"); + return VbGetSystemPropertyInt("wpsw_cur") ? WP_ENABLED : WP_DISABLED; } /* A helper function to return "fw_vboot2" system property. */ @@ -456,16 +456,21 @@ * Helper function to detect type of Servo board attached to host. * Returns a string as programmer parameter on success, otherwise NULL. */ -char *host_detect_servo(int *need_prepare_ptr) +char *host_detect_servo(const char **prepare_ctrl_name) { const char *servo_port = getenv(ENV_SERVOD_PORT); const char *servo_name = getenv(ENV_SERVOD_NAME); char *servo_type = host_shell("dut-control -o servo_type 2>/dev/null"); const char *programmer = NULL; char *ret = NULL; - int need_prepare = 0; /* To prepare by dut-control cpu_fw_spi:on */ char *servo_serial = NULL; + static const char * const cpu_fw_spi = "cpu_fw_spi"; + static const char * const ccd_cpu_fw_spi = "ccd_cpu_fw_spi"; + + /* By default, no control is needed. */ + *prepare_ctrl_name = NULL; + /* Get serial name if servo port is provided. */ if ((servo_port && *servo_port) || (servo_name && *servo_name)) { const char *cmd = "dut-control -o serialname 2>/dev/null"; @@ -475,6 +480,9 @@ if (strstr(servo_type, "with_servo_micro")) cmd = ("dut-control -o servo_micro_serialname" " 2>/dev/null"); + else if (strstr(servo_type, "with_c2d2")) + cmd = ("dut-control -o c2d2_serialname" + " 2>/dev/null"); else if (strstr(servo_type, "with_ccd")) cmd = "dut-control -o ccd_serialname 2>/dev/null"; @@ -489,15 +497,20 @@ } else if (strstr(servo_type, "servo_micro")) { VB2_DEBUG("Selected Servo Micro.\n"); programmer = "raiden_debug_spi"; - need_prepare = 1; + *prepare_ctrl_name = cpu_fw_spi; + } else if (strstr(servo_type, "c2d2")) { + VB2_DEBUG("Selected C2D2.\n"); + programmer = "raiden_debug_spi"; + *prepare_ctrl_name = cpu_fw_spi; } else if (strstr(servo_type, "ccd_cr50") || strstr(servo_type, "ccd_gsc")) { VB2_DEBUG("Selected CCD.\n"); - programmer = "raiden_debug_spi:target=AP"; + programmer = "raiden_debug_spi:target=AP,custom_rst=true"; + *prepare_ctrl_name = ccd_cpu_fw_spi; } else { VB2_DEBUG("Selected Servo V2.\n"); programmer = "ft2232_spi:type=google-servo-v2"; - need_prepare = 1; + *prepare_ctrl_name = cpu_fw_spi; } if (programmer) { @@ -513,29 +526,250 @@ free(servo_type); free(servo_serial); - *need_prepare_ptr = need_prepare; return ret; } +/* + * Returns 1 if the programmers in image1 and image2 are the same. + */ +static int is_the_same_programmer(const struct firmware_image *image1, + const struct firmware_image *image2) +{ + assert(image1 && image2); + + /* Including if both are NULL. */ + if (image1->programmer == image2->programmer) + return 1; + + /* Not the same if either one is NULL. */ + if (!image1->programmer || !image2->programmer) + return 0; + + return strcmp(image1->programmer, image2->programmer) == 0; +} + +enum flash_command { + FLASH_READ = 0, + FLASH_WRITE, +}; + +/* Converts the flashrom_params to an equivalent flashrom command. */ +static char *get_flashrom_command(enum flash_command flash_cmd, + struct flashrom_params *params, + const char *image_name, + const char *contents_name) +{ + int i, len = 0; + char *partial = NULL; + char *cmd = NULL; + + if (!image_name) + image_name = "<IMAGE>"; + if (!contents_name) + contents_name = "<OLD-IMAGE>"; + + for (i = 0; params->regions && params->regions[i]; i++) + len += strlen(params->regions[i]) + strlen(" -i "); + + if (len) { + partial = (char *)malloc(len + 1); + if (!partial) { + ERROR("Failed to allocate a string buffer.\n"); + return NULL; + } + + partial[0] = '\0'; + for (i = 0; params->regions[i]; i++) { + strcat(partial, " -i "); + strcat(partial, params->regions[i]); + } + assert(strlen(partial) == len); + } + + switch (flash_cmd) { + case FLASH_READ: + ASPRINTF(&cmd, "flashrom -r %s -p %s%s%s", + image_name, + params->image->programmer, + params->verbose > 1 ? " -V" : "", + partial ? partial : ""); + break; + + case FLASH_WRITE: + ASPRINTF(&cmd, "flashrom -w %s -p %s%s%s%s%s%s", + image_name, + params->image->programmer, + params->flash_contents ? " --flash-contents " : "", + params->flash_contents ? contents_name : "", + params->noverify ? " --noverify" : "", + params->verbose > 1 ? " -V" : "", + partial ? partial : ""); + break; + + default: + ERROR("Unknown command: %d.\n", flash_cmd); + break; + } + free(partial); + return cmd; +} + +/* + * Emulates writing a firmware image to the system. + * Returns 0 if success, non-zero if error. + */ +static int emulate_write_firmware(const char *filename, + const struct firmware_image *image, + const char * const sections[]) +{ + int i, errorcnt = 0; + struct firmware_image to_image = {0}; + + INFO("Writing from %s to %s (emu=%s).\n", + image->file_name, image->programmer, filename); + + if (load_firmware_image(&to_image, filename, NULL)) { + ERROR("Cannot load image from %s.\n", filename); + return -1; + } + + if (image->size != to_image.size) { + ERROR("Image size is different (%s:%d != %s:%d)\n", + image->file_name, image->size, to_image.file_name, + to_image.size); + errorcnt++; + goto exit; + } + + if (!sections) { + VB2_DEBUG(" - write the whole image.\n"); + memmove(to_image.data, image->data, image->size); + } + for (i = 0; sections && sections[i]; i++) { + VB2_DEBUG(" - write the section: %s.\n", sections[i]); + if (preserve_firmware_section(image, &to_image, sections[i])) { + ERROR("Failed to write the section: %s\n", sections[i]); + errorcnt++; + /* + * Exit the loop, but still write the file to reflect + * the partial changes - same as real flashrom behavior. + */ + break; + } + } + + if (vb2_write_file(filename, to_image.data, to_image.size)) { + ERROR("Failed writing to file: %s\n", filename); + errorcnt++; + goto exit; + } + +exit: + free_firmware_image(&to_image); + return errorcnt; +} + +static int external_flashrom(enum flash_command flash_cmd, + struct flashrom_params *params, + struct tempfile *tempfiles) +{ + int r; + char *cmd; + const char *image_name = NULL, *contents_name = NULL; + + switch (flash_cmd) { + case FLASH_READ: + image_name = create_temp_file(tempfiles); + break; + + case FLASH_WRITE: + image_name = get_firmware_image_temp_file( + params->image, tempfiles); + if (params->flash_contents) + contents_name = get_firmware_image_temp_file( + params->flash_contents, tempfiles); + break; + + default: + ERROR("Unknown command: %d\n", flash_cmd); + return -1; + } + + cmd = get_flashrom_command(flash_cmd, params, image_name, + contents_name); + if (!cmd) + return -1; + + VB2_DEBUG(cmd); + r = system(cmd); + free(cmd); + if (r) + return r; + + switch (flash_cmd) { + case FLASH_READ: + r = load_firmware_image(params->image, image_name, NULL); + break; + default: + break; + } + + return r; +} + +static int read_flash(struct flashrom_params *params, + struct updater_config *cfg) +{ + if (get_config_quirk(QUIRK_EXTERNAL_FLASHROM, cfg)) + return external_flashrom(FLASH_READ, params, &cfg->tempfiles); + + return flashrom_read_image(params->image, NULL, params->verbose); +} + +static int write_flash(struct flashrom_params *params, + struct updater_config *cfg) +{ + int r; + + if (get_config_quirk(QUIRK_EXTERNAL_FLASHROM, cfg)) + return external_flashrom(FLASH_WRITE, params, &cfg->tempfiles); + + r = flashrom_write_image(params->image, + params->regions, + params->flash_contents, + !params->noverify, + params->verbose); + /* + * Force a newline to flush stdout in case if + * flashrom_write_image left some messages in the buffer. + */ + fprintf(stdout, "\n"); + return r; +} /* * Loads the active system firmware image (usually from SPI flash chip). * Returns 0 if success, non-zero if error. */ -int load_system_firmware(struct firmware_image *image, - struct tempfile *tempfiles, - int retries, int verbosity) +int load_system_firmware(struct updater_config *cfg, + struct firmware_image *image) { int r, i; + char *cmd; + const int tries = 1 + get_config_quirk(QUIRK_EXTRA_RETRIES, cfg); + struct flashrom_params params = {0}; - INFO("flasrhom -r <IMAGE> -p %s%s\n", - image->programmer, - verbosity ? " -V" : ""); + params.image = image; + params.verbose = cfg->verbosity + 1; /* libflashrom verbose 1 = WARN. */ - for (i = 1, r = -1; i <= retries && r != 0; i++) { + cmd = get_flashrom_command(FLASH_READ, ¶ms, NULL, NULL); + INFO("%s\n", cmd); + free(cmd); + + for (i = 1, r = -1; i <= tries && r != 0; i++, params.verbose++) { if (i > 1) - WARN("Retry reading firmware (%d/%d)...\n", i, retries); - r = flashrom_read_image(image, NULL, verbosity + 1); + WARN("Retry reading firmware (%d/%d)...\n", i, tries); + r = read_flash(¶ms, cfg); } if (!r) r = parse_firmware_image(image); @@ -548,49 +782,38 @@ * FMAP section names (and ended with a NULL). * Returns 0 if success, non-zero if error. */ -int write_system_firmware(const struct firmware_image *image, - const struct firmware_image *diff_image, - const char * const sections[], - struct tempfile *tempfiles, - int do_verify, int retries, int verbosity) +int write_system_firmware(struct updater_config *cfg, + const struct firmware_image *image, + const char * const sections[]) { - int r, i, len = 0; - char *partial = NULL; + int r = 0, i; + char *cmd; + const int tries = 1 + get_config_quirk(QUIRK_EXTRA_RETRIES, cfg); + struct flashrom_params params = {0}; + struct firmware_image *flash_contents = NULL; - for (i = 0; sections && sections[i]; i++) - len += strlen(sections[i]) + strlen(" -i "); - if (len) { - partial = (char *)malloc(len + 1); - if (!partial) { - ERROR("Failed to allocate a string buffer.\n"); - return -1; - } - partial[0] = '\0'; - for (i = 0; sections[i]; i++) { - strcat(partial, " -i "); - strcat(partial, sections[i]); - } - assert(strlen(partial) == len); - } + if (cfg->emulation) + return emulate_write_firmware(cfg->emulation, image, sections); - INFO("flashrom -w <IMAGE> -p %s%s%s%s%s\n", - image->programmer, - diff_image ? " --flash-contents <DIFF_IMAGE>" : "", - do_verify ? "" : " --noverify", - verbosity > 1 ? " -V" : "", - partial ? partial : ""); - free(partial); + if (cfg->use_diff_image && cfg->image_current.data && + is_the_same_programmer(&cfg->image_current, image)) + flash_contents = &cfg->image_current; - for (i = 1, r = -1; i <= retries && r != 0; i++) { + params.image = (struct firmware_image *)image; + params.flash_contents = flash_contents; + params.regions = sections; + params.noverify = !cfg->do_verify; + params.noverify_all = true; + params.verbose = cfg->verbosity + 1; /* libflashrom verbose 1 = WARN. */ + + cmd = get_flashrom_command(FLASH_WRITE, ¶ms, NULL, NULL); + INFO("%s\n", cmd); + free(cmd); + + for (i = 1, r = -1; i <= tries && r != 0; i++, params.verbose++) { if (i > 1) - WARN("Retry writing firmware (%d/%d)...\n", i, retries); - r = flashrom_write_image(image, sections, diff_image, do_verify, - verbosity + 1); - /* - * Force a newline to flush stdout in case if - * flashrom_write_image left some messages in the buffer. - */ - fprintf(stdout, "\n"); + WARN("Retry writing firmware (%d/%d)...\n", i, tries); + r = write_flash(¶ms, cfg); } return r; }
diff --git a/futility/updater_utils.h b/futility/updater_utils.h index 3eb1d33..a99c38c 100644 --- a/futility/updater_utils.h +++ b/futility/updater_utils.h
@@ -8,6 +8,7 @@ #ifndef VBOOT_REFERENCE_FUTILITY_UPDATER_UTILS_H_ #define VBOOT_REFERENCE_FUTILITY_UPDATER_UTILS_H_ +#include <stdbool.h> #include <stdio.h> #include "fmap.h" @@ -15,7 +16,7 @@ ERROR("Failed to allocate memory, abort.\n"); exit(1); } while (0) /* Structure(s) declared in updater_archive */ -struct archive; +struct u_archive; /* flashrom programmers. */ static const char * const PROG_HOST = "host", @@ -57,6 +58,23 @@ /* Include definition of 'struct firmware_image;' */ #include "flashrom.h" +/* Parameters when invoking flashrom. */ +struct flashrom_params { + struct firmware_image *image; /* The firmware image to read/write. */ + const struct firmware_image *flash_contents; /* --flash-contents */ + const char *const *regions; /* -i: only read/write <region> */ + bool noverify; /* -n: don't auto-verify */ + bool noverify_all; /* -N: verify included regions only */ + int verbose; /* -V: more verbose output */ + /* Supported by libflashrom but no exported by flashrom_drv: + * - force + * - noverify_all + * Not supported by libflashrom: + * - do_not_diff + * - ignore_lock + */ +}; + enum { IMAGE_LOAD_SUCCESS = 0, IMAGE_READ_FAILURE = -1, @@ -71,15 +89,17 @@ * failure, or IMAGE_PARSE_FAILURE for non-vboot images. */ int load_firmware_image(struct firmware_image *image, const char *file_name, - struct archive *archive); + struct u_archive *archive); + +/* Structure(s) declared in updater.h */ +struct updater_config; /* * Loads the active system firmware image (usually from SPI flash chip). * Returns 0 if success, non-zero if error. */ -int load_system_firmware(struct firmware_image *image, - struct tempfile *tempfiles, - int retries, int verbosity); +int load_system_firmware(struct updater_config *cfg, + struct firmware_image *image); /* Frees the allocated resource from a firmware image object. */ void free_firmware_image(struct firmware_image *image); @@ -98,11 +118,9 @@ * FMAP section names (and ended with a NULL). * Returns 0 if success, non-zero if error. */ -int write_system_firmware(const struct firmware_image *image, - const struct firmware_image *diff_image, - const char * const sections[], - struct tempfile *tempfiles, - int do_verify, int retries, int verbosity); +int write_system_firmware(struct updater_config *cfg, + const struct firmware_image *image, + const char * const sections[]); struct firmware_section { uint8_t *data; @@ -182,7 +200,7 @@ * Helper function to detect type of Servo board attached to host. * Returns a string as programmer parameter on success, otherwise NULL. */ -char *host_detect_servo(int *need_prepare_ptr); +char *host_detect_servo(const char **prepare_ctrl_name); /* * Returns 1 if a given file (cbfs_entry_name) exists inside a particular CBFS
diff --git a/futility/vb2_helper.c b/futility/vb2_helper.c index 4d676a6..a8452db 100644 --- a/futility/vb2_helper.c +++ b/futility/vb2_helper.c
@@ -60,7 +60,7 @@ return 1; } -int ft_show_vb21_pubkey(const char *name, uint8_t *buf, uint32_t len, +int show_vb21_pubkey_buf(const char *name, uint8_t *buf, uint32_t len, void *data) { struct vb2_public_key key; @@ -91,6 +91,22 @@ return 0; } +int ft_show_vb21_pubkey(const char *name, void *data) +{ + int fd = -1; + uint8_t *buf; + uint32_t len; + int rv; + + if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len)) + return 1; + + rv = show_vb21_pubkey_buf(name, buf, len, data); + + futil_unmap_and_close_file(fd, FILE_RO, buf, len); + return rv; +} + static int vb2_private_key_sha1sum(struct vb2_private_key *key, uint8_t *digest) { uint8_t *buf; @@ -106,15 +122,23 @@ return 1; } -int ft_show_vb21_privkey(const char *name, uint8_t *buf, uint32_t len, - void *data) +int ft_show_vb21_privkey(const char *name, void *data) { struct vb2_private_key *key = 0; uint8_t sha1sum[VB2_SHA1_DIGEST_SIZE]; + int fd = -1; + uint8_t *buf; + uint32_t len; + int rv = 0; - if (VB2_SUCCESS != vb21_private_key_unpack(&key, buf, len)) + if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len)) return 1; + if (VB2_SUCCESS != vb21_private_key_unpack(&key, buf, len)) { + rv = 1; + goto done; + } + printf("Private key file: %s\n", name); printf(" Vboot API: 2.1\n"); printf(" Desc: \"%s\"\n", key->desc ? key->desc : ""); @@ -132,7 +156,9 @@ printf("\n"); } vb2_private_key_free(key); - return 0; +done: + futil_unmap_and_close_file(fd, FILE_RO, buf, len); + return rv; } static RSA *rsa_from_buffer(uint8_t *buf, uint32_t len) @@ -172,7 +198,7 @@ return FILE_TYPE_UNKNOWN; } -int ft_show_pem(const char *name, uint8_t *buf, uint32_t len, void *data) +int ft_show_pem(const char *name, void *data) { RSA *rsa_key; uint8_t *keyb; @@ -180,6 +206,13 @@ uint32_t keyb_len; int i, bits; const BIGNUM *rsa_key_n, *rsa_key_d; + int fd = -1; + uint8_t *buf; + uint32_t len; + int rv = 0; + + if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len)) + return 1; /* We're called only after ft_recognize_pem, so this should work. */ rsa_key = rsa_from_buffer(buf, len); @@ -197,7 +230,8 @@ if (vb_keyb_from_rsa(rsa_key, &keyb, &keyb_len)) { printf(" Key sha1sum: <error>"); RSA_free(rsa_key); - return 1; + rv = 1; + goto done; } printf(" Key sha1sum: "); @@ -209,5 +243,7 @@ free(keyb); RSA_free(rsa_key); - return 0; +done: + futil_unmap_and_close_file(fd, FILE_RO, buf, len); + return rv; }
diff --git a/host/arch/x86/lib/crossystem_arch.c b/host/arch/x86/lib/crossystem_arch.c index d48cf87..4040ddc 100644 --- a/host/arch/x86/lib/crossystem_arch.c +++ b/host/arch/x86/lib/crossystem_arch.c
@@ -734,6 +734,8 @@ { "INTC1055:00", FindGpioChipOffsetByLabel }, { "INTC1056:00", FindGpioChipOffsetByLabel }, { "INTC1057:00", FindGpioChipOffsetByLabel }, + /* INTC108x are for Meteor Lake */ + { "INTC1083:00", FindGpioChipOffsetByLabel }, /* INT3453 are for GLK */ { "INT3453:00", FindGpioChipOffsetByLabel }, { "INT3453:01", FindGpioChipOffsetByLabel },
diff --git a/host/lib/cbfstool.c b/host/lib/cbfstool.c new file mode 100644 index 0000000..8f54706 --- /dev/null +++ b/host/lib/cbfstool.c
@@ -0,0 +1,72 @@ +/* Copyright 2022 The ChromiumOS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "2common.h" +#include "2return_codes.h" +#include "subprocess.h" +#include "cbfstool.h" + +static const char *get_cbfstool_path(void) +{ + static const char *cbfstool = NULL; + + if (cbfstool) + return cbfstool; + + const char *env_cbfstool = getenv(ENV_CBFSTOOL); + if (env_cbfstool && env_cbfstool[0] != '\0') { + cbfstool = strdup(env_cbfstool); + return cbfstool; + } + + cbfstool = DEFAULT_CBFSTOOL; + return cbfstool; +} + +vb2_error_t cbfstool_truncate(const char *file, const char *region, + size_t *new_size) +{ + int status; + char output_buffer[128]; + const char *cbfstool = get_cbfstool_path(); + + struct subprocess_target output = { + .type = TARGET_BUFFER_NULL_TERMINATED, + .buffer = { + .buf = output_buffer, + .size = sizeof(output_buffer), + }, + }; + const char *const argv[] = { + cbfstool, file, "truncate", "-r", region, NULL, + }; + + VB2_DEBUG("Calling: %s '%s' truncate -r '%s'\n", cbfstool, file, + region); + status = subprocess_run(argv, &subprocess_null, &output, + &subprocess_null); + + if (status < 0) { + fprintf(stderr, "%s(): cbfstool invocation failed: %m\n", + __func__); + exit(1); + } + + /* Positive exit code means something is wrong with image. Return zero + as new size, because it might be problem with missing CBFS.*/ + if (status > 0) { + *new_size = 0; + return VB2_ERROR_CBFSTOOL; + } + + if (sscanf(output_buffer, "%zi", new_size) != 1) { + VB2_DEBUG("Failed to parse command output. Unexpected " + "output.\n"); + *new_size = 0; + return VB2_ERROR_CBFSTOOL; + } + + return VB2_SUCCESS; +}
diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c index a5427c2..6d55335 100644 --- a/host/lib/crossystem.c +++ b/host/lib/crossystem.c
@@ -38,7 +38,8 @@ typedef enum VdatStringField { VDAT_STRING_DEPRECATED_TIMERS = 0, /* Timer values */ VDAT_STRING_LOAD_FIRMWARE_DEBUG, /* LoadFirmware() debug info */ - VDAT_STRING_DEPRECATED_LOAD_KERNEL_DEBUG, /* LoadKernel() debug info */ + VDAT_STRING_DEPRECATED_LOAD_KERNEL_DEBUG, /* vb2api_load_kernel() + debug info */ VDAT_STRING_MAINFW_ACT /* Active main firmware */ } VdatStringField;
diff --git a/host/lib/flashrom_drv.c b/host/lib/flashrom_drv.c index 1d9e3fd..19d6384 100644 --- a/host/lib/flashrom_drv.c +++ b/host/lib/flashrom_drv.c
@@ -189,12 +189,14 @@ } } flashrom_layout_set(flashctx, layout); + } else if (image->size != len) { + r = -1; + goto err_cleanup; } - flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, true); - flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, true); - if (!do_verify) - flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, false); + flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, false); + flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, + do_verify); r |= flashrom_image_write(flashctx, image->data, image->size, diff_image ? diff_image->data : NULL);
diff --git a/host/lib/include/cbfstool.h b/host/lib/include/cbfstool.h new file mode 100644 index 0000000..1343d40 --- /dev/null +++ b/host/lib/include/cbfstool.h
@@ -0,0 +1,12 @@ +/* Copyright 2022 The ChromiumOS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "2return_codes.h" + +#define ENV_CBFSTOOL "CBFSTOOL" +#define DEFAULT_CBFSTOOL "cbfstool" + +vb2_error_t cbfstool_truncate(const char *file, const char *region, + size_t *new_size);
diff --git a/scripts/image_signing/common.sh b/scripts/image_signing/common.sh index efa00a2..81bcac3 100644 --- a/scripts/image_signing/common.sh +++ b/scripts/image_signing/common.sh
@@ -136,5 +136,24 @@ sudo setfattr -n security.selinux -v "u:object_r:cros_conf_file:s0" "$1" } +# Extracts a firmware updater bundle (for firmware image binaries) file +# (generated by src/platform/firmware/pack_firmware.sh). +# Args: INPUT_FILE OUTPUT_DIR +extract_firmware_bundle() { + local input="$(readlink -f "$1")" + local output_dir="$2" + if [[ ! -s "${input}" ]]; then + return 1 + elif grep -q '^##CUTHERE##' "${input}"; then + # Bundle supports self-extraction. + "${input}" --sb_extract "${output_dir}" || + die "Extracting firmware autoupdate (--sb_extract) failed." + else + # Legacy bundle - try uudecode. + uudecode -o - "${input}" | tar -C "${output_dir}" -zxf - 2>/dev/null || + die "Extracting firmware autoupdate failed." + fi +} + # This will override the trap set in common_minmal.sh trap "cleanup" INT TERM EXIT
diff --git a/scripts/image_signing/ensure_amd_psp_flags.sh b/scripts/image_signing/ensure_amd_psp_flags.sh new file mode 100755 index 0000000..efccb69 --- /dev/null +++ b/scripts/image_signing/ensure_amd_psp_flags.sh
@@ -0,0 +1,115 @@ +#!/bin/bash +# Copyright 2022 The ChromiumOS Authors. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Load common constants and variables. +. "$(dirname "$0")/common.sh" + +# Abort on error and uninitialized variables. +set -eu + +declare -A -r REQUIRED_BIT_MASKS=( + # Bit 58 - PSP_S0I3_RESUME_VERSTAGE - Run PSP verstage during S0i3 resume. + # Checks that FW images have not been tampered with when exiting S0i3. + [guybrush]="$((1 << 58))" + [zork]="0x0" +) + +declare -A -r FORBIDDEN_BIT_MASKS=( + [guybrush]="0x0" + [zork]="0x0" +) + +# Grunt uses an old firmware format that amdfwread cannot read. +# See b/233787191 for skyrim. +BOARD_IGNORE_LIST=(grunt skyrim) + +usage() { + echo "$0: Validate AMD PSP soft-fuse flags contained in a ChromeOS image." \ + "These flags can have security implications and control debug features." + echo "Usage $0 <board> <image>" +} + +main() { + if [[ $# -ne 2 ]]; then + usage + exit 1 + fi + + local board="$1" + local image="$2" + + # Check the ignore list. + if [[ " ${BOARD_IGNORE_LIST[*]} " == *" ${board} "* ]]; then + echo "Skipping ignore-listed board ${board}" + exit 0 + fi + + # Mount the image. + local loopdev rootfs + if [[ -d "${image}" ]]; then + rootfs="${image}" + else + rootfs="$(make_temp_dir)" + loopdev="$(loopback_partscan "${image}")" + mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}" + fi + + local firmware_bundle shellball_dir + firmware_bundle="${rootfs}/usr/sbin/chromeos-firmwareupdate" + shellball_dir="$(make_temp_dir)" + + # Get the board specific bit masks. + local required_bit_mask forbidden_bit_mask + + if [[ ! -v "REQUIRED_BIT_MASKS[${board}]" ]]; then + die "Missing PSP required bit mask set for ${board}" + fi + + if [[ ! -v "FORBIDDEN_BIT_MASKS[${board}]" ]]; then + die "Missing PSP forbidden bit mask set for ${board}" + fi + + required_bit_mask="${REQUIRED_BIT_MASKS[${board}]}" + forbidden_bit_mask="${FORBIDDEN_BIT_MASKS[${board}]}" + + # Extract our firmware. + if ! extract_firmware_bundle "${firmware_bundle}" "${shellball_dir}"; then + die "Failed to extract firmware bundle" + fi + + # Find our images and check the soft-fuse bits in each. + declare -a images + readarray -t images < <(find "${shellball_dir}" -iname 'bios-*') + + local image + for image in "${images[@]}"; do + local soft_fuse soft_fuse_output forbidden_set missing_set + if ! soft_fuse_output="$(amdfwread --soft-fuse "${image}")"; then + die "'amdfwread --soft-fuse ${image}' failed" + fi + + # Output format from amdfwread is Soft-fuse:value, where value is in hex. + soft_fuse="$(echo "${soft_fuse_output}" | \ + sed -E -n 's/Soft-fuse:(0[xX][0-9a-fA-F]+)/\1/p')" + if [[ -z "${soft_fuse}" ]]; then + die "Could not parse Soft-fuse value from output: '${soft_fuse_output}'" + fi + + forbidden_set="$((soft_fuse & forbidden_bit_mask))" + if [[ "${forbidden_set}" != 0 ]]; then + local forbidden_hex + forbidden_hex="$(printf %#x "${forbidden_set}")" + die "${image}: Forbidden AMD PSP soft-fuse bits set: ${forbidden_hex}" + fi + + missing_set="$((~soft_fuse & required_bit_mask))" + if [[ "${missing_set}" != 0 ]]; then + local missing_hex + missing_hex="$(printf %#x "${missing_set}")" + die "${image}: Required AMD PSP soft-fuse bits not set: ${missing_hex}" + fi + done +} +main "$@"
diff --git a/scripts/image_signing/gbb_flags_common.sh b/scripts/image_signing/gbb_flags_common.sh index ed51f15..ae50c10 100755 --- a/scripts/image_signing/gbb_flags_common.sh +++ b/scripts/image_signing/gbb_flags_common.sh
@@ -62,10 +62,23 @@ flashrom -p "${programmer}" -i GBB --noverify-all -w "${file}" } -get_programmer_for_servo() { +CPU_FW_SPI="${FLAGS_FALSE}" + +enable_cpu_fw_spi() { + dut-control cpu_fw_spi:on >/dev/null + CPU_FW_SPI="${FLAGS_TRUE}" +} + +maybe_disable_cpu_fw_spi() { + if [ "${CPU_FW_SPI}" = "${FLAGS_TRUE}" ]; then + dut-control cpu_fw_spi:off >/dev/null + fi +} +trap "maybe_disable_cpu_fw_spi" EXIT + +update_programmer_for_servo() { local servo_type local serial - local programmer servo_type=$(dut-control -o servo_type 2>/dev/null) || \ die "Failed to get servo information. Is servod running?" case "${servo_type}" in @@ -84,10 +97,8 @@ esac case "${servo_type}" in *servo_micro*|*c2d2*) - # TODO(sammc): Support servo micro, servo v2 and C2D2. This requires - # toggling cpu_fw_spi via dut-control before and after running flashrom. - # C2D2 additionally requires a working cpu_fw_spi implementation. - die "Unsupported servo type ${servo_type}" + programmer="raiden_debug_spi:serial=${serial}" + enable_cpu_fw_spi ;; *ccd_cr50*|*ccd_gsc*) programmer="raiden_debug_spi:target=AP,serial=${serial}" @@ -96,5 +107,4 @@ die "Unsupported servo type ${servo_type}" ;; esac - echo "${programmer}" }
diff --git a/scripts/image_signing/get_gbb_flags.sh b/scripts/image_signing/get_gbb_flags.sh index 1191e9f..84acaa0 100755 --- a/scripts/image_signing/get_gbb_flags.sh +++ b/scripts/image_signing/get_gbb_flags.sh
@@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # Copyright 2017 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be @@ -30,7 +30,7 @@ if [ -z "${FLAGS_file}" ]; then image_file="$(make_temp_file)" if [ "${FLAGS_servo}" = "${FLAGS_TRUE}" ]; then - programmer=$(get_programmer_for_servo) + update_programmer_for_servo fi flashrom_read "${image_file}" "${programmer}" fi
diff --git a/scripts/image_signing/make_dev_firmware.sh b/scripts/image_signing/make_dev_firmware.sh index 0db5638..20c8414 100755 --- a/scripts/image_signing/make_dev_firmware.sh +++ b/scripts/image_signing/make_dev_firmware.sh
@@ -167,8 +167,6 @@ local recovery_pubkey="${FLAGS_keys}/recovery_key.vbpubk" local firmware_keyblock="${FLAGS_keys}/firmware.keyblock" local firmware_prvkey="${FLAGS_keys}/firmware_data_key.vbprivk" - local dev_firmware_keyblock="${FLAGS_keys}/dev_firmware.keyblock" - local dev_firmware_prvkey="${FLAGS_keys}/dev_firmware_data_key.vbprivk" local kernel_sub_pubkey="${FLAGS_keys}/kernel_subkey.vbpubk" local ec_efs_pubkey="${FLAGS_keys}/key_ec_efs.vbpubk2" local ec_efs_prvkey="${FLAGS_keys}/key_ec_efs.vbprik2" @@ -281,8 +279,6 @@ echo "Using keyblocks (developer, normal)..." else echo "Using keyblocks (normal, normal)..." - dev_firmware_prvkey="$firmware_prvkey" - dev_firmware_keyblock="$firmware_keyblock" fi debug_msg "Extract firmware version and data key version" @@ -351,8 +347,6 @@ "${IMAGE_BIOS}" \ "${firmware_prvkey}" \ "${firmware_keyblock}" \ - "${dev_firmware_prvkey}" \ - "${dev_firmware_keyblock}" \ "${kernel_sub_pubkey}" \ "${firmware_version}" \ ${optional_opts} ||
diff --git a/scripts/image_signing/resign_firmwarefd.sh b/scripts/image_signing/resign_firmwarefd.sh index d4cb5b8..ea23315 100755 --- a/scripts/image_signing/resign_firmwarefd.sh +++ b/scripts/image_signing/resign_firmwarefd.sh
@@ -20,20 +20,12 @@ DST_FD=$2 FIRMWARE_DATAKEY=$3 FIRMWARE_KEYBLOCK=$4 -DEV_FIRMWARE_DATAKEY=$5 -DEV_FIRMWARE_KEYBLOCK=$6 -KERNEL_SUBKEY=$7 +KERNEL_SUBKEY=$5 # optional -VERSION=$8 -PREAMBLE_FLAG=$9 -LOEM_OUTPUT_DIR=${10} -LOEMID=${11} - -if [ ! -e $DEV_FIRMWARE_KEYBLOCK ] || [ ! -e $DEV_FIRMWARE_DATAKEY ] ; then - echo "No dev firmware keyblock/datakey found. Reusing normal keys." - DEV_FIRMWARE_KEYBLOCK="$FIRMWARE_KEYBLOCK" - DEV_FIRMWARE_DATAKEY="$FIRMWARE_DATAKEY" -fi +VERSION=$6 +PREAMBLE_FLAG=$7 +LOEM_OUTPUT_DIR=$8 +LOEMID=$9 # pass optional args [ -n "$VERSION" ] && VERSION="--version $VERSION" @@ -44,8 +36,6 @@ exec ${FUTILITY} sign \ --signprivate $FIRMWARE_DATAKEY \ --keyblock $FIRMWARE_KEYBLOCK \ - --devsign $DEV_FIRMWARE_DATAKEY \ - --devkeyblock $DEV_FIRMWARE_KEYBLOCK \ --kernelkey $KERNEL_SUBKEY \ $VERSION \ $PREAMBLE_FLAG \
diff --git a/scripts/image_signing/set_gbb_flags.sh b/scripts/image_signing/set_gbb_flags.sh index 3057da5..57fd4c0 100755 --- a/scripts/image_signing/set_gbb_flags.sh +++ b/scripts/image_signing/set_gbb_flags.sh
@@ -55,7 +55,7 @@ if [ -z "${FLAGS_file}" ]; then image_file="$(make_temp_file)" if [ "${FLAGS_servo}" = "${FLAGS_TRUE}" ]; then - programmer=$(get_programmer_for_servo) + update_programmer_for_servo fi flashrom_read "${image_file}" "${programmer}"
diff --git a/scripts/image_signing/sign_android_image.sh b/scripts/image_signing/sign_android_image.sh index 5af1aa6..6b65545 100755 --- a/scripts/image_signing/sign_android_image.sh +++ b/scripts/image_signing/sign_android_image.sh
@@ -250,6 +250,48 @@ sudo find "${dir}" -exec stat -c '%n:%u:%g:%a' {} + | sort } +# Snapshot capabilities in a directory recursively. +snapshot_capabilities() { + local dir=$1 + sudo find "${dir}" -exec getcap {} + | sort +} + +# Apply capabilities to files in |dir| as specified by |capabilities_list|. +# See b/179170462. +apply_capabilities() { + local dir=$1 + local capabilities_list=$2 + local entry + + while read -ra entry; do + if [[ ${#entry[@]} -lt 2 ]]; then + error "Unexpected output in capabilities_list of '${entry[*]}'" + return 1 + fi + # Output of getcap is either |{file} {capabilities}| or + # |{file} = {capabilities}|, so take the first and last element of each + # line. + info "Setting capabilities ${entry[${#entry[@]}-1]} for ${entry[0]}" + sudo setcap "${entry[${#entry[@]}-1]}" "${entry[0]}" + done < "${capabilities_list}" + + return 0 +} + +# Integrity check that capabilities are unchanged. +capabilities_integrity_check() { + local system_mnt=$1 + local working_dir=$2 + snapshot_capabilities "${system_mnt}" > "${working_dir}/capabilities.new" + local d + if ! d=$(diff "${working_dir}"/capabilities.{orig,new}); then + error "Unexpected change of capabilities, diff \n${d}" + return 1 + fi + + return 0 +} + # Integrity check that image content is unchanged. image_content_integrity_check() { local system_mnt=$1 @@ -265,6 +307,12 @@ return 0 } +list_image_files() { + local unsquashfs=$1 + local system_img=$2 + "${unsquashfs}" -l "${system_img}" | grep ^squashfs-root +} + sign_android_internal() { local root_fs_dir=$1 local key_dir=$2 @@ -330,8 +378,17 @@ local working_dir=$(make_temp_dir) local system_mnt="${working_dir}/mnt" + local system_capabilities_orig="${working_dir}/capabilities.orig" - info "Unpacking squashfs system image to ${system_mnt}" + # Extract with xattrs so we can read and audit capabilities. See b/179170462. + info "Unpacking squashfs system image with xattrs to ${system_mnt}" + sudo "${unsquashfs}" -x -f -no-progress -d "${system_mnt}" "${system_img}" + snapshot_capabilities "${system_mnt}" > "${system_capabilities_orig}" + sudo rm -rf "${system_mnt}" + + info "Unpacking squashfs system image without xattrs to ${system_mnt}" + list_image_files "${unsquashfs}" "${system_img}" > \ + "${working_dir}/image_file_list.orig" sudo "${unsquashfs}" -no-xattrs -f -no-progress -d "${system_mnt}" "${system_img}" snapshot_file_properties "${system_mnt}" > "${working_dir}/properties.orig" @@ -399,6 +456,14 @@ info "Packages cache ${packages_cache} does not exist. Skip regeneration." fi + # Apply original capabilities to system image and verify correctness. + if ! apply_capabilities "${system_mnt}" "${system_capabilities_orig}"; then + return 1 + fi + if ! capabilities_integrity_check "${system_mnt}" "${working_dir}"; then + return 1 + fi + info "Repacking squashfs image with compression flags '${compression_flags}'" local old_size=$(stat -c '%s' "${system_img}") # Remove old system image to prevent mksquashfs tries to merge both images. @@ -408,6 +473,17 @@ -no-progress local new_size=$(stat -c '%s' "${system_img}") info "Android system image size change: ${old_size} -> ${new_size}" + + list_image_files "${unsquashfs}" "${system_img}" > \ + "${working_dir}/image_file_list.new" + if d=$(grep -v -F -x -f "${working_dir}"/image_file_list.{new,orig}); then + # If we have a line in image_file_list.orig which does not appear in + # image_file_list.new, it means some files are removed during signing + # process. Here we have already deleted the original Android image so + # cannot retry. + die "Unexpected change of file list\n${d}" + fi + return 0 }
diff --git a/scripts/image_signing/sign_firmware.sh b/scripts/image_signing/sign_firmware.sh index 0e7ac7c..ebc6cdc 100755 --- a/scripts/image_signing/sign_firmware.sh +++ b/scripts/image_signing/sign_firmware.sh
@@ -57,8 +57,6 @@ "${temp_fw}" \ "${key_dir}/firmware_data_key${loem_key}.vbprivk" \ "${key_dir}/firmware${loem_key}.keyblock" \ - "${key_dir}/dev_firmware_data_key${loem_key}.vbprivk" \ - "${key_dir}/dev_firmware${loem_key}.keyblock" \ "${key_dir}/kernel_subkey.vbpubk" \ "${firmware_version}" \ "" \
diff --git a/scripts/image_signing/sign_gsc_firmware.sh b/scripts/image_signing/sign_gsc_firmware.sh index af7b7da..a5945ce 100755 --- a/scripts/image_signing/sign_gsc_firmware.sh +++ b/scripts/image_signing/sign_gsc_firmware.sh
@@ -148,13 +148,11 @@ # needs to be verified and in certain cases altered. # # The function verifies that the input manifest is a proper json file, and -# that the manifest conforms to GSC version numbering and board ID flags -# conventions for various build images: -# -# - only binaries where version is set to CR50_NODE_LOCKED_VERSION can be -# converted to node locked images. Board IDs for node locked images come -# from signing instructions, and the config1 manifest field value must have -# the 0x80000000 bit set. +# that the manifest conforms to GSC board ID flags conventions for various +# build images: + +# - board IDs for node locked images come from signing instructions, and the +# config1 manifest field value must have the 0x80000000 bit set. # # - when signing pre-pvt binaries (major version number is even) the 0x10 # flags bit must be set. @@ -198,11 +196,6 @@ if [[ -z ${INSN_DEVICE_ID:-} ]]; then die "Node locked target without Device ID value" fi - # Case of a node locked image, it must have the fixed version. - if [[ "${epoch}.${major}.${minor}" != "${CR50_NODE_LOCKED_VERSION}" ]] - then - die "Won't create node locked images for version $epoch.$major.$minor" - fi local sub local devid0
diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh index 2f2621d..22cfa8c 100755 --- a/scripts/image_signing/sign_official_build.sh +++ b/scripts/image_signing/sign_official_build.sh
@@ -330,25 +330,6 @@ disable_rw_mount "${rootfs}" } -# Extracts a firmware updater bundle (for firmware image binaries) file -# (generated by src/platform/firmware/pack_firmware.sh). -# Args: INPUT_FILE OUTPUT_DIR -extract_firmware_bundle() { - local input="$(readlink -f "$1")" - local output_dir="$2" - if [ ! -s "${input}" ]; then - return 1 - elif grep -q '^##CUTHERE##' "${input}"; then - # Bundle supports self-extraction. - "$input" --sb_extract "${output_dir}" || - die "Extracting firmware autoupdate (--sb_extract) failed." - else - # Legacy bundle - try uudecode. - uudecode -o - ${input} | tar -C ${output_dir} -zxf - 2>/dev/null || - die "Extracting firmware autoupdate failed." - fi -} - # Repacks firmware updater bundle content from given folder. # Args: INPUT_DIR TARGET_SCRIPT repack_firmware_bundle() { @@ -515,14 +496,6 @@ local signprivate="${KEY_DIR}/firmware_data_key${key_suffix}.vbprivk" local keyblock="${KEY_DIR}/firmware${key_suffix}.keyblock" - local devsign="${KEY_DIR}/dev_firmware_data_key${key_suffix}.vbprivk" - local devkeyblock="${KEY_DIR}/dev_firmware${key_suffix}.keyblock" - - if [ ! -e "${devsign}" ] || [ ! -e "${devkeyblock}" ] ; then - echo "No dev firmware keyblock/datakey found. Reusing normal keys." - devsign="${signprivate}" - devkeyblock="${keyblock}" - fi # Path to bios.bin. local bios_path="${shellball_dir}/${bios_image}" @@ -566,8 +539,6 @@ echo "Signing Bios with:" ${FUTILITY} sign \ --signprivate "${signprivate}" \ --keyblock "${keyblock}" \ - --devsign "${devsign}" \ - --devkeyblock "${devkeyblock}" \ --kernelkey "${KEY_DIR}/kernel_subkey.vbpubk" \ --version "${FIRMWARE_VERSION}" \ "${extra_args[@]}" \ @@ -576,8 +547,6 @@ ${FUTILITY} sign \ --signprivate "${signprivate}" \ --keyblock "${keyblock}" \ - --devsign "${devsign}" \ - --devkeyblock "${devkeyblock}" \ --kernelkey "${KEY_DIR}/kernel_subkey.vbpubk" \ --version "${FIRMWARE_VERSION}" \ "${extra_args[@]}" \
diff --git a/scripts/keygeneration/accessory/create_new_gsc_key.sh b/scripts/keygeneration/accessory/create_new_gsc_key.sh new file mode 100755 index 0000000..a7e81c1 --- /dev/null +++ b/scripts/keygeneration/accessory/create_new_gsc_key.sh
@@ -0,0 +1,77 @@ +#!/bin/bash + +# Copyright 2022 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. + +# Load common constants and functions. +. "$(dirname "$0")/../common.sh" + +usage() { + cat <<EOF +Usage: ${PROG} [options] <key_file_base_name> + +Options: + -o, --output_dir <dir>: Where to write the keys (default is cwd) +EOF + + if [[ $# -ne 0 ]]; then + die "$*" + else + exit 0 + fi +} + +generate_rsa3070_key() { + local base_name="$1" + local len="3070" + + echo "creating ${base_name} key pair..." + + # Make the RSA key pair. + openssl genrsa -F4 -out "${base_name}.pem" "${len}" + openssl rsa -in "${base_name}.pem" -outform PEM \ + -pubout -out "${base_name}.pem.pub" +} + +main() { + set -euo pipefail + + local base_name + local output_dir="${PWD}" + + base_name="" + while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + usage + ;; + -o|--output_dir) + output_dir="$2" + if [[ ! -d "${output_dir}" ]]; then + die "output dir (${output_dir}) doesn't exist." + fi + shift + ;; + -*) + usage "Unknown option: $1" + ;; + *) + if [[ -z ${base_name} ]]; then + base_name="$1" + else + usage "Unknown argument $1" + fi + ;; + esac + shift + done + + if [[ -z ${base_name} ]]; then + usage "Key file base name missing" + fi + + generate_rsa3070_key "${output_dir}/${base_name}" +} + +main "$@"
diff --git a/scripts/keygeneration/create_new_keys.sh b/scripts/keygeneration/create_new_keys.sh index 2e1fd22..4a2ad33 100755 --- a/scripts/keygeneration/create_new_keys.sh +++ b/scripts/keygeneration/create_new_keys.sh
@@ -14,7 +14,6 @@ Usage: ${PROG} [options] Options: - --devkeyblock Also generate developer firmware keyblock and data key --android Also generate android keys --uefi Also generate UEFI keys --8k Use 8k keys instead of 4k (enables options below) @@ -36,8 +35,6 @@ main() { set -e - # Flag to indicate whether we should be generating a developer keyblock flag. - local dev_keyblock="false" local android_keys="false" local uefi_keys="false" local root_key_algoid=${ROOT_KEY_ALGOID} @@ -50,11 +47,6 @@ while [[ $# -gt 0 ]]; do case $1 in - --devkeyblock) - echo "Will also generate developer firmware keyblock and data key." - dev_keyblock="true" - ;; - --android) echo "Will also generate Android keys." android_keys="true" @@ -158,9 +150,6 @@ make_pair ec_data_key ${EC_DATAKEY_ALGOID} ${eckey_version} make_pair root_key ${root_key_algoid} make_pair firmware_data_key ${FIRMWARE_DATAKEY_ALGOID} ${fkey_version} - if [[ "${dev_keyblock}" == "true" ]]; then - make_pair dev_firmware_data_key ${DEV_FIRMWARE_DATAKEY_ALGOID} ${fkey_version} - fi make_pair kernel_subkey ${KERNEL_SUBKEY_ALGOID} ${ksubkey_version} make_pair kernel_data_key ${KERNEL_DATAKEY_ALGOID} ${kdatakey_version} @@ -178,11 +167,6 @@ # Ditto EC keyblock make_keyblock ec ${EC_KEYBLOCK_MODE} ec_data_key ec_root_key - if [[ "${dev_keyblock}" == "true" ]]; then - # Create the dev firmware keyblock for use only in Developer mode. - make_keyblock dev_firmware ${DEV_FIRMWARE_KEYBLOCK_MODE} dev_firmware_data_key root_key - fi - # Create the recovery kernel keyblock for use only in Recovery mode. make_keyblock recovery_kernel ${RECOVERY_KERNEL_KEYBLOCK_MODE} recovery_kernel_data_key recovery_key
diff --git a/tests/cgpt_fuzzer.c b/tests/cgpt_fuzzer.c index d440ee8..6762bc3 100644 --- a/tests/cgpt_fuzzer.c +++ b/tests/cgpt_fuzzer.c
@@ -25,7 +25,7 @@ static struct MockDisk mock_disk; -vb2_error_t VbExDiskRead(VbExDiskHandle_t h, uint64_t lba_start, +vb2_error_t VbExDiskRead(vb2ex_disk_handle_t h, uint64_t lba_start, uint64_t lba_count, void *buffer) { size_t lba_size = mock_disk.size >> mock_disk.sector_shift;
diff --git a/tests/cgptlib_test.c b/tests/cgptlib_test.c index 6fd7c32..f614977 100644 --- a/tests/cgptlib_test.c +++ b/tests/cgptlib_test.c
@@ -9,10 +9,10 @@ #include "../cgpt/cgpt.h" #include "cgptlib_internal.h" #include "cgptlib_test.h" +#include "common/tests.h" #include "crc32.h" #include "crc32_test.h" #include "gpt.h" -#include "test_common.h" /* * Testing partition layout (sector_bytes=512)
diff --git a/tests/chromeos_config_tests.c b/tests/chromeos_config_tests.c index 2408d8c..6b24a33 100644 --- a/tests/chromeos_config_tests.c +++ b/tests/chromeos_config_tests.c
@@ -11,8 +11,8 @@ #include "2common.h" #include "2return_codes.h" #include "chromeos_config.h" +#include "common/tests.h" #include "host_misc.h" -#include "test_common.h" static struct { const char *path;
diff --git a/tests/common.sh b/tests/common.sh index e69692b..a207922 100644 --- a/tests/common.sh +++ b/tests/common.sh
@@ -5,7 +5,7 @@ # found in the LICENSE file. # Determine script directory. -SCRIPT_DIR="$(dirname $(realpath "${BASH_SOURCE[0]}"))" +SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" ROOT_DIR="$(dirname "${SCRIPT_DIR}")" SRCDIR="${SRCDIR:-${ROOT_DIR}}" BUILD="${BUILD:-${ROOT_DIR}/build}" @@ -19,8 +19,8 @@ TESTCASE_DIR="${SCRIPT_DIR}/testcases" TESTKEY_SCRATCH_DIR="${TEST_DIR}/testkeys" -if [ ! -d ${TESTKEY_SCRATCH_DIR} ]; then - mkdir -p ${TESTKEY_SCRATCH_DIR} +if [ ! -d "${TESTKEY_SCRATCH_DIR}" ]; then + mkdir -p "${TESTKEY_SCRATCH_DIR}" fi # Color output encodings. @@ -53,7 +53,8 @@ *) lev=0 ;; esac - local x=$(caller $lev) + local x + x=$(caller $lev) local cline=${x%% *} local cfunc=${x#* } cfunc=${cfunc##*/} @@ -65,7 +66,6 @@ } function check_test_keys { - [ -d ${TESTKEY_DIR} ] || \ + [ -d "${TESTKEY_DIR}" ] || \ error 1 "You must run gen_test_keys.sh to generate test keys first." } -
diff --git a/tests/common/boot_mode.c b/tests/common/boot_mode.c new file mode 100644 index 0000000..342b790 --- /dev/null +++ b/tests/common/boot_mode.c
@@ -0,0 +1,48 @@ +/* Copyright 2022 The ChromiumOS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Some helper function related to boot mode. + */ + +#include "2api.h" +#include "2misc.h" +#include "2nvstorage.h" +#include "common/boot_mode.h" +#include "common/tests.h" + +void _set_boot_mode(struct vb2_context *ctx, enum vb2_boot_mode boot_mode, + uint32_t recovery_reason, ...) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + + switch (boot_mode) { + case VB2_BOOT_MODE_MANUAL_RECOVERY: + TEST_NEQ(recovery_reason, 0, + "recovery_reason should be set in recovery mode"); + ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; + sd->recovery_reason = recovery_reason; + ctx->flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE; + ctx->flags |= VB2_CONTEXT_EC_TRUSTED; + break; + case VB2_BOOT_MODE_BROKEN_SCREEN: + TEST_NEQ(recovery_reason, 0, + "recovery_reason should be set in recovery mode"); + ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; + sd->recovery_reason = recovery_reason; + break; + case VB2_BOOT_MODE_DIAGNOSTICS: + vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1); + break; + case VB2_BOOT_MODE_DEVELOPER: + ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; + break; + case VB2_BOOT_MODE_NORMAL: + break; + default: + TEST_TRUE(0, "SET_BOOT_MODE: Undefined boot mode"); + return; + } + vb2_set_boot_mode(ctx); + TEST_EQ(ctx->boot_mode, boot_mode, "Validity check for set boot mode"); +}
diff --git a/tests/common/boot_mode.h b/tests/common/boot_mode.h new file mode 100644 index 0000000..bd6a3fd --- /dev/null +++ b/tests/common/boot_mode.h
@@ -0,0 +1,20 @@ +/* Copyright 2022 The ChromiumOS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "2api.h" + +void _set_boot_mode(struct vb2_context *ctx, enum vb2_boot_mode boot_mode, + uint32_t recovery_reason, ...); + +/* + * Set the boot mode to the expected boot mode with the recovery reason if + * given. Also, set the corresponding ctx flag. + * + * @param ctx Vboot context. + * @param boot_mode Boot mode to be set. + * @param recovery_reason Recovery reason set to sd->recovery_reason. + */ +#define SET_BOOT_MODE(ctx, boot_mode, ...) \ + _set_boot_mode(ctx, boot_mode, ##__VA_ARGS__, 0)
diff --git a/tests/test_common.c b/tests/common/tests.c similarity index 98% rename from tests/test_common.c rename to tests/common/tests.c index 2ce3a5d..7df1613 100644 --- a/tests/test_common.c +++ b/tests/common/tests.c
@@ -10,7 +10,7 @@ #include <string.h> #include "2common.h" -#include "test_common.h" +#include "common/tests.h" /* Global test success flag. */ int gTestSuccess = 1;
diff --git a/tests/test_common.h b/tests/common/tests.h similarity index 96% rename from tests/test_common.h rename to tests/common/tests.h index c3da880..656e2d9 100644 --- a/tests/test_common.h +++ b/tests/common/tests.h
@@ -3,8 +3,8 @@ * found in the LICENSE file. */ -#ifndef VBOOT_REFERENCE_TEST_COMMON_H_ -#define VBOOT_REFERENCE_TEST_COMMON_H_ +#ifndef VBOOT_REFERENCE_COMMON_TESTS_H_ +#define VBOOT_REFERENCE_COMMON_TESTS_H_ #include <setjmp.h> #include <stdio.h> @@ -164,4 +164,4 @@ abort(); \ } while (0) -#endif /* VBOOT_REFERENCE_TEST_COMMON_H_ */ +#endif /* VBOOT_REFERENCE_COMMON_TESTS_H_ */
diff --git a/tests/timer_utils.c b/tests/common/timer_utils.c similarity index 100% rename from tests/timer_utils.c rename to tests/common/timer_utils.c
diff --git a/tests/timer_utils.h b/tests/common/timer_utils.h similarity index 79% rename from tests/timer_utils.h rename to tests/common/timer_utils.h index 8cafdf9..b2a424a 100644 --- a/tests/timer_utils.h +++ b/tests/common/timer_utils.h
@@ -3,8 +3,8 @@ * found in the LICENSE file. */ -#ifndef VBOOT_REFERENCE_TIMER_UTILS_H_ -#define VBOOT_REFERENCE_TIMER_UTILS_H_ +#ifndef VBOOT_REFERENCE_COMMON_TIMER_UTILS_H_ +#define VBOOT_REFERENCE_COMMON_TIMER_UTILS_H_ #include <inttypes.h> #include <time.h> @@ -23,4 +23,4 @@ /* Get duration in milliseconds. */ uint32_t GetDurationMsecs(ClockTimerState* ct); -#endif /* VBOOT_REFERENCE_TIMER_UTILS_H_ */ +#endif /* VBOOT_REFERENCE_COMMON_TIMER_UTILS_H_ */
diff --git a/tests/crc32_test.c b/tests/crc32_test.c index 1d1d8cd..ee60cc0 100644 --- a/tests/crc32_test.c +++ b/tests/crc32_test.c
@@ -4,9 +4,9 @@ */ #include "cgptlib_test.h" +#include "common/tests.h" #include "crc32.h" #include "crc32_test.h" -#include "test_common.h" #define MAX_VECTOR_LEN 256
diff --git a/tests/devkeys/arv_platform.keyblock b/tests/devkeys/arv_platform.keyblock new file mode 100644 index 0000000..f3c976c --- /dev/null +++ b/tests/devkeys/arv_platform.keyblock Binary files differ
diff --git a/tests/external_rsa_signer.sh b/tests/external_rsa_signer.sh index 0724b87..405df42 100755 --- a/tests/external_rsa_signer.sh +++ b/tests/external_rsa_signer.sh
@@ -1,9 +1,13 @@ #!/bin/bash +# Copyright (c) 2010 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. + if [ $# -ne 1 ]; then echo "Usage: $0 <private_key_pem_file>" echo "Reads data to sign from stdin, encrypted data is output to stdout" exit 1 fi -openssl rsautl -sign -inkey $1 +openssl rsautl -sign -inkey "$1"
diff --git a/tests/futility/data/README b/tests/futility/data/README index 6723f3d..3d577b8 100644 --- a/tests/futility/data/README +++ b/tests/futility/data/README
@@ -1,6 +1,7 @@ These are officially signed BIOS images from existing Chromebooks. - bios_mario_mp.bin uses old names for the FMAP areas - bios_zgb_mp.bin RW firmware A and B are different bios_link_mp.bin uses the RO_NORMAL flag to skip RW firmware validation bios_peppy_mp.bin doesn't do any of those things + +This is dev-signed BIOS image with CBFS support: + bios_voxel_dev.bin
diff --git a/tests/futility/data/bios_mario_mp.bin b/tests/futility/data/bios_mario_mp.bin deleted file mode 100644 index 8a6e8c5..0000000 --- a/tests/futility/data/bios_mario_mp.bin +++ /dev/null Binary files differ
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_data_key_offset_too_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_data_key_offset_too_big.xxd.patch new file mode 100644 index 0000000..cb79555 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_data_key_offset_too_big.xxd.patch
@@ -0,0 +1 @@ +00200050: b808 0000 0000 0000 0804 0000 0000 0000 ................
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_data_key_size_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_data_key_size_big.xxd.patch new file mode 100644 index 0000000..8667c3f --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_data_key_size_big.xxd.patch
@@ -0,0 +1 @@ +00200050: 2000 0000 0000 0000 3412 0100 0000 0000 .......4.......
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_fmap_too_small.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_fmap_too_small.xxd.patch new file mode 100644 index 0000000..2c01f2a --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_fmap_too_small.xxd.patch
@@ -0,0 +1,2 @@ +00610100: 0000 0000 0000 0000 0100 0000 2000 6e00 ............ .n. +00610110: 0000 5642 4c4f 434b 5f41 0000 0000 0000 ..VBLOCK_A......
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_fmap_too_small_for_whole.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_fmap_too_small_for_whole.xxd.patch new file mode 100644 index 0000000..3d79703 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_fmap_too_small_for_whole.xxd.patch
@@ -0,0 +1,2 @@ +00610100: 0000 0000 0000 0000 0100 0000 2000 b608 ............ ... +00610110: 0000 5642 4c4f 434b 5f41 0000 0000 0000 ..VBLOCK_A......
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_data_size_too_small.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_data_size_too_small.xxd.patch new file mode 100644 index 0000000..4f284d9 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_data_size_too_small.xxd.patch
@@ -0,0 +1 @@ +00200040: 6c00 0000 0000 0000 1700 0000 0000 0000 l...............
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_invalid_contents.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_invalid_contents.xxd.patch new file mode 100644 index 0000000..8b5fefd --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_invalid_contents.xxd.patch
@@ -0,0 +1 @@ +00200470: babb 3f4b 95db d458 4142 4344 4142 4344 ..?K...XABCDABCD
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_offset_too_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_offset_too_big.xxd.patch new file mode 100644 index 0000000..1a7044c --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_offset_too_big.xxd.patch
@@ -0,0 +1 @@ +00200030: 9808 0000 0000 0000 4000 0000 0000 0000 ........@.......
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_size_too_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_size_too_big.xxd.patch new file mode 100644 index 0000000..e6d90bf --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_hash_size_too_big.xxd.patch
@@ -0,0 +1 @@ +00200030: 4804 0000 0000 0000 b808 0000 0000 0000 H...............
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_invalid_magic.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_invalid_magic.xxd.patch new file mode 100644 index 0000000..00015e2 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_invalid_magic.xxd.patch
@@ -0,0 +1 @@ +00200000: 4142 4344 4143 4244 0200 0000 0100 0000 ABCDACBD........
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_invalid_major_version.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_invalid_major_version.xxd.patch new file mode 100644 index 0000000..637b90a --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_invalid_major_version.xxd.patch
@@ -0,0 +1 @@ +00200000: 4348 524f 4d45 4f53 0200 0000 0200 0000 CHROMEOS........
diff --git a/tests/futility/data/bios_peppy_dev.bad_keyblock_size_not_fully_signed.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_keyblock_size_not_fully_signed.xxd.patch new file mode 100644 index 0000000..1a24d43 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_keyblock_size_not_fully_signed.xxd.patch
@@ -0,0 +1 @@ +00200010: 7604 0000 0000 0000 a004 0000 0000 0000 v...............
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_body_signature_offset_too_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_body_signature_offset_too_big.xxd.patch new file mode 100644 index 0000000..31408e5 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_body_signature_offset_too_big.xxd.patch
@@ -0,0 +1 @@ +00200900: 0100 0000 0000 0000 7408 0000 0000 0000 ........t.......
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_body_signature_size_too_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_body_signature_size_too_big.xxd.patch new file mode 100644 index 0000000..083cfbe --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_body_signature_size_too_big.xxd.patch
@@ -0,0 +1 @@ +00200910: 7408 0000 0000 0000 183c 0200 0000 0000 t........<......
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_fmap_too_small.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_fmap_too_small.xxd.patch new file mode 100644 index 0000000..0f0968d --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_fmap_too_small.xxd.patch
@@ -0,0 +1,2 @@ +00610100: 0000 0000 0000 0000 0100 0000 2000 ee08 ............ ... +00610110: 0000 5642 4c4f 434b 5f41 0000 0000 0000 ..VBLOCK_A......
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_fmap_too_small_for_whole.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_fmap_too_small_for_whole.xxd.patch new file mode 100644 index 0000000..bd75624 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_fmap_too_small_for_whole.xxd.patch
@@ -0,0 +1,2 @@ +00610100: 0000 0000 0000 0000 0100 0000 2000 2411 ............ .$. +00610110: 0000 5642 4c4f 434b 5f41 0000 0000 0000 ..VBLOCK_A......
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_header_version_major.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_header_version_major.xxd.patch new file mode 100644 index 0000000..456a753 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_header_version_major.xxd.patch
@@ -0,0 +1 @@ +002008d0: 7406 0000 0000 0000 0300 0000 0100 0000 t...............
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_header_version_minor.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_header_version_minor.xxd.patch new file mode 100644 index 0000000..140b44e --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_header_version_minor.xxd.patch
@@ -0,0 +1 @@ +002008d0: 7406 0000 0000 0000 0200 0000 0000 0000 t...............
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_kernel_subkey_offset_too_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_kernel_subkey_offset_too_big.xxd.patch new file mode 100644 index 0000000..3c5a14c --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_kernel_subkey_offset_too_big.xxd.patch
@@ -0,0 +1 @@ +002008f0: 7408 0000 0000 0000 0700 0000 0000 0000 t...............
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_kernel_subkey_size_too_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_kernel_subkey_size_too_big.xxd.patch new file mode 100644 index 0000000..3c5a14c --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_kernel_subkey_size_too_big.xxd.patch
@@ -0,0 +1 @@ +002008f0: 7408 0000 0000 0000 0700 0000 0000 0000 t...............
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_signature_data_size_too_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_signature_data_size_too_big.xxd.patch new file mode 100644 index 0000000..f23f2e1 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_signature_data_size_too_big.xxd.patch
@@ -0,0 +1 @@ +002008d0: 8408 0000 0000 0000 0200 0000 0100 0000 ................
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_signature_data_size_too_small.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_signature_data_size_too_small.xxd.patch new file mode 100644 index 0000000..b02b497 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_signature_data_size_too_small.xxd.patch
@@ -0,0 +1 @@ +002008d0: 6400 0000 0000 0000 0200 0000 0100 0000 d...............
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_signature_invalid_contents.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_signature_invalid_contents.xxd.patch new file mode 100644 index 0000000..0fed2fe --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_signature_invalid_contents.xxd.patch
@@ -0,0 +1,2 @@ +00200f20: 78c9 3a24 85ab ca17 498e c238 4142 4344 x.:$....I..8ABCD +00200f30: 4142 4344 1cef bf68 b86b cdbc 3782 9f85 ABCD...h.k..7...
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_signature_offset_too_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_signature_offset_too_big.xxd.patch new file mode 100644 index 0000000..5159fef --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_signature_offset_too_big.xxd.patch
@@ -0,0 +1 @@ +002008c0: 7408 0000 0000 0000 0002 0000 0000 0000 t...............
diff --git a/tests/futility/data/bios_peppy_dev.bad_preamble_signature_size_too_big.xxd.patch b/tests/futility/data/bios_peppy_dev.bad_preamble_signature_size_too_big.xxd.patch new file mode 100644 index 0000000..9afc0ab --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bad_preamble_signature_size_too_big.xxd.patch
@@ -0,0 +1 @@ +002008c0: 6c06 0000 0000 0000 7408 0000 0000 0000 l.......t.......
diff --git a/tests/futility/data/bios_peppy_dev.bin b/tests/futility/data/bios_peppy_dev.bin new file mode 100644 index 0000000..f241cd0 --- /dev/null +++ b/tests/futility/data/bios_peppy_dev.bin Binary files differ
diff --git a/tests/futility/data/bios_voxel_dev.bin b/tests/futility/data/bios_voxel_dev.bin new file mode 100644 index 0000000..7cd8535 --- /dev/null +++ b/tests/futility/data/bios_voxel_dev.bin Binary files differ
diff --git a/tests/futility/data/bios_voxel_dev.no_b_slot.xxd.patch b/tests/futility/data/bios_voxel_dev.no_b_slot.xxd.patch new file mode 100644 index 0000000..6a01277 --- /dev/null +++ b/tests/futility/data/bios_voxel_dev.no_b_slot.xxd.patch
@@ -0,0 +1,20 @@ +01804030: 0000 0000 0000 1e00 0000 0000 0000 5000 ..............P. +018043a0: 0000 0000 0000 0000 0000 c0ff 4f01 4000 ............O.@. +018043b0: 0000 5257 5f46 5749 445f 4200 0000 0000 ..RW_FWID_B..... +018043d0: 0000 0000 0000 5001 0000 3000 4d45 5f52 ......P...0.ME_R +018043e0: 575f 4200 0000 0000 0000 0000 0000 0000 W_B............. +018043f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +01804400: 8001 0000 8000 5750 5f52 4f00 0000 0000 ......WP_RO..... +01804420: 0000 0000 0000 0000 0000 8001 0040 0000 .............@.. +01804430: 524f 5f56 5044 0000 0000 0000 0000 0000 RO_VPD.......... +01804450: 0800 0040 8001 00c0 7f00 524f 5f53 4543 ...@......RO_SEC +01804460: 5449 4f4e 0000 0000 0000 0000 0000 0000 TION............ +01804470: 0000 0000 0000 0000 0000 0000 0040 8001 .............@.. +01804480: 0008 0000 464d 4150 0000 0000 0000 0000 ....FMAP........ +018044a0: 0000 0000 0000 0048 8001 4000 0000 524f .......H..@...RO +018044b0: 5f46 5249 4400 0000 0000 0000 0000 0000 _FRID........... +018044d0: 0050 8001 0000 0700 4742 4200 0000 0000 .P......GBB..... +018044f0: 0000 0000 0000 0000 0000 0050 8701 00b0 ...........P.... +01804500: 7800 434f 5245 424f 4f54 0000 0000 0000 x.COREBOOT...... +01804520: 0000 0000 0050 8701 00b0 7800 434f 5245 .....P....x.CORE +01804530: 424f 4f54 0000 0000 0000 0000 0000 0000 BOOT............
diff --git a/tests/futility/data/bios_zgb_mp.bin b/tests/futility/data/bios_zgb_mp.bin deleted file mode 100644 index c85d820..0000000 --- a/tests/futility/data/bios_zgb_mp.bin +++ /dev/null Binary files differ
diff --git a/tests/futility/data_bios_voxel_dev.bin_expect.txt b/tests/futility/data_bios_voxel_dev.bin_expect.txt new file mode 100644 index 0000000..60cd1ea --- /dev/null +++ b/tests/futility/data_bios_voxel_dev.bin_expect.txt
@@ -0,0 +1,6 @@ +b11d74edd286c144e1135b49e7f0bc20cf041f10 +c14bd720b70d97394257e3e826bd8f43de48d4ed +e2c1c92d7d7aa7dfed5e8375edd30b7ae52b7450 +5d2b220899c4403d564092ada3f12d3cc4483223 +e2c1c92d7d7aa7dfed5e8375edd30b7ae52b7450 +5d2b220899c4403d564092ada3f12d3cc4483223
diff --git a/tests/futility/data_bios_zgb_mp.bin_expect.txt b/tests/futility/data_bios_zgb_mp.bin_expect.txt deleted file mode 100644 index 2a021ce..0000000 --- a/tests/futility/data_bios_zgb_mp.bin_expect.txt +++ /dev/null
@@ -1,6 +0,0 @@ -9f59876c7f7dc881f02d934786c6b7c2c17dcaac -9bd99a594c45b6739899a17ec29ac2289ee75463 -a0e4415cd4e271802504cce3a211b54562178fc8 -5d2b220899c4403d564092ada3f12d3cc4483223 -e2c1c92d7d7aa7dfed5e8375edd30b7ae52b7450 -5d2b220899c4403d564092ada3f12d3cc4483223
diff --git a/tests/futility/expect_output/show.tests_futility_data_bios_mario_mp.bin b/tests/futility/expect_output/show.tests_futility_data_bios_mario_mp.bin deleted file mode 100644 index 6039855..0000000 --- a/tests/futility/expect_output/show.tests_futility_data_bios_mario_mp.bin +++ /dev/null
@@ -1,63 +0,0 @@ -BIOS: tests/futility/data/bios_mario_mp.bin -GBB header: GBB Area - Version: 1.0 - Flags: 0x00000000 - Regions: offset size - hwid 0x00000080 0x00000100 - bmpvf 0x00001180 0x0003de80 - rootkey 0x00000180 0x00001000 - recovery_key 0x0003f000 0x00001000 - Size: 0x00040000 / 0x00040000 -GBB content: - HWID: {9D799111-A88A-439E-9E1F-FBBB41B00A9A} - digest: <none> - Root Key: - Vboot API: 1.0 - Algorithm: 11 RSA8192 SHA512 - Key Version: 1 - Key sha1sum: 541f467a7d8747f55ae9087ee4e34155f5ee3cd7 - Recovery Key: - Vboot API: 1.0 - Algorithm: 11 RSA8192 SHA512 - Key Version: 1 - Key sha1sum: 5d0d163b824cab5ae4f23fb2cc012e2a4124f4fe -Firmware body: Firmware A Data - Offset: 0x00040000 - Size: 0x000d0000 -Firmware body: Firmware B Data - Offset: 0x00120000 - Size: 0x000d0000 -Keyblock: Firmware A Key - Signature: valid - Size: 0x8b8 - Flags: 7 !DEV DEV !REC - Data key algorithm: 8 RSA4096 SHA512 - Data key version: 1 - Data key sha1sum: cd72cfb929765f82baba0a01ed937a73f502f6c5 -Firmware Preamble: - Size: 2164 - Header version: 2.1 - Firmware version: 1 - Kernel key algorithm: 8 RSA4096 SHA512 - Kernel key version: 1 - Kernel key sha1sum: e39e019cb5df3e874f443721540cb261a88c58ef - Firmware body size: 851968 - Preamble flags: 0 -Body verification succeeded. -Keyblock: Firmware B Key - Signature: valid - Size: 0x8b8 - Flags: 7 !DEV DEV !REC - Data key algorithm: 8 RSA4096 SHA512 - Data key version: 1 - Data key sha1sum: cd72cfb929765f82baba0a01ed937a73f502f6c5 -Firmware Preamble: - Size: 2164 - Header version: 2.1 - Firmware version: 1 - Kernel key algorithm: 8 RSA4096 SHA512 - Kernel key version: 1 - Kernel key sha1sum: e39e019cb5df3e874f443721540cb261a88c58ef - Firmware body size: 851968 - Preamble flags: 0 -Body verification succeeded.
diff --git a/tests/futility/expect_output/show.tests_futility_data_bios_peppy_mp.bin b/tests/futility/expect_output/show.tests_futility_data_bios_peppy_mp.bin new file mode 100644 index 0000000..88733c9 --- /dev/null +++ b/tests/futility/expect_output/show.tests_futility_data_bios_peppy_mp.bin
@@ -0,0 +1,63 @@ +BIOS: tests/futility/data/bios_peppy_mp.bin +GBB header: GBB + Version: 1.1 + Flags: 0x00000039 + Regions: offset size + hwid 0x00000080 0x00000100 + bmpvf 0x00001180 0x000ece80 + rootkey 0x00000180 0x00001000 + recovery_key 0x000ee000 0x00001000 + Size: 0x000ef000 / 0x000ef000 +GBB content: + HWID: X86 PEPPY TEST 4211 + digest: <none> + Root Key: + Vboot API: 1.0 + Algorithm: 11 RSA8192 SHA512 + Key Version: 1 + Key sha1sum: fc68bcb88bf9af1907289a9f377d658b3b9fe5b0 + Recovery Key: + Vboot API: 1.0 + Algorithm: 11 RSA8192 SHA512 + Key Version: 1 + Key sha1sum: bf39d0d3e30cbf6a121416d04df4603ad5310779 +Firmware body: FW_MAIN_A + Offset: 0x00210000 + Size: 0x000c0000 +Firmware body: FW_MAIN_B + Offset: 0x00300000 + Size: 0x000c0000 +Keyblock: VBLOCK_A + Signature: valid + Size: 0x8b8 + Flags: 7 !DEV DEV !REC + Data key algorithm: 8 RSA4096 SHA512 + Data key version: 1 + Data key sha1sum: f917ad29e36aa8a286f978c1aa0550ea31c6a561 +Firmware Preamble: + Size: 2164 + Header version: 2.1 + Firmware version: 2 + Kernel key algorithm: 7 RSA4096 SHA256 + Kernel key version: 2 + Kernel key sha1sum: cc05423373b76acbec23ec45dfa3696a2ea6dc0f + Firmware body size: 146456 + Preamble flags: 0 +Body verification succeeded. +Keyblock: VBLOCK_B + Signature: valid + Size: 0x8b8 + Flags: 7 !DEV DEV !REC + Data key algorithm: 8 RSA4096 SHA512 + Data key version: 1 + Data key sha1sum: f917ad29e36aa8a286f978c1aa0550ea31c6a561 +Firmware Preamble: + Size: 2164 + Header version: 2.1 + Firmware version: 2 + Kernel key algorithm: 7 RSA4096 SHA256 + Kernel key version: 2 + Kernel key sha1sum: cc05423373b76acbec23ec45dfa3696a2ea6dc0f + Firmware body size: 146456 + Preamble flags: 0 +Body verification succeeded.
diff --git a/tests/futility/expect_output/show.tests_futility_data_bios_zgb_mp.bin b/tests/futility/expect_output/show.tests_futility_data_bios_zgb_mp.bin deleted file mode 100644 index 2f9f807..0000000 --- a/tests/futility/expect_output/show.tests_futility_data_bios_zgb_mp.bin +++ /dev/null
@@ -1,63 +0,0 @@ -BIOS: tests/futility/data/bios_zgb_mp.bin -GBB header: GBB - Version: 1.0 - Flags: 0x00000000 - Regions: offset size - hwid 0x00000080 0x00000100 - bmpvf 0x00001180 0x0003de80 - rootkey 0x00000180 0x00001000 - recovery_key 0x0003f000 0x00001000 - Size: 0x00040000 / 0x00040000 -GBB content: - HWID: {FA42644C-CF3A-4692-A9D3-1A667CB232E9} - digest: <none> - Root Key: - Vboot API: 1.0 - Algorithm: 11 RSA8192 SHA512 - Key Version: 1 - Key sha1sum: 9f59876c7f7dc881f02d934786c6b7c2c17dcaac - Recovery Key: - Vboot API: 1.0 - Algorithm: 11 RSA8192 SHA512 - Key Version: 1 - Key sha1sum: 9bd99a594c45b6739899a17ec29ac2289ee75463 -Firmware body: FW_MAIN_A - Offset: 0x00030000 - Size: 0x000dffc0 -Firmware body: FW_MAIN_B - Offset: 0x00120000 - Size: 0x000dffc0 -Keyblock: VBLOCK_A - Signature: valid - Size: 0x8b8 - Flags: 6 DEV !REC - Data key algorithm: 8 RSA4096 SHA512 - Data key version: 1 - Data key sha1sum: a78aaa1691c2125ef8ccefa1a8a6bea92d38fae6 -Firmware Preamble: - Size: 2164 - Header version: 2.1 - Firmware version: 2 - Kernel key algorithm: 7 RSA4096 SHA256 - Kernel key version: 2 - Kernel key sha1sum: 0c9fd5b03ab47d37924ba8a7beb64039d84ed0e1 - Firmware body size: 917440 - Preamble flags: 0 -Body verification succeeded. -Keyblock: VBLOCK_B - Signature: valid - Size: 0x8b8 - Flags: 7 !DEV DEV !REC - Data key algorithm: 8 RSA4096 SHA512 - Data key version: 1 - Data key sha1sum: 4fe08ed739069d6834b68612eb707998a0825f34 -Firmware Preamble: - Size: 2164 - Header version: 2.1 - Firmware version: 2 - Kernel key algorithm: 7 RSA4096 SHA256 - Kernel key version: 2 - Kernel key sha1sum: 0c9fd5b03ab47d37924ba8a7beb64039d84ed0e1 - Firmware body size: 917440 - Preamble flags: 0 -Body verification succeeded.
diff --git a/tests/futility/models/whitetip/setvars.sh b/tests/futility/models/customtip/setvars.sh similarity index 87% rename from tests/futility/models/whitetip/setvars.sh rename to tests/futility/models/customtip/setvars.sh index 4b9cb40..a4bb55a 100755 --- a/tests/futility/models/whitetip/setvars.sh +++ b/tests/futility/models/customtip/setvars.sh
@@ -7,14 +7,14 @@ # particular model. The pack_firmware.py script uses this to create a working # setvars-model.sh script. -# Version information for model whitetip +# Version information for model customtip TARGET_RO_FWID="Google_Coral.10068.45.0" TARGET_FWID="Google_Coral.10068.45.0" TARGET_ECID="coral_v1.1.7272-0b44fba22" TARGET_PDID="" TARGET_PLATFORM="Google_Coral" -# Image and key files for model whitetip +# Image and key files for model customtip IMAGE_MAIN="images/bios_coral.bin" IMAGE_EC="" IMAGE_PD=""
diff --git a/tests/futility/run_test_scripts.sh b/tests/futility/run_test_scripts.sh index f224bdf..aeb3477 100755 --- a/tests/futility/run_test_scripts.sh +++ b/tests/futility/run_test_scripts.sh
@@ -62,11 +62,11 @@ if [ ! "$rc" ]; then echo -e "${COL_GREEN}PASSED${COL_STOP}" : $(( pass++ )) - rm -f ${OUTDIR}/$j.{stdout,stderr,return} + rm -f "${OUTDIR}/$j".{stdout,stderr,return} else echo -e "${COL_RED}FAILED (${rc:-0}). Stdout is recorded in" \ "${OUTDIR}/$j.stdout${COL_STOP}" - cat ${OUTDIR}/$j.stderr + cat "${OUTDIR}/$j.stderr" fi done
diff --git a/tests/futility/test_create.sh b/tests/futility/test_create.sh index 55c648c..77c7eb4 100755 --- a/tests/futility/test_create.sh +++ b/tests/futility/test_create.sh
@@ -15,7 +15,7 @@ # Demonstrate that we can recreate the same vb1 keys without the .keyb files for sig in rsa1024 rsa2048 rsa4096 rsa8192; do for hash in sha1 sha256 sha512; do - ${FUTILITY} --vb1 create --hash_alg "${hash}" \ + "${FUTILITY}" --vb1 create --hash_alg "${hash}" \ "${TESTKEYS}/key_${sig}.pem" "${TMP}_key_${sig}.${hash}" cmp "${TESTKEYS}/key_${sig}.${hash}.vbprivk" \ "${TMP}_key_${sig}.${hash}.vbprivk" @@ -29,7 +29,7 @@ # prove anything until we've used them to sign some stuff, though. for sig in rsa1024 rsa2048 rsa4096 rsa8192; do for hash in sha1 sha256 sha512; do - ${FUTILITY} --vb21 create --hash_alg "${hash}" \ + "${FUTILITY}" --vb21 create --hash_alg "${hash}" \ "${TESTKEYS}/key_${sig}.pem" "${TMP}_key_${sig}.${hash}" done done @@ -37,12 +37,12 @@ # Demonstrate that the sha1sums are the same for all the keys created from the # same .pem files, both public and private, vb1 and vb21. for sig in rsa1024 rsa2048 rsa4096 rsa8192; do - pem_sum=$(${FUTILITY} show "${TESTKEYS}/key_${sig}.pem" | + pem_sum=$("${FUTILITY}" show "${TESTKEYS}/key_${sig}.pem" | awk '/sha1sum/ {print $3}') # expect only one - [ $(echo "$pem_sum" | wc -w) = 1 ] - num_keys=$(echo ${TMP}_key_${sig}.* | wc -w) - key_sums=$(${FUTILITY} show ${TMP}_key_${sig}.* | + [ "$(echo "$pem_sum" | wc -w)" = 1 ] + num_keys=$(echo "${TMP}_key_${sig}".* | wc -w) + key_sums=$("${FUTILITY}" show "${TMP}_key_${sig}".* | awk '/sha1sum:|ID:/ {print $NF}') num_sums=$(echo "$key_sums" | wc -w) # expect one sha1sum (or ID) line per file @@ -57,7 +57,7 @@ # the private key. for sig in rsa1024 rsa2048 rsa4096 rsa8192; do for hash in sha1 sha256 sha512; do - ${FUTILITY} --vb21 create --hash_alg "${hash}" \ + "${FUTILITY}" --vb21 create --hash_alg "${hash}" \ "${TESTKEYS}/key_${sig}.pub.pem" "${TMP}_key_${sig}.pubonly.${hash}" cmp "${TMP}_key_${sig}.pubonly.${hash}.vbpubk2" \ "${TMP}_key_${sig}.${hash}.vbpubk2" @@ -65,5 +65,5 @@ done # cleanup -rm -rf ${TMP}* +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_dump_fmap.sh b/tests/futility/test_dump_fmap.sh index 5ae2e97..b8e418a 100755 --- a/tests/futility/test_dump_fmap.sh +++ b/tests/futility/test_dump_fmap.sh
@@ -51,5 +51,5 @@ # cleanup -rm -f ${TMP}* FMAP SI_DESC FOO +rm -f "${TMP}"* FMAP SI_DESC FOO exit 0
diff --git a/tests/futility/test_file_types.c b/tests/futility/test_file_types.c index 3f88872..ee433ba 100644 --- a/tests/futility/test_file_types.c +++ b/tests/futility/test_file_types.c
@@ -10,7 +10,7 @@ #include "file_type.h" #include "futility.h" -#include "test_common.h" +#include "common/tests.h" /* * Files that exemplify each type. @@ -26,8 +26,7 @@ {FILE_TYPE_KEYBLOCK, "tests/devkeys/kernel.keyblock"}, {FILE_TYPE_FW_PREAMBLE, "tests/futility/data/fw_vblock.bin"}, {FILE_TYPE_GBB, "tests/futility/data/fw_gbb.bin"}, - {FILE_TYPE_BIOS_IMAGE, "tests/futility/data/bios_zgb_mp.bin"}, - {FILE_TYPE_OLD_BIOS_IMAGE, "tests/futility/data/bios_mario_mp.bin"}, + {FILE_TYPE_BIOS_IMAGE, "tests/futility/data/bios_peppy_mp.bin"}, {FILE_TYPE_KERN_PREAMBLE, "tests/futility/data/kern_preamble.bin"}, {FILE_TYPE_RAW_FIRMWARE, }, /* need a test for this */ {FILE_TYPE_RAW_KERNEL, }, /* need a test for this */
diff --git a/tests/futility/test_file_types.sh b/tests/futility/test_file_types.sh index 4b7a9fb..313e408 100755 --- a/tests/futility/test_file_types.sh +++ b/tests/futility/test_file_types.sh
@@ -16,13 +16,13 @@ # Args are <expected_type>, <file_to_probe> test_case() { local result - result=$(${FUTILITY} show -t "${SRCDIR}/$2" | awk '{print $NF}') + result=$("${FUTILITY}" show -t "${SRCDIR}/$2" | awk '{print $NF}') [ "$1" = "$result" ] } # Arg is <file_to_probe> fail_case() { - if ${FUTILITY} show -t "$1" ; then false; else true; fi + if "${FUTILITY}" show -t "$1" ; then false; else true; fi } # Known types @@ -32,8 +32,7 @@ test_case "keyblock" "tests/devkeys/kernel.keyblock" test_case "fw_pre" "tests/futility/data/fw_vblock.bin" test_case "gbb" "tests/futility/data/fw_gbb.bin" -test_case "bios" "tests/futility/data/bios_zgb_mp.bin" -test_case "oldbios" "tests/futility/data/bios_mario_mp.bin" +test_case "bios" "tests/futility/data/bios_peppy_mp.bin" test_case "kernel" "tests/futility/data/kern_preamble.bin" # We don't have a way to identify these (yet?) # test_case "RAW_FIRMWARE" @@ -55,22 +54,23 @@ # often won't work, but it certainly shouldn't core dump. # We'll ask futility to tell us what types it supports -TYPES=$(${FUTILITY} show --type help | awk '/^ +/ {print $1}') +TYPES=$("${FUTILITY}" show --type help | awk '/^ +/ {print $1}') # And we'll just reuse the same files above. -FILES=$(awk '/^test_case / {print $NF}' $0 | tr -d '"') +FILES=$(awk '/^test_case / {print $NF}' "$0" | tr -d '"') # futility should normally exit with either 0 or 1. Make sure that happens. # NOTE: /bin/bash returns values > 125 for special problems like signals. # I welcome patches to do this more portably. for type in $TYPES; do for file in $FILES; do - ${FUTILITY} show --type ${type} "${SRCDIR}/${file}" && rc=$? || rc=$? + "${FUTILITY}" show --type "${type}" "${SRCDIR}/${file}" && \ + rc=$? || rc=$? [ "$rc" -le 2 ] done done # cleanup -rm -rf ${TMP}* +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_gbb_utility.sh b/tests/futility/test_gbb_utility.sh index bdfa262..5b783c4 100755 --- a/tests/futility/test_gbb_utility.sh +++ b/tests/futility/test_gbb_utility.sh
@@ -15,56 +15,58 @@ # First, let's test the basic functionality # For simplicity, we'll use the same size for all properties. -${FUTILITY} gbb -c 16,0x10,16,0x10 ${TMP}.blob +"${FUTILITY}" gbb -c 16,0x10,16,0x10 "${TMP}.blob" # Flags -${FUTILITY} gbb -s --flags=0xdeadbeef ${TMP}.blob -${FUTILITY} gbb -g --flags ${TMP}.blob | grep -i 0xdeadbeef +"${FUTILITY}" gbb -s --flags=0xdeadbeef "${TMP}.blob" +"${FUTILITY}" gbb -g --flags "${TMP}.blob" | grep -i 0xdeadbeef # HWID length should include the terminating null - this is too long -if ${FUTILITY} gbb -s --hwid="0123456789ABCDEF" ${TMP}.blob; then +if "${FUTILITY}" gbb -s --hwid="0123456789ABCDEF" "${TMP}.blob"; then false; fi # This works -${FUTILITY} gbb -s --hwid="0123456789ABCDE" ${TMP}.blob +"${FUTILITY}" gbb -s --hwid="0123456789ABCDE" "${TMP}.blob" # Read it back? -${FUTILITY} gbb -g ${TMP}.blob | grep "0123456789ABCDE" +"${FUTILITY}" gbb -g "${TMP}.blob" | grep "0123456789ABCDE" # Same kind of tests for the other fields, but they need binary files. # too long -dd if=/dev/urandom bs=17 count=1 of=${TMP}.data1.toolong -dd if=/dev/urandom bs=17 count=1 of=${TMP}.data2.toolong -if ${FUTILITY} gbb -s --rootkey ${TMP}.data1.toolong ${TMP}.blob; then false; fi -if ${FUTILITY} gbb -s --recoverykey ${TMP}.data2.toolong ${TMP}.blob; then false; fi +dd if=/dev/urandom bs=17 count=1 of="${TMP}.data1.toolong" +dd if=/dev/urandom bs=17 count=1 of="${TMP}.data2.toolong" +if "${FUTILITY}" gbb -s --rootkey "${TMP}.data1.toolong" "${TMP}.blob"; + then false; fi +if "${FUTILITY}" gbb -s --recoverykey "${TMP}.data2.toolong" "${TMP}.blob"; + then false; fi # shorter than max should be okay, though -dd if=/dev/urandom bs=10 count=1 of=${TMP}.data1.short -dd if=/dev/urandom bs=10 count=1 of=${TMP}.data2.short -${FUTILITY} gbb -s \ - --rootkey ${TMP}.data1.short \ - --recoverykey ${TMP}.data2.short ${TMP}.blob +dd if=/dev/urandom bs=10 count=1 of="${TMP}.data1.short" +dd if=/dev/urandom bs=10 count=1 of="${TMP}.data2.short" +"${FUTILITY}" gbb -s \ + --rootkey "${TMP}.data1.short" \ + --recoverykey "${TMP}.data2.short" "${TMP}.blob" # read 'em back -${FUTILITY} gbb -g \ - --rootkey ${TMP}.read1 \ - --recoverykey ${TMP}.read2 ${TMP}.blob +"${FUTILITY}" gbb -g \ + --rootkey "${TMP}.read1" \ + --recoverykey "${TMP}.read2" "${TMP}.blob" # Verify (but remember, it's short) -cmp -n 10 ${TMP}.data1.short ${TMP}.read1 -cmp -n 10 ${TMP}.data2.short ${TMP}.read2 +cmp -n 10 "${TMP}.data1.short" "${TMP}.read1" +cmp -n 10 "${TMP}.data2.short" "${TMP}.read2" # Okay -dd if=/dev/urandom bs=16 count=1 of=${TMP}.data1 -dd if=/dev/urandom bs=16 count=1 of=${TMP}.data2 -dd if=/dev/urandom bs=16 count=1 of=${TMP}.data3 -${FUTILITY} gbb -s --rootkey ${TMP}.data1 ${TMP}.blob -${FUTILITY} gbb -s --recoverykey ${TMP}.data2 ${TMP}.blob +dd if=/dev/urandom bs=16 count=1 of="${TMP}.data1" +dd if=/dev/urandom bs=16 count=1 of="${TMP}.data2" +dd if=/dev/urandom bs=16 count=1 of="${TMP}.data3" +"${FUTILITY}" gbb -s --rootkey "${TMP}.data1" "${TMP}.blob" +"${FUTILITY}" gbb -s --recoverykey "${TMP}.data2" "${TMP}.blob" # Read 'em back. -${FUTILITY} gbb -g --rootkey ${TMP}.read1 ${TMP}.blob -${FUTILITY} gbb -g --recoverykey ${TMP}.read2 ${TMP}.blob +"${FUTILITY}" gbb -g --rootkey "${TMP}.read1" "${TMP}.blob" +"${FUTILITY}" gbb -g --recoverykey "${TMP}.read2" "${TMP}.blob" # Verify -cmp ${TMP}.data1 ${TMP}.read1 -cmp ${TMP}.data2 ${TMP}.read2 +cmp "${TMP}.data1" "${TMP}.read1" +cmp "${TMP}.data2" "${TMP}.read2" # Okay, creating GBB blobs seems to work. Now let's make sure that corrupted @@ -100,82 +102,85 @@ # # bad major_version -cat ${TMP}.blob | ${REPLACE} 0x4 2 > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x4 2 < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi # header size too large -cat ${TMP}.blob | ${REPLACE} 0x8 0x81 > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x8 0x81 < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi # header size too small -cat ${TMP}.blob | ${REPLACE} 0x8 0x7f > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x8 0x7f < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi # HWID not null-terminated is invalid -cat ${TMP}.blob | ${REPLACE} 0x8f 0x41 > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x8f 0x41 < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi # HWID of length zero is okay -cat ${TMP}.blob | ${REPLACE} 0x14 0x00 > ${TMP}.blob.ok -${FUTILITY} gbb ${TMP}.blob.ok +"${REPLACE}" 0x14 0x00 < "${TMP}.blob" > "${TMP}.blob.ok" +"${FUTILITY}" gbb "${TMP}.blob.ok" # And HWID of length 1 consisting only of '\0' is okay, too. -cat ${TMP}.blob | ${REPLACE} 0x14 0x01 | ${REPLACE} 0x80 0x00 > ${TMP}.blob.ok -${FUTILITY} gbb ${TMP}.blob.ok +"${REPLACE}" 0x14 0x01 < "${TMP}.blob" | "${REPLACE}" 0x80 0x00 \ + > "${TMP}.blob.ok" +"${FUTILITY}" gbb "${TMP}.blob.ok" # zero-length HWID not null-terminated is invalid -cat ${TMP}.blob | ${REPLACE} 0x8f 0x41 > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x8f 0x41 < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi # hwid_offset < GBB_HEADER_SIZE is invalid -cat ${TMP}.blob | ${REPLACE} 0x10 0x7f > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi -cat ${TMP}.blob | ${REPLACE} 0x10 0x00 > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x10 0x7f < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi +"${REPLACE}" 0x10 0x00 < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi # rootkey_offset < GBB_HEADER_SIZE is invalid -cat ${TMP}.blob | ${REPLACE} 0x18 0x7f > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi -cat ${TMP}.blob | ${REPLACE} 0x18 0x00 > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x18 0x7f < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi +"${REPLACE}" 0x18 0x00 < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi # recovery_key_offset < GBB_HEADER_SIZE is invalid -cat ${TMP}.blob | ${REPLACE} 0x28 0x7f > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi -cat ${TMP}.blob | ${REPLACE} 0x28 0x00 > ${TMP}.blob.bad -if ${FUTILITY} gbb ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x28 0x7f < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi +"${REPLACE}" 0x28 0x00 < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb "${TMP}.blob.bad"; then false; fi # hwid: offset + size == end of file is okay; beyond is invalid -cat ${TMP}.blob | ${REPLACE} 0x14 0x40 > ${TMP}.blob.bad -${FUTILITY} gbb -g ${TMP}.blob.bad -cat ${TMP}.blob | ${REPLACE} 0x14 0x41 > ${TMP}.blob.bad -if ${FUTILITY} gbb -g ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x14 0x40 < "${TMP}.blob" > "${TMP}.blob.bad" +"${FUTILITY}" gbb -g "${TMP}.blob.bad" +"${REPLACE}" 0x14 0x41 < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb -g "${TMP}.blob.bad"; then false; fi # rootkey: offset + size == end of file is okay; beyond is invalid -cat ${TMP}.blob | ${REPLACE} 0x1c 0x30 > ${TMP}.blob.bad -${FUTILITY} gbb -g ${TMP}.blob.bad -cat ${TMP}.blob | ${REPLACE} 0x1c 0x31 > ${TMP}.blob.bad -if ${FUTILITY} gbb -g ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x1c 0x30 < "${TMP}.blob" > "${TMP}.blob.bad" +"${FUTILITY}" gbb -g "${TMP}.blob.bad" +"${REPLACE}" 0x1c 0x31 < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb -g "${TMP}.blob.bad"; then false; fi # recovery_key: offset + size == end of file is okay; beyond is invalid -cat ${TMP}.blob | ${REPLACE} 0x2c 0x10 > ${TMP}.blob.bad -${FUTILITY} gbb -g ${TMP}.blob.bad -cat ${TMP}.blob | ${REPLACE} 0x2c 0x11 > ${TMP}.blob.bad -if ${FUTILITY} gbb -g ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x2c 0x10 < "${TMP}.blob" > "${TMP}.blob.bad" +"${FUTILITY}" gbb -g "${TMP}.blob.bad" +"${REPLACE}" 0x2c 0x11 < "${TMP}.blob" > "${TMP}.blob.bad" +if "${FUTILITY}" gbb -g "${TMP}.blob.bad"; then false; fi # hwid_size == 0 doesn't complain, but can't be set -cat ${TMP}.blob | ${REPLACE} 0x14 0x00 > ${TMP}.blob.bad -${FUTILITY} gbb -g ${TMP}.blob.bad -if ${FUTILITY} gbb -s --hwid="A" ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x14 0x00 < "${TMP}.blob" > "${TMP}.blob.bad" +"${FUTILITY}" gbb -g "${TMP}.blob.bad" +if "${FUTILITY}" gbb -s --hwid="A" "${TMP}.blob.bad"; then false; fi # rootkey_size == 0 gives warning, gets nothing, can't be set -cat ${TMP}.blob | ${REPLACE} 0x1c 0x00 > ${TMP}.blob.bad -${FUTILITY} gbb -g --rootkey ${TMP}.read1 ${TMP}.blob.bad -if ${FUTILITY} gbb -s --rootkey ${TMP}.data1 ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x1c 0x00 < "${TMP}.blob" > "${TMP}.blob.bad" +"${FUTILITY}" gbb -g --rootkey "${TMP}.read1" "${TMP}.blob.bad" +if "${FUTILITY}" gbb -s --rootkey "${TMP}.data1" "${TMP}.blob.bad"; + then false; fi # recovery_key_size == 0 gives warning, gets nothing, can't be set -cat ${TMP}.blob | ${REPLACE} 0x2c 0x00 > ${TMP}.blob.bad -${FUTILITY} gbb -g --recoverykey ${TMP}.read2 ${TMP}.blob.bad -if ${FUTILITY} gbb -s --recoverykey ${TMP}.data2 ${TMP}.blob.bad; then false; fi +"${REPLACE}" 0x2c 0x00 < "${TMP}.blob" > "${TMP}.blob.bad" +"${FUTILITY}" gbb -g --recoverykey "${TMP}.read2" "${TMP}.blob.bad" +if "${FUTILITY}" gbb -s --recoverykey "${TMP}.data2" "${TMP}.blob.bad"; + then false; fi # GBB v1.2 adds a sha256 digest field in what was previously padding: @@ -189,21 +194,21 @@ # See that the digest is updated properly. hwid="123456789ABCDEF" -${FUTILITY} gbb -s --hwid=${hwid} ${TMP}.blob +"${FUTILITY}" gbb -s --hwid="${hwid}" "${TMP}.blob" expect=$(echo -n "$hwid" | sha256sum | cut -d ' ' -f 1) -[ $(echo -n ${expect} | wc -c) == "64" ] -${FUTILITY} gbb -g --digest ${TMP}.blob | grep ${expect} +[ "$(echo -n "${expect}" | wc -c)" == "64" ] +"${FUTILITY}" gbb -g --digest "${TMP}.blob" | grep "${expect}" # Garble the digest, see that it's noticed. # (assuming these zeros aren't present) -cat ${TMP}.blob | ${REPLACE} 0x33 0x00 0x00 0x00 0x00 0x00 > ${TMP}.blob.bad -${FUTILITY} gbb -g --digest ${TMP}.blob.bad | grep '0000000000' -${FUTILITY} gbb -g --digest ${TMP}.blob.bad | grep 'invalid' +"${REPLACE}" 0x33 0x00 0x00 0x00 0x00 0x00 < "${TMP}.blob" > "${TMP}.blob.bad" +"${FUTILITY}" gbb -g --digest "${TMP}.blob.bad" | grep '0000000000' +"${FUTILITY}" gbb -g --digest "${TMP}.blob.bad" | grep 'invalid' # Garble the HWID. The digest is unchanged, but now invalid. -cat ${TMP}.blob | ${REPLACE} 0x84 0x70 0x71 0x72 > ${TMP}.blob.bad -${FUTILITY} gbb -g --digest ${TMP}.blob.bad | grep 'invalid' +"${REPLACE}" 0x84 0x70 0x71 0x72 < "${TMP}.blob" > "${TMP}.blob.bad" +"${FUTILITY}" gbb -g --digest "${TMP}.blob.bad" | grep 'invalid' # cleanup -rm -f ${TMP}* +rm -f "${TMP}"* exit 0
diff --git a/tests/futility/test_load_fmap.sh b/tests/futility/test_load_fmap.sh index a93b71f..7821243 100755 --- a/tests/futility/test_load_fmap.sh +++ b/tests/futility/test_load_fmap.sh
@@ -10,34 +10,34 @@ cd "$OUTDIR" -IN=${SCRIPT_DIR}/futility/data/bios_link_mp.bin -BIOS=${TMP}.bios.bin +IN="${SCRIPT_DIR}/futility/data/bios_link_mp.bin" +BIOS="${TMP}.bios.bin" -cp ${IN} ${BIOS} +cp "${IN}" "${BIOS}" -AREAS="RW_SECTION_A VBLOCK_B BOOT_STUB" - +AREAS=(RW_SECTION_A VBLOCK_B BOOT_STUB) +set -x # Extract good blobs first -${FUTILITY} dump_fmap -x ${BIOS} ${AREAS} +"${FUTILITY}" dump_fmap -x "${BIOS}" "${AREAS[@]}" # Save the good blobs, make same-size random blobs, create command -CMDS="" -for a in ${AREAS}; do - size=$(stat -c '%s' $a) - mv $a $a.good - dd if=/dev/urandom of=$a.rand bs=$size count=1 - CMDS="$CMDS $a:$a.rand" +CMDS=( ) +for a in "${AREAS[@]}"; do + size=$(stat -c '%s' "$a") + mv "$a" "$a.good" + dd if=/dev/urandom of="$a.rand" bs="$size" count=1 + CMDS+=("$a:$a.rand") done # Poke the new blobs in -${FUTILITY} load_fmap ${BIOS} ${CMDS} +"${FUTILITY}" load_fmap "${BIOS}" "${CMDS[@]}" # Pull them back out and see if they match -${FUTILITY} dump_fmap -x ${BIOS} ${AREAS} -for a in ${AREAS}; do - cmp $a $a.rand +"${FUTILITY}" dump_fmap -x "${BIOS}" "${AREAS[@]}" +for a in "${AREAS[@]}"; do + cmp "$a" "$a.rand" done # cleanup -rm -f ${TMP}* ${AREAS} *.rand *.good +rm -f "${TMP}"* "${AREAS[@]}" ./*.rand ./*.good exit 0
diff --git a/tests/futility/test_main.sh b/tests/futility/test_main.sh index 2e5f4dc..725abe3 100755 --- a/tests/futility/test_main.sh +++ b/tests/futility/test_main.sh
@@ -10,55 +10,57 @@ cd "$OUTDIR" # No args returns nonzero exit code -${FUTILITY} && false +"${FUTILITY}" && false # It's weird but okay if the command is a full path. -${FUTILITY} /fake/path/to/help > "$TMP" +"${FUTILITY}" /fake/path/to/help > "$TMP" grep Usage "$TMP" # Make sure logging does something. LOG="/tmp/futility.log" -[ -f ${LOG} ] && mv ${LOG} ${LOG}.backup -touch ${LOG} -${FUTILITY} help -grep ${FUTILITY} ${LOG} -rm -f ${LOG} -[ -f ${LOG}.backup ] && mv ${LOG}.backup ${LOG} +[ -f "${LOG}" ] && mv "${LOG}" "${LOG}.backup" +touch "${LOG}" +"${FUTILITY}" help +grep "${FUTILITY}" "${LOG}" +rm -f "${LOG}" +[ -f "${LOG}.backup" ] && mv "${LOG}.backup" "${LOG}" # Use some known digests to verify that things work... -DEVKEYS=${SRCDIR}/tests/devkeys +DEVKEYS="${SRCDIR}/tests/devkeys" SHA=e78ce746a037837155388a1096212ded04fb86eb # all progs in the pipelines should work set -o pipefail # If it's invoked as the name of a command we know, it should do that command -ln -sf ${FUTILITY} vbutil_key -./vbutil_key --unpack ${DEVKEYS}/installer_kernel_data_key.vbpubk | grep ${SHA} -ln -sf ${FUTILITY} vbutil_keyblock -./vbutil_keyblock --unpack ${DEVKEYS}/installer_kernel.keyblock | grep ${SHA} -cp ${FUTILITY} show -./show ${SCRIPT_DIR}/futility/data/rec_kernel_part.bin | grep ${SHA} +ln -sf "${FUTILITY}" vbutil_key +./vbutil_key --unpack "${DEVKEYS}/installer_kernel_data_key.vbpubk" | \ + grep "${SHA}" +ln -sf "${FUTILITY}" vbutil_keyblock +./vbutil_keyblock --unpack "${DEVKEYS}/installer_kernel.keyblock" | \ + grep "${SHA}" +cp "${FUTILITY}" show +./show "${SCRIPT_DIR}/futility/data/rec_kernel_part.bin" | grep "${SHA}" # If it's invoked by any other name, expect the command to be the first arg. -ln -sf ${FUTILITY} muggle -./muggle vbutil_key --unpack ${DEVKEYS}/installer_kernel_data_key.vbpubk \ - | grep ${SHA} -ln -sf ${FUTILITY} buggle -./buggle vbutil_keyblock --unpack ${DEVKEYS}/installer_kernel.keyblock \ - | grep ${SHA} -cp ${FUTILITY} boo -./boo show ${SCRIPT_DIR}/futility/data/rec_kernel_part.bin | grep ${SHA} +ln -sf "${FUTILITY}" muggle +./muggle vbutil_key --unpack "${DEVKEYS}/installer_kernel_data_key.vbpubk" \ + | grep "${SHA}" +ln -sf "${FUTILITY}" buggle +./buggle vbutil_keyblock --unpack "${DEVKEYS}/installer_kernel.keyblock" \ + | grep "${SHA}" +cp "${FUTILITY}" boo +./boo show "${SCRIPT_DIR}/futility/data/rec_kernel_part.bin" | grep "${SHA}" # we expect the first command fail, but the output to match anyway set +o pipefail # If it can't figure out the command at all, it should complain. -${FUTILITY} muggle | grep Usage: +"${FUTILITY}" muggle | grep Usage: ./buggle futility | grep Usage: ./boo | grep Usage: # cleanup -rm -f ${TMP}* vbutil_key vbutil_keyblock show muggle buggle boo +rm -f "${TMP}"* vbutil_key vbutil_keyblock show muggle buggle boo exit 0
diff --git a/tests/futility/test_not_really.c b/tests/futility/test_not_really.c index 3cfc3ed..9bffb1a 100644 --- a/tests/futility/test_not_really.c +++ b/tests/futility/test_not_really.c
@@ -6,7 +6,7 @@ #include <stdio.h> #include "2struct.h" -#include "test_common.h" +#include "common/tests.h" int main(int argc, char *argv[]) {
diff --git a/tests/futility/test_rwsig.sh b/tests/futility/test_rwsig.sh index 2bd70ce..3a0a6e3 100755 --- a/tests/futility/test_rwsig.sh +++ b/tests/futility/test_rwsig.sh
@@ -10,7 +10,7 @@ cd "$OUTDIR" DATADIR="${SCRIPT_DIR}/futility/data" -TESTKEYS=${SRCDIR}/tests/testkeys +TESTKEYS="${SRCDIR}/tests/testkeys" SIGS="1024 2048 2048_exp3 3072_exp3 4096 8192" HASHES="SHA1 SHA256 SHA512" @@ -18,13 +18,13 @@ set -o pipefail -infile=${DATADIR}/hammer_dev.bin -outfile=${TMP}.hammer_dev.bin -cp ${infile} ${outfile} +infile="${DATADIR}/hammer_dev.bin" +outfile="${TMP}.hammer_dev.bin" +cp "${infile}" "${outfile}" # Signing without private key should extract EC_RW.bin -${FUTILITY} sign --type rwsig --version 2 ${outfile} -cmp ${infile} ${outfile} -cmp ${EC_RW} ${DATADIR}/${EC_RW} +"${FUTILITY}" sign --type rwsig --version 2 "${outfile}" +cmp "${infile}" "${outfile}" +cmp "${EC_RW}" "${DATADIR}/${EC_RW}" for s in $SIGS; do echo -n "$s " 1>&3 @@ -34,31 +34,32 @@ outkeys=${TMP}.${s}_${h} outfile=${TMP}.${s}_${h}.bin - ${FUTILITY} create --desc "Test key" --hash_alg ${h} \ - ${pemfile} ${outkeys} + "${FUTILITY}" create --desc "Test key" --hash_alg "${h}" \ + "${pemfile}" "${outkeys}" # The input file should be correctly signed to start with - ${FUTILITY} show --type rwsig ${infile} + "${FUTILITY}" show --type rwsig "${infile}" # Using the wrong key to verify it should fail - if ${FUTILITY} show --type rwsig --pubkey ${outkeys}.vbpubk2 \ - ${infile}; then + if "${FUTILITY}" show --type rwsig --pubkey "${outkeys}.vbpubk2" \ + "${infile}"; then exit 1 fi - cp ${infile} ${outfile} + cp "${infile}" "${outfile}" # Sign ec.bin with a new private key - ${FUTILITY} sign --type rwsig --prikey ${outkeys}.vbprik2 \ - --version 2 ${outfile} + "${FUTILITY}" sign --type rwsig --prikey "${outkeys}.vbprik2" \ + --version 2 "${outfile}" # Check EC_RW.bin is produced - [[ -e ${EC_RW} ]] + [[ -e "${EC_RW}" ]] - ${FUTILITY} show --type rwsig --pubkey ${outkeys}.vbpubk2 ${outfile} - ${FUTILITY} show --type rwsig ${outfile} + "${FUTILITY}" show --type rwsig --pubkey "${outkeys}.vbpubk2" \ + "${outfile}" + "${FUTILITY}" show --type rwsig "${outfile}" done done # cleanup -rm -rf ${TMP}* +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_show_contents.sh b/tests/futility/test_show_contents.sh index e040362..9b3431d 100755 --- a/tests/futility/test_show_contents.sh +++ b/tests/futility/test_show_contents.sh
@@ -16,8 +16,7 @@ tests/devkeys/kernel.keyblock tests/futility/data/fw_vblock.bin tests/futility/data/fw_gbb.bin - tests/futility/data/bios_zgb_mp.bin - tests/futility/data/bios_mario_mp.bin + tests/futility/data/bios_peppy_mp.bin tests/futility/data/kern_preamble.bin tests/futility/data/sample.vbpubk2 tests/futility/data/sample.vbprik2 @@ -29,7 +28,7 @@ outfile="show.${file//\//_}" gotfile="${OUTDIR}/${outfile}" wantfile="${SRCDIR}/tests/futility/expect_output/${outfile}" - ( cd "${SRCDIR}" && ${FUTILITY} show "${file}" ) | tee "${gotfile}" + ( cd "${SRCDIR}" && "${FUTILITY}" show "${file}" ) | tee "${gotfile}" # Uncomment this to update the expected output #cp "${gotfile}" "${wantfile}" @@ -48,7 +47,7 @@ outfile="vbutil_key.${file//\//_}" gotfile="${OUTDIR}/${outfile}" wantfile="${SRCDIR}/tests/futility/expect_output/${outfile}" - ( cd "${SRCDIR}" && ${FUTILITY} vbutil_key --unpack "${file}" ) \ + ( cd "${SRCDIR}" && "${FUTILITY}" vbutil_key --unpack "${file}" ) \ | tee "${gotfile}" # Uncomment this to update the expected output @@ -63,7 +62,7 @@ outfile="vbutil_keyblock.${file//\//_}" gotfile="${OUTDIR}/${outfile}" wantfile="${SRCDIR}/tests/futility/expect_output/${outfile}" -( cd "${SRCDIR}" && ${FUTILITY} vbutil_keyblock --unpack "${file}" \ +( cd "${SRCDIR}" && "${FUTILITY}" vbutil_keyblock --unpack "${file}" \ --signpubkey "tests/devkeys/kernel_subkey.vbpubk" ) \ | tee "${gotfile}" @@ -83,7 +82,7 @@ # arbitrary non-zero numbers so we can verify they're printed # properly. dd bs=1024 count=16 if=/dev/urandom of="${TMP}.fw_main" -${FUTILITY} vbutil_firmware --vblock "${TMP}.vblock.old" \ +"${FUTILITY}" vbutil_firmware --vblock "${TMP}.vblock.old" \ --keyblock "${KEYDIR}/firmware.keyblock" \ --signprivate "${KEYDIR}/firmware_data_key.vbprivk" \ --version 12 \ @@ -92,7 +91,7 @@ --flags 42 # Verify -${FUTILITY} vbutil_firmware --verify "${TMP}.vblock.old" \ +"${FUTILITY}" vbutil_firmware --verify "${TMP}.vblock.old" \ --signpubkey "${KEYDIR}/root_key.vbpubk" \ --fv "${TMP}.fw_main" | tee "${gotfile}" @@ -103,5 +102,5 @@ # cleanup -rm -rf "${TMP}*" +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_show_kernel.sh b/tests/futility/test_show_kernel.sh index 151cf46..f2610a3 100755 --- a/tests/futility/test_show_kernel.sh +++ b/tests/futility/test_show_kernel.sh
@@ -9,52 +9,52 @@ # Work in scratch directory cd "$OUTDIR" -DEVKEYS=${SRCDIR}/tests/devkeys -TESTKEYS=${SRCDIR}/tests/testkeys +DEVKEYS="${SRCDIR}/tests/devkeys" +TESTKEYS="${SRCDIR}/tests/testkeys" echo 'Creating test kernel' # Dummy kernel data -echo "hi there" > ${TMP}.config.txt -dd if=/dev/urandom bs=16384 count=1 of=${TMP}.bootloader.bin -dd if=/dev/urandom bs=32768 count=1 of=${TMP}.kernel.bin +echo "hi there" > "${TMP}.config.txt" +dd if=/dev/urandom bs=16384 count=1 of="${TMP}.bootloader.bin" +dd if=/dev/urandom bs=32768 count=1 of="${TMP}.kernel.bin" # Pack kernel data key using original vboot utilities. -${FUTILITY} vbutil_key --pack ${TMP}.datakey.test \ - --key ${TESTKEYS}/key_rsa2048.keyb --algorithm 4 +"${FUTILITY}" vbutil_key --pack "${TMP}.datakey.test" \ + --key "${TESTKEYS}/key_rsa2048.keyb" --algorithm 4 # Keyblock with kernel data key is signed by kernel subkey # Flags=5 means dev=0 rec=0 -${FUTILITY} vbutil_keyblock --pack ${TMP}.keyblock.test \ - --datapubkey ${TMP}.datakey.test \ +"${FUTILITY}" vbutil_keyblock --pack "${TMP}.keyblock.test" \ + --datapubkey "${TMP}.datakey.test" \ --flags 5 \ - --signprivate ${DEVKEYS}/kernel_subkey.vbprivk + --signprivate "${DEVKEYS}/kernel_subkey.vbprivk" # Kernel preamble is signed with the kernel data key -${FUTILITY} vbutil_kernel \ - --pack ${TMP}.kernel.test \ - --keyblock ${TMP}.keyblock.test \ - --signprivate ${TESTKEYS}/key_rsa2048.sha256.vbprivk \ +"${FUTILITY}" vbutil_kernel \ + --pack "${TMP}.kernel.test" \ + --keyblock "${TMP}.keyblock.test" \ + --signprivate "${TESTKEYS}/key_rsa2048.sha256.vbprivk" \ --version 1 \ --arch arm \ - --vmlinuz ${TMP}.kernel.bin \ - --bootloader ${TMP}.bootloader.bin \ - --config ${TMP}.config.txt + --vmlinuz "${TMP}.kernel.bin" \ + --bootloader "${TMP}.bootloader.bin" \ + --config "${TMP}.config.txt" echo 'Verifying test kernel' # Verify the kernel -${FUTILITY} show ${TMP}.kernel.test \ - --publickey ${DEVKEYS}/kernel_subkey.vbpubk \ - | egrep 'Signature.*valid' +"${FUTILITY}" show "${TMP}.kernel.test" \ + --publickey "${DEVKEYS}/kernel_subkey.vbpubk" \ + | grep -E 'Signature.*valid' echo 'Test kernel blob looks good' # Mess up the padding, make sure it fails. rc=0 -${FUTILITY} show ${TMP}.kernel.test \ +"${FUTILITY}" show "${TMP}.kernel.test" \ --pad 0x100 \ - --publickey ${DEVKEYS}/kernel_subkey.vbpubk \ + --publickey "${DEVKEYS}/kernel_subkey.vbpubk" \ || rc=$? [ $rc -ne 0 ] [ $rc -lt 128 ] @@ -63,9 +63,9 @@ # Look waaaaaay off the end of the file, make sure it fails. rc=0 -${FUTILITY} show ${TMP}.kernel.test \ +"${FUTILITY}" show "${TMP}.kernel.test" \ --pad 0x100000 \ - --publickey ${DEVKEYS}/kernel_subkey.vbpubk \ + --publickey "${DEVKEYS}/kernel_subkey.vbpubk" \ || rc=$? [ $rc -ne 0 ] [ $rc -lt 128 ] @@ -73,5 +73,5 @@ echo 'Really invalid args are still invalid' # cleanup -rm -rf ${TMP}* +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_show_usbpd1.sh b/tests/futility/test_show_usbpd1.sh index b5553aa..3998fa7 100755 --- a/tests/futility/test_show_usbpd1.sh +++ b/tests/futility/test_show_usbpd1.sh
@@ -24,23 +24,24 @@ for test in $TESTS; do - infile=${DATADIR}/${test}.unsigned + infile="${DATADIR}/${test}.unsigned" for h in $HASHES; do - pemfile=${TESTKEYS}/key_rsa${s}.pem - outfile=${TMP}.${test}_${s}_${h}.new + pemfile="${TESTKEYS}/key_rsa${s}.pem" + outfile="${TMP}.${test}_${s}_${h}.new" # sign it - ${FUTILITY} sign --type usbpd1 --pem ${pemfile} ${infile} ${outfile} + "${FUTILITY}" sign --type usbpd1 --pem "${pemfile}" "${infile}" \ + "${outfile}" # make sure it identifies correctly - ${FUTILITY} verify ${outfile} + "${FUTILITY}" verify "${outfile}" done done done # cleanup -rm -rf ${TMP}* +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_show_vs_verify.sh b/tests/futility/test_show_vs_verify.sh index 4981a38..c0c0872 100755 --- a/tests/futility/test_show_vs_verify.sh +++ b/tests/futility/test_show_vs_verify.sh
@@ -10,67 +10,67 @@ cd "$OUTDIR" # some stuff we'll need -DEVKEYS=${SRCDIR}/tests/devkeys +DEVKEYS="${SRCDIR}/tests/devkeys" # The show command exits with 0 if the data is consistent. # The verify command exits with 0 only if all the data is verified. #### keyblock -${FUTILITY} show ${DEVKEYS}/firmware.keyblock +"${FUTILITY}" show "${DEVKEYS}/firmware.keyblock" -if ${FUTILITY} verify ${DEVKEYS}/firmware.keyblock ; then false; fi +if "${FUTILITY}" verify "${DEVKEYS}/firmware.keyblock" ; then false; fi -${FUTILITY} verify ${DEVKEYS}/firmware.keyblock \ - --publickey ${DEVKEYS}/root_key.vbpubk +"${FUTILITY}" verify "${DEVKEYS}/firmware.keyblock" \ + --publickey "${DEVKEYS}/root_key.vbpubk" #### firmware vblock # Get some bits to look at -${FUTILITY} dump_fmap -x ${SCRIPT_DIR}/futility/data/bios_peppy_mp.bin \ - GBB:${TMP}.gbb VBLOCK_A:${TMP}.vblock_a FW_MAIN_A:${TMP}.fw_main_a -${FUTILITY} gbb -g -k ${TMP}.rootkey ${TMP}.gbb +"${FUTILITY}" dump_fmap -x "${SCRIPT_DIR}/futility/data/bios_peppy_mp.bin" \ + "GBB:${TMP}.gbb" "VBLOCK_A:${TMP}.vblock_a" "FW_MAIN_A:${TMP}.fw_main_a" +"${FUTILITY}" gbb -g -k "${TMP}.rootkey" "${TMP}.gbb" -${FUTILITY} show ${TMP}.vblock_a +"${FUTILITY}" show "${TMP}.vblock_a" -${FUTILITY} show ${TMP}.vblock_a --publickey ${TMP}.rootkey +"${FUTILITY}" show "${TMP}.vblock_a" --publickey "${TMP}.rootkey" -${FUTILITY} show ${TMP}.vblock_a \ - --publickey ${TMP}.rootkey \ - --fv ${TMP}.fw_main_a +"${FUTILITY}" show "${TMP}.vblock_a" \ + --publickey "${TMP}.rootkey" \ + --fv "${TMP}.fw_main_a" -if ${FUTILITY} verify ${TMP}.vblock_a ; then false ; fi +if "${FUTILITY}" verify "${TMP}.vblock_a" ; then false ; fi -if ${FUTILITY} verify ${TMP}.vblock_a \ - --publickey ${TMP}.rootkey ; then false ; fi +if "${FUTILITY}" verify "${TMP}.vblock_a" \ + --publickey "${TMP}.rootkey" ; then false ; fi -${FUTILITY} verify ${TMP}.vblock_a \ - --publickey ${TMP}.rootkey \ - --fv ${TMP}.fw_main_a +"${FUTILITY}" verify "${TMP}.vblock_a" \ + --publickey "${TMP}.rootkey" \ + --fv "${TMP}.fw_main_a" #### kernel partition -${FUTILITY} show ${SCRIPT_DIR}/futility/data/rec_kernel_part.bin +"${FUTILITY}" show "${SCRIPT_DIR}/futility/data/rec_kernel_part.bin" -${FUTILITY} show ${SCRIPT_DIR}/futility/data/rec_kernel_part.bin \ - --publickey ${DEVKEYS}/kernel_subkey.vbpubk +"${FUTILITY}" show "${SCRIPT_DIR}/futility/data/rec_kernel_part.bin" \ + --publickey "${DEVKEYS}/kernel_subkey.vbpubk" -${FUTILITY} show ${SCRIPT_DIR}/futility/data/rec_kernel_part.bin \ - --publickey ${DEVKEYS}/recovery_key.vbpubk +"${FUTILITY}" show "${SCRIPT_DIR}/futility/data/rec_kernel_part.bin" \ + --publickey "${DEVKEYS}/recovery_key.vbpubk" -if ${FUTILITY} verify ${SCRIPT_DIR}/futility/data/rec_kernel_part.bin ; \ +if "${FUTILITY}" verify "${SCRIPT_DIR}/futility/data/rec_kernel_part.bin" ; \ then false ; fi -if ${FUTILITY} verify ${SCRIPT_DIR}/futility/data/rec_kernel_part.bin \ - --publickey ${DEVKEYS}/kernel_subkey.vbpubk ; then false ; fi +if "${FUTILITY}" verify "${SCRIPT_DIR}/futility/data/rec_kernel_part.bin" \ + --publickey "${DEVKEYS}/kernel_subkey.vbpubk" ; then false ; fi -${FUTILITY} verify ${SCRIPT_DIR}/futility/data/rec_kernel_part.bin \ - --publickey ${DEVKEYS}/recovery_key.vbpubk +"${FUTILITY}" verify "${SCRIPT_DIR}/futility/data/rec_kernel_part.bin" \ + --publickey "${DEVKEYS}/recovery_key.vbpubk" # cleanup -rm -rf ${TMP}* +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_sign_firmware.sh b/tests/futility/test_sign_firmware.sh index fa5529c..fe8462c 100755 --- a/tests/futility/test_sign_firmware.sh +++ b/tests/futility/test_sign_firmware.sh
@@ -3,44 +3,98 @@ # 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" +me="${0##*/}" +TMP="${me}.tmp" # Work in scratch directory cd "$OUTDIR" -KEYDIR=${SRCDIR}/tests/devkeys +KEYDIR="${SRCDIR}/tests/devkeys" +DATADIR="${SCRIPT_DIR}/futility/data" # The input BIOS images are all signed with MP keys. We resign them with dev # keys, which means we can precalculate the expected results. Note that the # script does not change the root or recovery keys in the GBB. INFILES=" -${SCRIPT_DIR}/futility/data/bios_link_mp.bin -${SCRIPT_DIR}/futility/data/bios_mario_mp.bin -${SCRIPT_DIR}/futility/data/bios_peppy_mp.bin +${DATADIR}/bios_link_mp.bin +${DATADIR}/bios_peppy_mp.bin +" + +# BIOS image containing CBFS RW/A and RW/B, and signed with developer keys. +GOOD_CBFS="${DATADIR}/bios_voxel_dev.bin" + +# BIOS image containing CBFS RW/A and RW/B, and signed with developer keys. +INFILES="${INFILES} +${GOOD_CBFS} " # We also want to test that we can sign an image without any valid firmware # preambles. That one won't be able to tell how much of the FW_MAIN region is # the valid firmware, so it'll have to sign the entire region. -GOOD_VBLOCKS=${SCRIPT_DIR}/futility/data/bios_peppy_mp.bin +GOOD_VBLOCKS="${DATADIR}/bios_peppy_mp.bin" ONEMORE=bios_peppy_mp_no_vblock.bin -cp ${GOOD_VBLOCKS} ${ONEMORE} -${FUTILITY} load_fmap ${ONEMORE} VBLOCK_A:/dev/urandom VBLOCK_B:/dev/zero +CLEAN_B=bios_peppy_mp_clean_b_slot.bin +cp "${GOOD_VBLOCKS}" "${ONEMORE}" +cp "${GOOD_VBLOCKS}" "${CLEAN_B}" + +GOOD_DEV="${DATADIR}/bios_peppy_dev.bin" + +NO_B_SLOT_PATCH="${DATADIR}/bios_voxel_dev.no_b_slot.xxd.patch" + +BAD_KEYBLOCK_PATCHES=( +"${DATADIR}/bios_peppy_dev.bad_keyblock_data_key_offset_too_big.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_keyblock_data_key_size_big.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_keyblock_hash_data_size_too_small.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_keyblock_hash_invalid_contents.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_keyblock_hash_offset_too_big.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_keyblock_hash_size_too_big.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_keyblock_invalid_magic.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_keyblock_invalid_major_version.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_keyblock_size_not_fully_signed.xxd.patch" +) + +BAD_PREAMBLE_PATCHES=( +"${DATADIR}/bios_peppy_dev.bad_preamble_body_signature_offset_too_big.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_body_signature_size_too_big.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_header_version_major.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_header_version_minor.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_kernel_subkey_offset_too_big.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_kernel_subkey_size_too_big.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_signature_data_size_too_big.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_signature_data_size_too_small.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_signature_invalid_contents.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_signature_offset_too_big.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_signature_size_too_big.xxd.patch" +) + +BAD_FMAP_KEYBLOCK_PATCHES=( +"${DATADIR}/bios_peppy_dev.bad_keyblock_fmap_too_small_for_whole.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_keyblock_fmap_too_small.xxd.patch" +) + +BAD_FMAP_PREAMBLE_PATCHES=( +"${DATADIR}/bios_peppy_dev.bad_preamble_fmap_too_small_for_whole.xxd.patch" +"${DATADIR}/bios_peppy_dev.bad_preamble_fmap_too_small.xxd.patch" +) + +"${FUTILITY}" load_fmap "${ONEMORE}" VBLOCK_A:/dev/urandom VBLOCK_B:/dev/zero INFILES="${INFILES} ${ONEMORE}" -set -o pipefail +# args: xxd_patch_file input_file +function apply_xxd_patch { + xxd -r "${1}" "${2}" +} -# We've removed dev_firmware keyblock and private keys from ToT test key dir. -# It's currently only available on few legacy (alex, zgb) devices' key folders -# on signer bot. Add them to ${KEYDIR} if you need to test that. -DEV_FIRMWARE_PARAMS="" -if [ -f "${KEYDIR}/dev_firmware.keyblock" ]; then - DEV_FIRMWARE_PARAMS=" - -S ${KEYDIR}/dev_firmware_data_key.vbprivk - -B ${KEYDIR}/dev_firmware.keyblock" - INFILES="${INFILES} ${SCRIPT_DIR}/futility/data/bios_zgb_mp.bin" -fi +# args: file1 file2 +function cmp_first_line { + cmp <(head -n1 "${1}") <(head -n1 "${2}") +} + +function cmp_last_line { + cmp <(tail -n1 "${1}") <(tail -n1 "${2}") +} + +set -o pipefail count=0 for infile in $INFILES; do @@ -48,140 +102,391 @@ base=${infile##*/} : $(( count++ )) - echo -n "$count " 1>&3 + echo -n "${count} " 1>&3 - outfile=${TMP}.${base}.new + outfile="${TMP}.${base}.new" loemid="loem" - loemdir=${TMP}.${base}_dir + loemdir="${TMP}.${base}_dir" - mkdir -p ${loemdir} + mkdir -p "${loemdir}" - # resign_firmwarefd.sh works on BIOS image files. The args are: - # - # infile - # outfile - # firmware_datakey - # firmware_keyblock - # dev_firmware_datakey (these are only used if RW A & RW B differ) - # dev_firmware_keyblock - # kernel_subkey - # firmware_version - # preamble_flag - # loem_output_dir (optional: dir for copy of new vblocks) - # loemid (optional: copy new vblocks using this name) - # - #OLD ${BIN_DIR}/resign_firmwarefd.sh \ - #OLD ${infile} \ - #OLD ${outfile} \ - #OLD ${KEYDIR}/firmware_data_key.vbprivk \ - #OLD ${KEYDIR}/firmware.keyblock \ - #OLD ${KEYDIR}/dev_firmware_data_key.vbprivk \ - #OLD ${KEYDIR}/dev_firmware.keyblock \ - #OLD ${KEYDIR}/kernel_subkey.vbpubk \ - #OLD 14 \ - #OLD 8 \ - #OLD ${loemdir} \ - #OLD ${loemid} - - ${FUTILITY} sign \ - -s ${KEYDIR}/firmware_data_key.vbprivk \ - -b ${KEYDIR}/firmware.keyblock \ - ${DEV_FIRMWARE_PARAMS} \ - -k ${KEYDIR}/kernel_subkey.vbpubk \ + "${FUTILITY}" sign \ + -K "${KEYDIR}" \ -v 14 \ -f 8 \ - -d ${loemdir} \ - -l ${loemid} \ - ${infile} ${outfile} + -d "${loemdir}" \ + -l "${loemid}" \ + "${infile}" "${outfile}" # check the firmware version and preamble flags - m=$(${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${outfile} \ - | egrep 'Firmware version: +14$|Preamble flags: +8$' | wc -l) - [ "$m" = "4" ] + m=$("${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \ + "${outfile}" | grep -c -E 'Firmware version: +14$|Preamble flags: +8$') + [ "${m}" = "4" ] # check the sha1sums - ${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${outfile} \ + "${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" "${outfile}" \ | grep sha1sum \ - | sed -e 's/.*: \+//' > ${TMP}.${base}.sha.new - cmp ${SCRIPT_DIR}/futility/data_${base}_expect.txt ${TMP}.${base}.sha.new + | sed -e 's/.*: \+//' > "${TMP}.${base}.sha.new" + cmp "${SCRIPT_DIR}/futility/data_${base}_expect.txt" "${TMP}.${base}.sha.new" # and the LOEM stuff - ${FUTILITY} dump_fmap -x ${outfile} \ - FW_MAIN_A:${loemdir}/fw_main_A FW_MAIN_B:${loemdir}/fw_main_B \ - "Firmware A Data":${loemdir}/fw_main_A \ - "Firmware B Data":${loemdir}/fw_main_B + "${FUTILITY}" dump_fmap -x "${outfile}" \ + "FW_MAIN_A:${loemdir}/fw_main_A" "FW_MAIN_B:${loemdir}/fw_main_B" - - ${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk \ - --fv ${loemdir}/fw_main_A \ - ${loemdir}/vblock_A.${loemid} | grep sha1sum \ - | sed -e 's/.*: \+//' > ${loemdir}/loem.sha.new - ${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk \ - --fv ${loemdir}/fw_main_B \ - ${loemdir}/vblock_B.${loemid} | grep sha1sum \ - | sed -e 's/.*: \+//' >> ${loemdir}/loem.sha.new + "${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \ + --fv "${loemdir}/fw_main_A" \ + "${loemdir}/vblock_A.${loemid}" | grep sha1sum \ + | sed -e 's/.*: \+//' > "${loemdir}/loem.sha.new" + "${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \ + --fv "${loemdir}/fw_main_B" \ + "${loemdir}/vblock_B.${loemid}" | grep sha1sum \ + | sed -e 's/.*: \+//' >> "${loemdir}/loem.sha.new" # the vblocks don't have root or recovery keys - tail -4 ${SCRIPT_DIR}/futility/data_${base}_expect.txt > ${loemdir}/sha.expect - cmp ${loemdir}/sha.expect ${loemdir}/loem.sha.new + tail -4 "${SCRIPT_DIR}/futility/data_${base}_expect.txt" \ + > "${loemdir}/sha.expect" + cmp "${loemdir}/sha.expect" "${loemdir}/loem.sha.new" done # Make sure that the BIOS with the good vblocks signed the right size. -GOOD_OUT=${TMP}.${GOOD_VBLOCKS##*/}.new -MORE_OUT=${TMP}.${ONEMORE##*/}.new +GOOD_OUT="${TMP}.${GOOD_VBLOCKS##*/}.new" +MORE_OUT="${TMP}.${ONEMORE##*/}.new" +GOOD_CBFS_OUT="${TMP}.${GOOD_CBFS##*/}.new" -${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${GOOD_OUT} \ - | awk '/Firmware body size:/ {print $4}' > ${TMP}.good.body -${FUTILITY} dump_fmap -p ${GOOD_OUT} \ - | awk '/FW_MAIN_/ {print $3}' > ${TMP}.good.fw_main +"${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" "${GOOD_OUT}" \ + | awk '/Firmware body size:/ {print $4}' > "${TMP}.good.body" +"${FUTILITY}" dump_fmap -p "${GOOD_OUT}" \ + | awk '/FW_MAIN_/ {print $3}' > "${TMP}.good.fw_main" # This should fail because they're different -if cmp ${TMP}.good.body ${TMP}.good.fw_main; then false; fi +if cmp "${TMP}.good.body" "${TMP}.good.fw_main"; then false; fi # Make sure that the BIOS with the bad vblocks signed the whole fw body -${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${MORE_OUT} \ - | awk '/Firmware body size:/ {print $4}' > ${TMP}.onemore.body -${FUTILITY} dump_fmap -p ${MORE_OUT} \ - | awk '/FW_MAIN_/ {print $3}' > ${TMP}.onemore.fw_main +"${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" "${MORE_OUT}" \ + | awk '/Firmware body size:/ {print $4}' > "${TMP}.onemore.body" +"${FUTILITY}" dump_fmap -p "${MORE_OUT}" \ + | awk '/FW_MAIN_/ {print $3}' > "${TMP}.onemore.fw_main" # These should match -cmp ${TMP}.onemore.body ${TMP}.onemore.fw_main -cmp ${TMP}.onemore.body ${TMP}.good.fw_main +cmp "${TMP}.onemore.body" "${TMP}.onemore.fw_main" +cmp "${TMP}.onemore.body" "${TMP}.good.fw_main" + +"${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \ + "${GOOD_CBFS_OUT}" \ + | awk '/Firmware body size:/ {print $4}' > "${TMP}.good_cbfs.body" +"${FUTILITY}" dump_fmap -p "${GOOD_CBFS_OUT}" \ + | awk '/FW_MAIN_/ {print $3}' > "${TMP}.good_cbfs.fw_main" +if cmp "${TMP}.good_cbfs.body" "${TMP}.good_cbfs.fw_main"; then false; fi -# Sign the last one again but don't specify the version or the preamble flags. -# The version should default to 1, but the preamble flags should be preserved. +# Sign CBFS image after adding new files. Size should increase but still be +# smaller than FlashMap size. : $(( count++ )) -echo -n "$count " 1>&3 +echo -n "${count} " 1>&3 -${FUTILITY} sign \ - -s ${KEYDIR}/firmware_data_key.vbprivk \ - -b ${KEYDIR}/firmware.keyblock \ - ${DEV_FIRMWARE_PARAMS} \ - -k ${KEYDIR}/kernel_subkey.vbpubk \ - ${MORE_OUT} ${MORE_OUT}.2 +cp "${GOOD_CBFS_OUT}" "${GOOD_CBFS_OUT}.1" +truncate -s 512 "${TMP}.zero_512" +cbfstool "${GOOD_CBFS_OUT}.1" expand -r FW_MAIN_A,FW_MAIN_B +cbfstool "${GOOD_CBFS_OUT}.1" add \ + -r FW_MAIN_A,FW_MAIN_B -f "${TMP}.zero_512" -n new-data-file -t raw -m=$(${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${MORE_OUT}.2 \ - | egrep 'Firmware version: +1$|Preamble flags: +8$' | wc -l) -[ "$m" = "4" ] +"${FUTILITY}" sign \ + -s "${KEYDIR}/firmware_data_key.vbprivk" \ + -K "${KEYDIR}" \ + "${GOOD_CBFS_OUT}.1" + +"${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \ + "${GOOD_CBFS_OUT}.1" \ + | awk '/Firmware body size:/ {print $4}' > "${TMP}.good_cbfs.1.body" +"${FUTILITY}" dump_fmap -p "${GOOD_CBFS_OUT}" \ + | awk '/FW_MAIN_/ {print $3}' > "${TMP}.good_cbfs.1.fw_main" + +# Check if size increased, but also if it was correctly truncated, +# so it does not span over whole FlashMap area. +[[ $(head -n1 "${TMP}.good_cbfs.body") \ + < $(head -n1 "${TMP}.good_cbfs.1.body") ]] +[[ $(tail -n1 "${TMP}.good_cbfs.body") \ + < $(tail -n1 "${TMP}.good_cbfs.1.body") ]] +[[ $(head -n1 "${TMP}.good_cbfs.1.body") \ + < $(head -n1 "${TMP}.good_cbfs.1.fw_main") ]] +[[ $(tail -n1 "${TMP}.good_cbfs.1.body") \ + < $(tail -n1 "${TMP}.good_cbfs.1.fw_main") ]] + + +# Sign image again but don't specify the version or the preamble flags. +# The firmware version and preamble flags should be preserved. +# NOTICE: Version preservation behavior changed from defaulting to 1. +: $(( count++ )) +echo -n "${count} " 1>&3 + +"${FUTILITY}" sign \ + -b "${KEYDIR}/firmware.keyblock" \ + -K "${KEYDIR}" \ + "${MORE_OUT}" "${MORE_OUT}.2" + +m=$("${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \ + "${MORE_OUT}.2" | grep -c -E 'Firmware version: +14$|Preamble flags: +8$') +[ "${m}" = "4" ] # If the original preamble is not present, the preamble flags should be zero. : $(( count++ )) -echo -n "$count " 1>&3 +echo -n "${count} " 1>&3 -${FUTILITY} load_fmap ${MORE_OUT} VBLOCK_A:/dev/urandom VBLOCK_B:/dev/zero -${FUTILITY} sign \ - -s ${KEYDIR}/firmware_data_key.vbprivk \ - -b ${KEYDIR}/firmware.keyblock \ - ${DEV_FIRMWARE_PARAMS} \ - -k ${KEYDIR}/kernel_subkey.vbpubk \ - ${MORE_OUT} ${MORE_OUT}.3 +"${FUTILITY}" load_fmap "${MORE_OUT}" VBLOCK_A:/dev/urandom VBLOCK_B:/dev/zero +"${FUTILITY}" sign \ + -k "${KEYDIR}/kernel_subkey.vbpubk" \ + -K "${KEYDIR}" \ + "${MORE_OUT}" "${MORE_OUT}.3" -m=$(${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${MORE_OUT}.3 \ - | egrep 'Firmware version: +1$|Preamble flags: +0$' | wc -l) -[ "$m" = "4" ] +m=$("${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \ + "${MORE_OUT}.3" | grep -c -E 'Firmware version: +1$|Preamble flags: +0$') +[ "${m}" = "4" ] + + +# Check signing when B slot is empty +: $(( count++ )) +echo -n "${count} " 1>&3 + +"${FUTILITY}" load_fmap "${CLEAN_B}" VBLOCK_B:/dev/zero FW_MAIN_B:/dev/zero +"${FUTILITY}" sign \ + -s "${KEYDIR}/firmware_data_key.vbprivk" \ + -b "${KEYDIR}/firmware.keyblock" \ + -K "${KEYDIR}" \ + "${CLEAN_B}" "${CLEAN_B}.1" + +"${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" "${CLEAN_B}.1" \ + | awk '/Firmware body size:/ {print $4}' > "${TMP}.clean_b.body" +"${FUTILITY}" dump_fmap -p "${CLEAN_B}.1" \ + | awk '/FW_MAIN_/ {print $3}' > "${TMP}.clean_b.fw_main" + +# These should not be equal, as FW_MAIN_A size should be kept intact, when size +# of FW_MAIN_B should be taken from FlashMap. +if cmp "${TMP}.clean_b.body" "${TMP}.clean_b.fw_main" ; then false; fi +if cmp "${TMP}.clean_b.body" "${TMP}.good.body" ; then false; fi +cmp_first_line "${TMP}.clean_b.body" "${TMP}.good.body" +cmp_last_line "${TMP}.clean_b.body" "${TMP}.clean_b.fw_main" + +# Version for slot A should be kept intact, while for B slot it should default +# to 1. All flags should be zero. +m=$("${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \ + "${CLEAN_B}.1" \ + | grep -c -E \ + 'Firmware version: +1$|Preamble flags: +0$|Firmware version: +2$') +[ "${m}" = "4" ] + +# Check signing when there is no B slot +: $(( count++ )) +echo -n "${count} " 1>&3 + +NO_B_SLOT="${TMP}.${GOOD_CBFS##*/}.no_b_slot" +NO_B_SLOT_SIGNED_IMG="${NO_B_SLOT}.signed" + +cp "${GOOD_CBFS}" "${NO_B_SLOT}" +apply_xxd_patch "${NO_B_SLOT_PATCH}" "${NO_B_SLOT}" + +"${FUTILITY}" sign \ + -s "${KEYDIR}/firmware_data_key.vbprivk" \ + -k "${KEYDIR}/kernel_subkey.vbpubk" \ + -K "${KEYDIR}" \ + -v 1 \ + "${NO_B_SLOT}" "${NO_B_SLOT_SIGNED_IMG}" + +"${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \ + "${NO_B_SLOT_SIGNED_IMG}" \ + | awk '/Firmware body size:/ {print $4}' > "${TMP}.no_b_slot.body" +"${FUTILITY}" dump_fmap -p "${NO_B_SLOT_SIGNED_IMG}" \ + | awk '/FW_MAIN_/ {print $3}' > "${TMP}.no_b_slot.fw_main" + +if cmp "${TMP}.no_b_slot.body" "${TMP}.no_b_slot.fw_main" ; then false; fi +cmp "${TMP}.no_b_slot.body" <(tail -n1 "${TMP}.good_cbfs.body") + +m=$("${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \ + "${NO_B_SLOT_SIGNED_IMG}" \ + | grep -c -E 'Firmware version: +1$|Preamble flags: +0$') +[ "${m}" = "2" ] + +# Check signing when cbfstool reports incorrect size +# Signing should fail, as it should not be possible for CBFS contents to be +# bigger than FlashMap size of the area +: $(( count++ )) +echo -n "${count} " 1>&3 + +CBFSTOOL_STUB="$(realpath "${TMP}.cbfs_stub.sh")" +echo -en 'echo "0xFFEEDD0"; exit 0;' > "${CBFSTOOL_STUB}" +chmod +x "${CBFSTOOL_STUB}" + +if CBFSTOOL="${CBFSTOOL_STUB}" "${FUTILITY}" sign \ + -b "${KEYDIR}/firmware.keyblock" \ + -k "${KEYDIR}/kernel_subkey.vbpubk" \ + -K "${KEYDIR}" \ + -v 1 \ + "${GOOD_CBFS}" "${TMP}.1.${GOOD_CBFS##*/}" +then + false +fi + +# Redefine cbfstool stub to return valid value for FW_MAIN_A and invalid for +# FW_MAIN_B size. With this behavior futility should fail to sign this image, +# as cbfstool should never return incorrect size (larger than area). +cp "${GOOD_CBFS}" "${TMP}.good_cbfs.bin" +FW_MAIN_A_SIZE="$(printf '0x%x' \ + "$(cbfstool "${TMP}.good_cbfs.bin" truncate -r FW_MAIN_A)")" +MARK_FILE="$(realpath "${TMP}.mark1")" +rm -f "${MARK_FILE}" + +cat << EOF > "${CBFSTOOL_STUB}" +#!/usr/bin/env bash +if ! [ -f "${MARK_FILE}" ]; then + echo "${FW_MAIN_A_SIZE}"; + echo 1 > "${MARK_FILE}"; +else + echo 0xFFFFAA0; +fi +exit 0; +EOF + +if CBFSTOOL="${CBFSTOOL_STUB}" "${FUTILITY}" sign \ + -K "${KEYDIR}" \ + -v 1 \ + "${GOOD_CBFS}" "${TMP}.2.${GOOD_CBFS##*/}" +then + false +fi + + +# Check various incorrect values in VBLOCK (keyblock and preamble) +: $(( count++ )) +echo -n "${count} " 1>&3 + +bad_counter=1 +for keyblock_patch in "${BAD_KEYBLOCK_PATCHES[@]}"; do + echo -n "${count}.${bad_counter} " 1>&3 + BAD_IN="${TMP}.${GOOD_DEV##*/}.bad.${bad_counter}.in.bin" + BAD_OUT="${TMP}.${GOOD_DEV##*/}.bad.${bad_counter}.out.bin" + cp "${GOOD_DEV}" "${BAD_IN}" + apply_xxd_patch "${keyblock_patch}" "${BAD_IN}" + + FUTIL_OUTPUT="$(if "${FUTILITY}" verify \ + --publickey "${KEYDIR}/root_key.vbpubk" "${BAD_IN}"; \ + then false; fi)" + grep -q 'VBLOCK_A keyblock component is invalid' <<< "${FUTIL_OUTPUT}" + + FUTIL_OUTPUT="$("${FUTILITY}" sign \ + -K "${KEYDIR}" \ + "${BAD_IN}" "${BAD_OUT}" 2>&1)" + grep -q 'VBLOCK_A keyblock is invalid' <<< "${FUTIL_OUTPUT}" + + "${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" "${BAD_OUT}" \ + | awk '/Firmware body size:/ {print $4}' > "${BAD_OUT}.body" + "${FUTILITY}" dump_fmap -p "${BAD_OUT}" \ + | awk '/FW_MAIN_/ {print $3}' > "${BAD_OUT}.fw_main" + + cmp "${BAD_OUT}.fw_main" "${TMP}.good.fw_main" + cmp_first_line "${BAD_OUT}.body" "${TMP}.good.fw_main" + cmp_last_line "${BAD_OUT}.body" "${TMP}.good.body" + + : $(( bad_counter++ )) +done + +for vblock_patch in "${BAD_PREAMBLE_PATCHES[@]}"; do + echo -n "${count}.${bad_counter} " 1>&3 + BAD_IN="${TMP}.${GOOD_DEV##*/}.bad.${bad_counter}.in.bin" + BAD_OUT="${TMP}.${GOOD_DEV##*/}.bad.${bad_counter}.out.bin" + cp "${GOOD_DEV}" "${BAD_IN}" + apply_xxd_patch "${vblock_patch}" "${BAD_IN}" + + FUTIL_OUTPUT="$(if "${FUTILITY}" verify \ + --publickey "${KEYDIR}/root_key.vbpubk" "${BAD_IN}"; \ + then false; fi)" + grep -q 'VBLOCK_A is invalid' <<< "${FUTIL_OUTPUT}" + + FUTIL_OUTPUT="$("${FUTILITY}" sign \ + -K "${KEYDIR}" \ + "${BAD_IN}" "${BAD_OUT}" 2>&1)" + grep -q 'VBLOCK_A preamble is invalid' <<< "${FUTIL_OUTPUT}" + + "${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" "${BAD_OUT}" \ + | awk '/Firmware body size:/ {print $4}' > "${BAD_OUT}.body" + "${FUTILITY}" dump_fmap -p "${BAD_OUT}" \ + | awk '/FW_MAIN_/ {print $3}' > "${BAD_OUT}.fw_main" + + cmp "${BAD_OUT}.fw_main" "${TMP}.good.fw_main" + cmp_first_line "${BAD_OUT}.body" "${TMP}.good.fw_main" + cmp_last_line "${BAD_OUT}.body" "${TMP}.good.body" + + : $(( bad_counter++ )) +done + +for vblock_patch in "${BAD_FMAP_KEYBLOCK_PATCHES[@]}"; do + echo -n "${count}.${bad_counter} " 1>&3 + BAD_IN="${TMP}.${GOOD_DEV##*/}.bad.${bad_counter}.in.bin" + BAD_OUT="${TMP}.${GOOD_DEV##*/}.bad.${bad_counter}.out.bin" + cp "${GOOD_DEV}" "${BAD_IN}" + apply_xxd_patch "${vblock_patch}" "${BAD_IN}" + + FUTIL_OUTPUT="$(if "${FUTILITY}" verify \ + --publickey "${KEYDIR}/root_key.vbpubk" "${BAD_IN}"; \ + then false; fi)" + grep -q 'VBLOCK_A keyblock component is invalid' <<< "${FUTIL_OUTPUT}" + + FUTIL_OUTPUT="$(if "${FUTILITY}" sign \ + -K "${KEYDIR}" \ + "${BAD_IN}" "${BAD_OUT}" 2>&1; \ + then false; fi)" + m="$(grep -c -E \ + 'VBLOCK_A keyblock is invalid|Keyblock and preamble do not fit in VBLOCK' \ + <<< "${FUTIL_OUTPUT}")" + [ "${m}" = "2" ] + + : $(( bad_counter++ )) +done + +echo -n "${count}.${bad_counter} " 1>&3 +BAD_IN="${TMP}.${GOOD_DEV##*/}.bad.${bad_counter}.in.bin" +BAD_OUT="${TMP}.${GOOD_DEV##*/}.bad.${bad_counter}.out.bin" +cp "${GOOD_DEV}" "${BAD_IN}" +apply_xxd_patch "${BAD_FMAP_PREAMBLE_PATCHES[0]}" "${BAD_IN}" + +FUTIL_OUTPUT="$(if "${FUTILITY}" verify \ + --publickey "${KEYDIR}/root_key.vbpubk" "${BAD_IN}"; \ + then false; fi)" +grep -q 'VBLOCK_A is invalid' <<< "${FUTIL_OUTPUT}" + +FUTIL_OUTPUT="$(if "${FUTILITY}" sign \ + -K "${KEYDIR}" \ + "${BAD_IN}" "${BAD_OUT}" 2>&1; \ + then false; fi)" +m="$(grep -c -E \ + 'VBLOCK_A preamble is invalid|Keyblock and preamble do not fit in VBLOCK' \ + <<< "${FUTIL_OUTPUT}")" +[ "${m}" = "2" ] + +: $(( bad_counter++ )) + +echo -n "${count}.${bad_counter} " 1>&3 +BAD_IN="${TMP}.${GOOD_DEV##*/}.bad.${bad_counter}.in.bin" +BAD_OUT="${TMP}.${GOOD_DEV##*/}.bad.${bad_counter}.out.bin" +cp "${GOOD_DEV}" "${BAD_IN}" +apply_xxd_patch "${BAD_FMAP_PREAMBLE_PATCHES[1]}" "${BAD_IN}" + +FUTIL_OUTPUT="$(if "${FUTILITY}" verify \ + --publickey "${KEYDIR}/root_key.vbpubk" "${BAD_IN}"; \ + then false; fi)" +grep -q 'VBLOCK_A is invalid' <<< "${FUTIL_OUTPUT}" + +FUTIL_OUTPUT="$(if "${FUTILITY}" sign \ + -K "${KEYDIR}" \ + "${BAD_IN}" "${BAD_OUT}" 2>&1; \ + then false; fi)" +m="$(grep -c -E \ + -e 'VBLOCK_A is invalid\. Keyblock and preamble do not fit' \ + -e 'Keyblock and preamble do not fit in VBLOCK' \ + <<< "${FUTIL_OUTPUT}")" +[ "${m}" = "2" ] + +: $(( bad_counter++ )) # cleanup -rm -rf ${TMP}* ${ONEMORE} +rm -rf "${TMP}"* "${ONEMORE}" exit 0
diff --git a/tests/futility/test_sign_fw_main.sh b/tests/futility/test_sign_fw_main.sh index face801..e22f907 100755 --- a/tests/futility/test_sign_fw_main.sh +++ b/tests/futility/test_sign_fw_main.sh
@@ -9,38 +9,36 @@ # Work in scratch directory cd "$OUTDIR" -KEYDIR=${SRCDIR}/tests/devkeys +KEYDIR="${SRCDIR}/tests/devkeys" # create a firmware blob -dd bs=1024 count=16 if=/dev/urandom of=${TMP}.fw_main +dd bs=1024 count=16 if=/dev/urandom of="${TMP}.fw_main" # try the old way -${FUTILITY} vbutil_firmware --vblock ${TMP}.vblock.old \ - --keyblock ${KEYDIR}/firmware.keyblock \ - --signprivate ${KEYDIR}/firmware_data_key.vbprivk \ +"${FUTILITY}" vbutil_firmware --vblock "${TMP}.vblock.old" \ + --keyblock "${KEYDIR}/firmware.keyblock" \ + --signprivate "${KEYDIR}/firmware_data_key.vbprivk" \ --version 12 \ - --fv ${TMP}.fw_main \ - --kernelkey ${KEYDIR}/kernel_subkey.vbpubk \ + --fv "${TMP}.fw_main" \ + --kernelkey "${KEYDIR}/kernel_subkey.vbpubk" \ --flags 42 # verify -${FUTILITY} vbutil_firmware --verify ${TMP}.vblock.old \ - --signpubkey ${KEYDIR}/root_key.vbpubk \ - --fv ${TMP}.fw_main +"${FUTILITY}" vbutil_firmware --verify "${TMP}.vblock.old" \ + --signpubkey "${KEYDIR}/root_key.vbpubk" \ + --fv "${TMP}.fw_main" # and the new way -${FUTILITY} --debug sign \ - --signprivate ${KEYDIR}/firmware_data_key.vbprivk \ - --keyblock ${KEYDIR}/firmware.keyblock \ - --kernelkey ${KEYDIR}/kernel_subkey.vbpubk \ +"${FUTILITY}" --debug sign \ + --keyset "${KEYDIR}" \ --version 12 \ - --fv ${TMP}.fw_main \ + --fv "${TMP}.fw_main" \ --flags 42 \ - ${TMP}.vblock.new + "${TMP}.vblock.new" # They should match -cmp ${TMP}.vblock.old ${TMP}.vblock.new +cmp "${TMP}.vblock.old" "${TMP}.vblock.new" # cleanup -rm -rf ${TMP}* +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_sign_kernel.sh b/tests/futility/test_sign_kernel.sh index d252745..bba1164 100755 --- a/tests/futility/test_sign_kernel.sh +++ b/tests/futility/test_sign_kernel.sh
@@ -11,11 +11,11 @@ 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 -dd if=/dev/urandom bs=1M count=16 of=${TMP}.kern_partition +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" +dd if=/dev/urandom bs=1M count=16 of="${TMP}.kern_partition" # default padding padding=49152 @@ -26,273 +26,278 @@ echo -n "${arch}: 1 " 1>&3 # pack it up the old way - ${FUTILITY} --debug vbutil_kernel \ - --pack ${TMP}.blob1.${arch} \ - --keyblock ${DEVKEYS}/recovery_kernel.keyblock \ - --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \ + "${FUTILITY}" --debug vbutil_kernel \ + --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 ${SCRIPT_DIR}/futility/data/vmlinuz-${arch}.bin \ - --arch ${arch} \ - --pad ${padding} \ + --config "${TMP}.config.txt" \ + --bootloader "${TMP}.bootloader.bin" \ + --vmlinuz "${SCRIPT_DIR}/futility/data/vmlinuz-${arch}.bin" \ + --arch "${arch}" \ + --pad "${padding}" \ --kloadaddr 0x11000 # verify the old way - ${FUTILITY} vbutil_kernel --verify ${TMP}.blob1.${arch} \ - --pad ${padding} \ - --signpubkey ${DEVKEYS}/recovery_key.vbpubk > ${TMP}.verify1 + "${FUTILITY}" vbutil_kernel --verify "${TMP}.blob1.${arch}" \ + --pad "${padding}" \ + --signpubkey "${DEVKEYS}/recovery_key.vbpubk" > "${TMP}.verify1" # pack it up the new way - ${FUTILITY} --debug sign \ - --keyblock ${DEVKEYS}/recovery_kernel.keyblock \ - --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \ + "${FUTILITY}" --debug sign \ + --keyset "${DEVKEYS}/recovery_" \ --version 1 \ - --config ${TMP}.config.txt \ - --bootloader ${TMP}.bootloader.bin \ - --vmlinuz ${SCRIPT_DIR}/futility/data/vmlinuz-${arch}.bin \ - --arch ${arch} \ - --pad ${padding} \ + --config "${TMP}.config.txt" \ + --bootloader "${TMP}.bootloader.bin" \ + --vmlinuz "${SCRIPT_DIR}/futility/data/vmlinuz-${arch}.bin" \ + --arch "${arch}" \ + --pad "${padding}" \ --kloadaddr 0x11000 \ - --outfile ${TMP}.blob2.${arch} + --outfile "${TMP}.blob2.${arch}" - ${FUTILITY} vbutil_kernel --verify ${TMP}.blob2.${arch} \ - --pad ${padding} \ - --signpubkey ${DEVKEYS}/recovery_key.vbpubk > ${TMP}.verify2 + "${FUTILITY}" vbutil_kernel --verify "${TMP}.blob2.${arch}" \ + --pad "${padding}" \ + --signpubkey "${DEVKEYS}/recovery_key.vbpubk" > "${TMP}.verify2" # they should be identical - cmp ${TMP}.blob1.${arch} ${TMP}.blob2.${arch} - diff ${TMP}.verify1 ${TMP}.verify2 + cmp "${TMP}.blob1.${arch}" "${TMP}.blob2.${arch}" + diff "${TMP}.verify1" "${TMP}.verify2" echo -n "2 " 1>&3 # repack it the old way - ${FUTILITY} --debug vbutil_kernel \ - --repack ${TMP}.blob3.${arch} \ - --oldblob ${TMP}.blob1.${arch} \ - --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ - --keyblock ${DEVKEYS}/kernel.keyblock \ + "${FUTILITY}" --debug vbutil_kernel \ + --repack "${TMP}.blob3.${arch}" \ + --oldblob "${TMP}.blob1.${arch}" \ + --signprivate "${DEVKEYS}/kernel_data_key.vbprivk" \ + --keyblock "${DEVKEYS}/kernel.keyblock" \ --version 2 \ - --pad ${padding} \ - --config ${TMP}.config2.txt \ - --bootloader ${TMP}.bootloader2.bin + --pad "${padding}" \ + --config "${TMP}.config2.txt" \ + --bootloader "${TMP}.bootloader2.bin" # verify the old way - ${FUTILITY} vbutil_kernel --verify ${TMP}.blob3.${arch} \ - --pad ${padding} \ - --signpubkey ${DEVKEYS}/kernel_subkey.vbpubk > ${TMP}.verify3 + "${FUTILITY}" vbutil_kernel --verify "${TMP}.blob3.${arch}" \ + --pad "${padding}" \ + --signpubkey "${DEVKEYS}/kernel_subkey.vbpubk" > "${TMP}.verify3" # repack it the new way - ${FUTILITY} --debug sign \ - --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ - --keyblock ${DEVKEYS}/kernel.keyblock \ + "${FUTILITY}" --debug sign \ + --keyset "${DEVKEYS}" \ + --keyblock "${DEVKEYS}/kernel.keyblock" \ --version 2 \ - --pad ${padding} \ - --config ${TMP}.config2.txt \ - --bootloader ${TMP}.bootloader2.bin \ - ${TMP}.blob2.${arch} \ - ${TMP}.blob4.${arch} + --pad "${padding}" \ + --config "${TMP}.config2.txt" \ + --bootloader "${TMP}.bootloader2.bin" \ + "${TMP}.blob2.${arch}" \ + "${TMP}.blob4.${arch}" - ${FUTILITY} vbutil_kernel --verify ${TMP}.blob4.${arch} \ - --pad ${padding} \ - --signpubkey ${DEVKEYS}/kernel_subkey.vbpubk > ${TMP}.verify4 + "${FUTILITY}" vbutil_kernel --verify "${TMP}.blob4.${arch}" \ + --pad "${padding}" \ + --signpubkey "${DEVKEYS}/kernel_subkey.vbpubk" > "${TMP}.verify4" # they should be identical - cmp ${TMP}.blob3.${arch} ${TMP}.blob4.${arch} - diff ${TMP}.verify3 ${TMP}.verify4 + cmp "${TMP}.blob3.${arch}" "${TMP}.blob4.${arch}" + diff "${TMP}.verify3" "${TMP}.verify4" echo -n "3 " 1>&3 # repack it the new way, in-place - cp ${TMP}.blob2.${arch} ${TMP}.blob5.${arch} - ${FUTILITY} --debug sign \ - --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ - --keyblock ${DEVKEYS}/kernel.keyblock \ + cp "${TMP}.blob2.${arch}" "${TMP}.blob5.${arch}" + "${FUTILITY}" --debug sign \ + --signprivate "${DEVKEYS}/kernel_data_key.vbprivk" \ + --keyblock "${DEVKEYS}/kernel.keyblock" \ --version 2 \ - --pad ${padding} \ - --config ${TMP}.config2.txt \ - --bootloader ${TMP}.bootloader2.bin \ - ${TMP}.blob5.${arch} + --pad "${padding}" \ + --config "${TMP}.config2.txt" \ + --bootloader "${TMP}.bootloader2.bin" \ + "${TMP}.blob5.${arch}" - ${FUTILITY} vbutil_kernel --verify ${TMP}.blob5.${arch} \ - --pad ${padding} \ - --signpubkey ${DEVKEYS}/kernel_subkey.vbpubk > ${TMP}.verify5 + "${FUTILITY}" vbutil_kernel --verify "${TMP}.blob5.${arch}" \ + --pad "${padding}" \ + --signpubkey "${DEVKEYS}/kernel_subkey.vbpubk" > "${TMP}.verify5" # they should be identical - cmp ${TMP}.blob3.${arch} ${TMP}.blob5.${arch} - diff ${TMP}.verify3 ${TMP}.verify5 + cmp "${TMP}.blob3.${arch}" "${TMP}.blob5.${arch}" + diff "${TMP}.verify3" "${TMP}.verify5" # and now just the vblocks... echo -n "4 " 1>&3 # pack the old way - ${FUTILITY} vbutil_kernel \ - --pack ${TMP}.blob1.${arch}.vb1 \ + "${FUTILITY}" vbutil_kernel \ + --pack "${TMP}.blob1.${arch}.vb1" \ --vblockonly \ - --keyblock ${DEVKEYS}/recovery_kernel.keyblock \ - --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \ + --keyblock "${DEVKEYS}/recovery_kernel.keyblock" \ + --signprivate "${DEVKEYS}/recovery_kernel_data_key.vbprivk" \ --version 1 \ - --config ${TMP}.config.txt \ - --bootloader ${TMP}.bootloader.bin \ - --vmlinuz ${SCRIPT_DIR}/futility/data/vmlinuz-${arch}.bin \ - --arch ${arch} \ - --pad ${padding} \ + --config "${TMP}.config.txt" \ + --bootloader "${TMP}.bootloader.bin" \ + --vmlinuz "${SCRIPT_DIR}/futility/data/vmlinuz-${arch}.bin" \ + --arch "${arch}" \ + --pad "${padding}" \ --kloadaddr 0x11000 # compare this new vblock with the one from the full pack - dd bs=${padding} count=1 if=${TMP}.blob1.${arch} of=${TMP}.blob1.${arch}.vb0 - cmp ${TMP}.blob1.${arch}.vb0 ${TMP}.blob1.${arch}.vb1 + dd bs="${padding}" count=1 if="${TMP}.blob1.${arch}" \ + of="${TMP}.blob1.${arch}.vb0" + cmp "${TMP}.blob1.${arch}.vb0" "${TMP}.blob1.${arch}.vb1" # pack the new way - ${FUTILITY} --debug sign \ - --keyblock ${DEVKEYS}/recovery_kernel.keyblock \ - --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \ + "${FUTILITY}" --debug sign \ + --keyblock "${DEVKEYS}/recovery_kernel.keyblock" \ + --signprivate "${DEVKEYS}/recovery_kernel_data_key.vbprivk" \ --version 1 \ - --config ${TMP}.config.txt \ - --bootloader ${TMP}.bootloader.bin \ - --vmlinuz ${SCRIPT_DIR}/futility/data/vmlinuz-${arch}.bin \ - --arch ${arch} \ - --pad ${padding} \ + --config "${TMP}.config.txt" \ + --bootloader "${TMP}.bootloader.bin" \ + --vmlinuz "${SCRIPT_DIR}/futility/data/vmlinuz-${arch}.bin" \ + --arch "${arch}" \ + --pad "${padding}" \ --kloadaddr 0x11000 \ --vblockonly \ - ${TMP}.blob2.${arch}.vb1 + "${TMP}.blob2.${arch}.vb1" # compare this new vblock with the one from the full pack - dd bs=${padding} count=1 if=${TMP}.blob2.${arch} of=${TMP}.blob2.${arch}.vb0 - cmp ${TMP}.blob2.${arch}.vb0 ${TMP}.blob2.${arch}.vb1 + dd bs="${padding}" count=1 if="${TMP}.blob2.${arch}" \ + of="${TMP}.blob2.${arch}.vb0" + cmp "${TMP}.blob2.${arch}.vb0" "${TMP}.blob2.${arch}.vb1" echo -n "5 " 1>&3 # now repack the old way, again emitting just the vblock - ${FUTILITY} vbutil_kernel \ - --repack ${TMP}.blob3.${arch}.vb1 \ + "${FUTILITY}" vbutil_kernel \ + --repack "${TMP}.blob3.${arch}.vb1" \ --vblockonly \ - --oldblob ${TMP}.blob1.${arch} \ - --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ - --keyblock ${DEVKEYS}/kernel.keyblock \ + --oldblob "${TMP}.blob1.${arch}" \ + --signprivate "${DEVKEYS}/kernel_data_key.vbprivk" \ + --keyblock "${DEVKEYS}/kernel.keyblock" \ --version 2 \ - --pad ${padding} \ - --config ${TMP}.config2.txt \ - --bootloader ${TMP}.bootloader2.bin + --pad "${padding}" \ + --config "${TMP}.config2.txt" \ + --bootloader "${TMP}.bootloader2.bin" # compare the full repacked vblock with the new repacked vblock - dd bs=${padding} count=1 if=${TMP}.blob3.${arch} of=${TMP}.blob3.${arch}.vb0 - cmp ${TMP}.blob3.${arch}.vb0 ${TMP}.blob3.${arch}.vb1 + dd bs="${padding}" count=1 if="${TMP}.blob3.${arch}" \ + of="${TMP}.blob3.${arch}.vb0" + cmp "${TMP}.blob3.${arch}.vb0" "${TMP}.blob3.${arch}.vb1" # extract just the kernel blob - dd bs=${padding} skip=1 if=${TMP}.blob3.${arch} of=${TMP}.blob3.${arch}.kb0 + dd bs="${padding}" skip=1 if="${TMP}.blob3.${arch}" \ + of="${TMP}.blob3.${arch}.kb0" # and verify it using the new vblock (no way to do that with vbutil_kernel) - ${FUTILITY} --debug verify \ - --pad ${padding} \ - --publickey ${DEVKEYS}/kernel_subkey.vbpubk \ - --fv ${TMP}.blob3.${arch}.kb0 \ - ${TMP}.blob3.${arch}.vb1 > ${TMP}.verify3v + "${FUTILITY}" --debug verify \ + --pad "${padding}" \ + --publickey "${DEVKEYS}/kernel_subkey.vbpubk" \ + --fv "${TMP}.blob3.${arch}.kb0" \ + "${TMP}.blob3.${arch}.vb1" > "${TMP}.verify3v" # repack the new way - ${FUTILITY} --debug sign \ - --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ - --keyblock ${DEVKEYS}/kernel.keyblock \ + "${FUTILITY}" --debug sign \ + --signprivate "${DEVKEYS}/kernel_data_key.vbprivk" \ + --keyblock "${DEVKEYS}/kernel.keyblock" \ --version 2 \ - --config ${TMP}.config2.txt \ - --bootloader ${TMP}.bootloader2.bin \ - --pad ${padding} \ + --config "${TMP}.config2.txt" \ + --bootloader "${TMP}.bootloader2.bin" \ + --pad "${padding}" \ --vblockonly \ - ${TMP}.blob2.${arch} \ - ${TMP}.blob4.${arch}.vb1 \ + "${TMP}.blob2.${arch}" \ + "${TMP}.blob4.${arch}.vb1" \ # compare the full repacked vblock with the new repacked vblock - dd bs=${padding} count=1 if=${TMP}.blob4.${arch} of=${TMP}.blob4.${arch}.vb0 - cmp ${TMP}.blob4.${arch}.vb0 ${TMP}.blob4.${arch}.vb1 + dd bs="${padding}" count=1 if="${TMP}.blob4.${arch}" \ + of="${TMP}.blob4.${arch}.vb0" + cmp "${TMP}.blob4.${arch}.vb0" "${TMP}.blob4.${arch}.vb1" # extract just the kernel blob - dd bs=${padding} skip=1 if=${TMP}.blob4.${arch} of=${TMP}.blob4.${arch}.kb0 + dd bs="${padding}" skip=1 if="${TMP}.blob4.${arch}" \ + of="${TMP}.blob4.${arch}.kb0" # and verify it using the new vblock (no way to do that with vbutil_kernel) - ${FUTILITY} --debug verify \ - --pad ${padding} \ - --publickey ${DEVKEYS}/kernel_subkey.vbpubk \ - --fv ${TMP}.blob4.${arch}.kb0 \ - ${TMP}.blob4.${arch}.vb1 > ${TMP}.verify4v + "${FUTILITY}" --debug verify \ + --pad "${padding}" \ + --publickey "${DEVKEYS}/kernel_subkey.vbpubk" \ + --fv "${TMP}.blob4.${arch}.kb0" \ + "${TMP}.blob4.${arch}.vb1" > "${TMP}.verify4v" echo -n "6 " 1>&3 # Now lets repack some kernel partitions, not just blobs. - cp ${TMP}.kern_partition ${TMP}.part1.${arch} - dd if=${TMP}.blob1.${arch} of=${TMP}.part1.${arch} conv=notrunc + cp "${TMP}.kern_partition" "${TMP}.part1.${arch}" + dd if="${TMP}.blob1.${arch}" of="${TMP}.part1.${arch}" conv=notrunc # Make sure the partitions verify - ${FUTILITY} vbutil_kernel --verify ${TMP}.part1.${arch} \ - --pad ${padding} \ - --signpubkey ${DEVKEYS}/recovery_key.vbpubk > ${TMP}.verify6 + "${FUTILITY}" vbutil_kernel --verify "${TMP}.part1.${arch}" \ + --pad "${padding}" \ + --signpubkey "${DEVKEYS}/recovery_key.vbpubk" > "${TMP}.verify6" # The partition should verify the same way as the blob - diff ${TMP}.verify1 ${TMP}.verify6 + diff "${TMP}.verify1" "${TMP}.verify6" # repack it the old way - ${FUTILITY} --debug vbutil_kernel \ - --repack ${TMP}.part6.${arch} \ - --oldblob ${TMP}.part1.${arch} \ - --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ - --keyblock ${DEVKEYS}/kernel.keyblock \ + "${FUTILITY}" --debug vbutil_kernel \ + --repack "${TMP}.part6.${arch}" \ + --oldblob "${TMP}.part1.${arch}" \ + --signprivate "${DEVKEYS}/kernel_data_key.vbprivk" \ + --keyblock "${DEVKEYS}/kernel.keyblock" \ --version 2 \ - --pad ${padding} \ - --config ${TMP}.config2.txt \ - --bootloader ${TMP}.bootloader2.bin + --pad "${padding}" \ + --config "${TMP}.config2.txt" \ + --bootloader "${TMP}.bootloader2.bin" # verify the old way - ${FUTILITY} vbutil_kernel --verify ${TMP}.part6.${arch} \ - --pad ${padding} \ - --signpubkey ${DEVKEYS}/kernel_subkey.vbpubk > ${TMP}.verify6.old + "${FUTILITY}" vbutil_kernel --verify "${TMP}.part6.${arch}" \ + --pad "${padding}" \ + --signpubkey "${DEVKEYS}/kernel_subkey.vbpubk" > "${TMP}.verify6.old" # this "partition" should actually be the same as the old-way blob - cmp ${TMP}.blob3.${arch} ${TMP}.part6.${arch} + cmp "${TMP}.blob3.${arch}" "${TMP}.part6.${arch}" # repack it the new way, in-place - cp ${TMP}.part1.${arch} ${TMP}.part6.${arch}.new1 - ${FUTILITY} --debug sign \ - --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ - --keyblock ${DEVKEYS}/kernel.keyblock \ + cp "${TMP}.part1.${arch}" "${TMP}.part6.${arch}.new1" + "${FUTILITY}" --debug sign \ + --signprivate "${DEVKEYS}/kernel_data_key.vbprivk" \ + --keyblock "${DEVKEYS}/kernel.keyblock" \ --version 2 \ - --pad ${padding} \ - --config ${TMP}.config2.txt \ - --bootloader ${TMP}.bootloader2.bin \ - ${TMP}.part6.${arch}.new1 + --pad "${padding}" \ + --config "${TMP}.config2.txt" \ + --bootloader "${TMP}.bootloader2.bin" \ + "${TMP}.part6.${arch}.new1" - ${FUTILITY} vbutil_kernel --verify ${TMP}.part6.${arch}.new1 \ - --pad ${padding} \ - --signpubkey ${DEVKEYS}/kernel_subkey.vbpubk > ${TMP}.verify6.new1 + "${FUTILITY}" vbutil_kernel --verify "${TMP}.part6.${arch}.new1" \ + --pad "${padding}" \ + --signpubkey "${DEVKEYS}/kernel_subkey.vbpubk" > "${TMP}.verify6.new1" # The verification should be indentical - diff ${TMP}.verify6.old ${TMP}.verify6.new1 + diff "${TMP}.verify6.old" "${TMP}.verify6.new1" # But the content should only match up to the size of the kernel blob, since # we're modifying an entire partition in-place. - blobsize=$(stat -c '%s' ${TMP}.part6.${arch}) - cmp -n ${blobsize} ${TMP}.part6.${arch} ${TMP}.part6.${arch}.new1 + blobsize=$(stat -c '%s' "${TMP}.part6.${arch}") + cmp -n "${blobsize}" "${TMP}.part6.${arch}" "${TMP}.part6.${arch}.new1" # The rest of the partition should be unchanged. - cmp -i ${blobsize} ${TMP}.part1.${arch} ${TMP}.part6.${arch}.new1 + cmp -i "${blobsize}" "${TMP}.part1.${arch}" "${TMP}.part6.${arch}.new1" # repack it the new way, from input to output - cp ${TMP}.part1.${arch} ${TMP}.part1.${arch}.in - ${FUTILITY} --debug sign \ - --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \ - --keyblock ${DEVKEYS}/kernel.keyblock \ + cp "${TMP}.part1.${arch}" "${TMP}.part1.${arch}.in" + "${FUTILITY}" --debug sign \ + --signprivate "${DEVKEYS}/kernel_data_key.vbprivk" \ + --keyblock "${DEVKEYS}/kernel.keyblock" \ --version 2 \ - --pad ${padding} \ - --config ${TMP}.config2.txt \ - --bootloader ${TMP}.bootloader2.bin \ - ${TMP}.part1.${arch}.in \ - ${TMP}.part6.${arch}.new2 + --pad "${padding}" \ + --config "${TMP}.config2.txt" \ + --bootloader "${TMP}.bootloader2.bin" \ + "${TMP}.part1.${arch}.in" \ + "${TMP}.part6.${arch}.new2" - ${FUTILITY} vbutil_kernel --verify ${TMP}.part6.${arch}.new2 \ - --pad ${padding} \ - --signpubkey ${DEVKEYS}/kernel_subkey.vbpubk > ${TMP}.verify6.new2 + "${FUTILITY}" vbutil_kernel --verify "${TMP}.part6.${arch}.new2" \ + --pad "${padding}" \ + --signpubkey "${DEVKEYS}/kernel_subkey.vbpubk" > "${TMP}.verify6.new2" # The input file should not have changed (just being sure). - cmp ${TMP}.part1.${arch} ${TMP}.part1.${arch}.in + cmp "${TMP}.part1.${arch}" "${TMP}.part1.${arch}.in" # The verification should be indentical - diff ${TMP}.verify6.old ${TMP}.verify6.new2 + diff "${TMP}.verify6.old" "${TMP}.verify6.new2" # And creating a new output file should only emit a blob's worth - cmp ${TMP}.part6.${arch} ${TMP}.part6.${arch}.new2 + cmp "${TMP}.part6.${arch}" "${TMP}.part6.${arch}.new2" # 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 @@ -304,5 +309,5 @@ try_arch arm # cleanup -rm -rf ${TMP}* +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_sign_keyblocks.sh b/tests/futility/test_sign_keyblocks.sh index f689c89..75d367d 100755 --- a/tests/futility/test_sign_keyblocks.sh +++ b/tests/futility/test_sign_keyblocks.sh
@@ -16,95 +16,95 @@ # Create a copy of an existing keyblock, using the old way -${FUTILITY} vbutil_keyblock --pack ${TMP}.keyblock0 \ - --datapubkey ${DEVKEYS}/firmware_data_key.vbpubk \ +"${FUTILITY}" vbutil_keyblock --pack "${TMP}.keyblock0" \ + --datapubkey "${DEVKEYS}/firmware_data_key.vbpubk" \ --flags 23 \ - --signprivate ${DEVKEYS}/root_key.vbprivk + --signprivate "${DEVKEYS}/root_key.vbprivk" # Check it. -${FUTILITY} vbutil_keyblock --unpack ${TMP}.keyblock0 \ - --signpubkey ${DEVKEYS}/root_key.vbpubk +"${FUTILITY}" vbutil_keyblock --unpack "${TMP}.keyblock0" \ + --signpubkey "${DEVKEYS}/root_key.vbpubk" # It should be the same as the dev-key firmware keyblock -cmp ${DEVKEYS}/firmware.keyblock ${TMP}.keyblock0 +cmp "${DEVKEYS}/firmware.keyblock" "${TMP}.keyblock0" # Now create it the new way -${FUTILITY} --debug sign \ - --datapubkey ${DEVKEYS}/firmware_data_key.vbpubk \ +"${FUTILITY}" --debug sign \ + --datapubkey "${DEVKEYS}/firmware_data_key.vbpubk" \ --flags 23 \ - --signprivate ${DEVKEYS}/root_key.vbprivk \ - --outfile ${TMP}.keyblock1 + --signprivate "${DEVKEYS}/root_key.vbprivk" \ + --outfile "${TMP}.keyblock1" # It should be the same too. -cmp ${DEVKEYS}/firmware.keyblock ${TMP}.keyblock1 +cmp "${DEVKEYS}/firmware.keyblock" "${TMP}.keyblock1" # Create a keyblock without signing it. # old way -${FUTILITY} vbutil_keyblock --pack ${TMP}.keyblock0 \ - --datapubkey ${DEVKEYS}/firmware_data_key.vbpubk \ +"${FUTILITY}" vbutil_keyblock --pack "${TMP}.keyblock0" \ + --datapubkey "${DEVKEYS}/firmware_data_key.vbpubk" \ --flags 14 # new way -${FUTILITY} --debug sign \ +"${FUTILITY}" --debug sign \ --flags 14 \ - ${DEVKEYS}/firmware_data_key.vbpubk \ - ${TMP}.keyblock1 + "${DEVKEYS}/firmware_data_key.vbpubk" \ + "${TMP}.keyblock1" -cmp ${TMP}.keyblock0 ${TMP}.keyblock1 +cmp "${TMP}.keyblock0" "${TMP}.keyblock1" # Create one using PEM args # old way -${FUTILITY} vbutil_keyblock --pack ${TMP}.keyblock2 \ - --datapubkey ${DEVKEYS}/firmware_data_key.vbpubk \ - --signprivate_pem ${TESTKEYS}/key_rsa4096.pem \ +"${FUTILITY}" vbutil_keyblock --pack "${TMP}.keyblock2" \ + --datapubkey "${DEVKEYS}/firmware_data_key.vbpubk" \ + --signprivate_pem "${TESTKEYS}/key_rsa4096.pem" \ --pem_algorithm 8 \ --flags 9 # verify it -${FUTILITY} vbutil_keyblock --unpack ${TMP}.keyblock2 \ - --signpubkey ${TESTKEYS}/key_rsa4096.sha512.vbpubk +"${FUTILITY}" vbutil_keyblock --unpack "${TMP}.keyblock2" \ + --signpubkey "${TESTKEYS}/key_rsa4096.sha512.vbpubk" # new way -${FUTILITY} --debug sign \ - --pem_signpriv ${TESTKEYS}/key_rsa4096.pem \ +"${FUTILITY}" --debug sign \ + --pem_signpriv "${TESTKEYS}/key_rsa4096.pem" \ --pem_algo 8 \ --flags 9 \ - ${DEVKEYS}/firmware_data_key.vbpubk \ - ${TMP}.keyblock3 + "${DEVKEYS}/firmware_data_key.vbpubk" \ + "${TMP}.keyblock3" -cmp ${TMP}.keyblock2 ${TMP}.keyblock3 +cmp "${TMP}.keyblock2" "${TMP}.keyblock3" # Try it with an external signer # old way -${FUTILITY} vbutil_keyblock --pack ${TMP}.keyblock4 \ - --datapubkey ${DEVKEYS}/firmware_data_key.vbpubk \ - --signprivate_pem ${TESTKEYS}/key_rsa4096.pem \ +"${FUTILITY}" vbutil_keyblock --pack "${TMP}.keyblock4" \ + --datapubkey "${DEVKEYS}/firmware_data_key.vbpubk" \ + --signprivate_pem "${TESTKEYS}/key_rsa4096.pem" \ --pem_algorithm 8 \ --flags 19 \ - --externalsigner ${SIGNER} + --externalsigner "${SIGNER}" # verify it -${FUTILITY} vbutil_keyblock --unpack ${TMP}.keyblock4 \ - --signpubkey ${TESTKEYS}/key_rsa4096.sha512.vbpubk +"${FUTILITY}" vbutil_keyblock --unpack "${TMP}.keyblock4" \ + --signpubkey "${TESTKEYS}/key_rsa4096.sha512.vbpubk" # new way -${FUTILITY} --debug sign \ - --pem_signpriv ${TESTKEYS}/key_rsa4096.pem \ +"${FUTILITY}" --debug sign \ + --pem_signpriv "${TESTKEYS}/key_rsa4096.pem" \ --pem_algo 8 \ - --pem_external ${SIGNER} \ + --pem_external "${SIGNER}" \ --flags 19 \ - ${DEVKEYS}/firmware_data_key.vbpubk \ - ${TMP}.keyblock5 + "${DEVKEYS}/firmware_data_key.vbpubk" \ + "${TMP}.keyblock5" -cmp ${TMP}.keyblock4 ${TMP}.keyblock5 +cmp "${TMP}.keyblock4" "${TMP}.keyblock5" # cleanup -rm -rf ${TMP}* +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_sign_usbpd1.sh b/tests/futility/test_sign_usbpd1.sh index 48e64eb..2324fae 100755 --- a/tests/futility/test_sign_usbpd1.sh +++ b/tests/futility/test_sign_usbpd1.sh
@@ -24,33 +24,33 @@ : $(( count++ )) echo -n "$count " 1>&3 - pemfile=${DATADIR}/${test}.pem - infile=${DATADIR}/${test}.unsigned - goodfile=${DATADIR}/${test}.signed - outfile=${TMP}.${test}.new + pemfile="${DATADIR}/${test}.pem" + infile="${DATADIR}/${test}.unsigned" + goodfile="${DATADIR}/${test}.signed" + outfile="${TMP}.${test}.new" # Signing the whole thing with futility should produce identical results - ${FUTILITY} sign --type usbpd1 --pem ${pemfile} ${infile} ${outfile} - cmp ${goodfile} ${outfile} + "${FUTILITY}" sign --type usbpd1 --pem "${pemfile}" "${infile}" "${outfile}" + cmp "${goodfile}" "${outfile}" # Now try signing just the RW part - size=$(stat -c '%s' ${infile}) + size=$(stat -c '%s' "${infile}") half=$(( size / 2 )) - newin=${TMP}.${test}.rw_in - dd if=${infile} bs=${half} count=1 skip=1 of=${newin} + newin="${TMP}.${test}.rw_in" + dd if="${infile}" bs="${half}" count=1 skip=1 of="${newin}" newgood=${TMP}.${test}.rw_ok - dd if=${goodfile} bs=${half} count=1 skip=1 of=${newgood} - newout=${TMP}.${test}.rw_out + dd if="${goodfile}" bs="${half}" count=1 skip=1 of="${newgood}" + newout="${TMP}.${test}.rw_out" # Sign the RW part alone - ${FUTILITY} sign --type usbpd1 --pem ${pemfile} \ + "${FUTILITY}" sign --type usbpd1 --pem "${pemfile}" \ --ro_size 0 \ - ${newin} ${newout} - cmp ${newgood} ${newout} + "${newin}" "${newout}" + cmp "${newgood}" "${newout}" done # cleanup -rm -rf ${TMP}* +rm -rf "${TMP}"* exit 0
diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index 25c5543..8d8a559 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh
@@ -40,12 +40,12 @@ set -o pipefail # In all the test scenario, we want to test "updating from PEPPY to LINK". -TO_IMAGE=${TMP}.src.link -FROM_IMAGE=${TMP}.src.peppy +TO_IMAGE="${TMP}.src.link" +FROM_IMAGE="${TMP}.src.peppy" TO_HWID="X86 LINK TEST 6638" FROM_HWID="X86 PEPPY TEST 4211" -cp -f ${LINK_BIOS} ${TO_IMAGE} -cp -f ${PEPPY_BIOS} ${FROM_IMAGE} +cp -f "${LINK_BIOS}" "${TO_IMAGE}" +cp -f "${PEPPY_BIOS}" "${FROM_IMAGE}" "${FUTILITY}" load_fmap "${FROM_IMAGE}" \ RO_VPD:"${RO_VPD_BLOB}" RW_VPD:"${RO_VPD_BLOB}" cp -f "${FROM_IMAGE}" "${FROM_IMAGE}".unpatched @@ -57,29 +57,34 @@ local data="$4" # NAME OFFSET SIZE - local fmap_info="$(${FUTILITY} dump_fmap -p ${file} ${section})" - local base="$(echo "${fmap_info}" | sed 's/^[^ ]* //; s/ [^ ]*$//')" - local offset=$((base + section_offset)) + local fmap_info + local base + local offset + + fmap_info="$("${FUTILITY}" dump_fmap -p "${file}" "${section}")" + base="$(echo "${fmap_info}" | sed 's/^[^ ]* //; s/ [^ ]*$//')" + offset=$((base + section_offset)) echo "offset: ${offset}" - printf "${data}" | dd of="${file}" bs=1 seek="${offset}" conv=notrunc + printf "%b" "${data}" | dd of="${file}" bs=1 seek="${offset}" \ + conv=notrunc } # PEPPY and LINK have different platform element ("Google_Link" and # "Google_Peppy") in firmware ID so we want to hack them by changing # "Google_" to "Google.". -patch_file ${TO_IMAGE} RW_FWID_A 0 Google. -patch_file ${TO_IMAGE} RW_FWID_B 0 Google. -patch_file ${TO_IMAGE} RO_FRID 0 Google. -patch_file ${FROM_IMAGE} RW_FWID_A 0 Google. -patch_file ${FROM_IMAGE} RW_FWID_B 0 Google. -patch_file ${FROM_IMAGE} RO_FRID 0 Google. +patch_file "${TO_IMAGE}" RW_FWID_A 0 Google. +patch_file "${TO_IMAGE}" RW_FWID_B 0 Google. +patch_file "${TO_IMAGE}" RO_FRID 0 Google. +patch_file "${FROM_IMAGE}" RW_FWID_A 0 Google. +patch_file "${FROM_IMAGE}" RW_FWID_B 0 Google. +patch_file "${FROM_IMAGE}" RO_FRID 0 Google. unpack_image() { local folder="${TMP}.$1" local image="$2" mkdir -p "${folder}" - (cd "${folder}" && ${FUTILITY} dump_fmap -x "../${image}") - ${FUTILITY} gbb -g --rootkey="${folder}/rootkey" "${image}" + (cd "${folder}" && "${FUTILITY}" dump_fmap -x "../${image}") + "${FUTILITY}" gbb -g --rootkey="${folder}/rootkey" "${image}" } # Unpack images so we can prepare expected results by individual sections. @@ -114,19 +119,19 @@ cp -f "${FROM_IMAGE}" "${TMP}.expected.legacy" "${FUTILITY}" gbb -s --hwid="${FROM_HWID}" "${TMP}.expected.full" "${FUTILITY}" load_fmap "${TMP}.expected.full" \ - RW_VPD:${TMP}.from/RW_VPD \ - RO_VPD:${TMP}.from/RO_VPD + "RW_VPD:${TMP}.from/RW_VPD" \ + "RO_VPD:${TMP}.from/RO_VPD" "${FUTILITY}" load_fmap "${TMP}.expected.rw" \ - RW_SECTION_A:${TMP}.to/RW_SECTION_A \ - RW_SECTION_B:${TMP}.to/RW_SECTION_B \ - RW_SHARED:${TMP}.to/RW_SHARED \ - RW_LEGACY:${TMP}.to/RW_LEGACY + "RW_SECTION_A:${TMP}.to/RW_SECTION_A" \ + "RW_SECTION_B:${TMP}.to/RW_SECTION_B" \ + "RW_SHARED:${TMP}.to/RW_SHARED" \ + "RW_LEGACY:${TMP}.to/RW_LEGACY" "${FUTILITY}" load_fmap "${TMP}.expected.a" \ - RW_SECTION_A:${TMP}.to/RW_SECTION_A + "RW_SECTION_A:${TMP}.to/RW_SECTION_A" "${FUTILITY}" load_fmap "${TMP}.expected.b" \ - RW_SECTION_B:${TMP}.to/RW_SECTION_B + "RW_SECTION_B:${TMP}.to/RW_SECTION_B" "${FUTILITY}" load_fmap "${TMP}.expected.legacy" \ - RW_LEGACY:${TMP}.to/RW_LEGACY + "RW_LEGACY:${TMP}.to/RW_LEGACY" cp -f "${TMP}.expected.full" "${TMP}.expected.full.gbb12" patch_file "${TMP}.expected.full.gbb12" GBB 6 "\x02" "${FUTILITY}" gbb -s --hwid="${FROM_HWID}" "${TMP}.expected.full.gbb12" @@ -149,7 +154,7 @@ # FMAP_AREA_PRESERVE (\010=0x08). TO_IMAGE_WIPE_RW_VPD="${TO_IMAGE}.wipe_rw_vpd" cp -f "${TO_IMAGE}" "${TO_IMAGE_WIPE_RW_VPD}" -patch_file ${TO_IMAGE_WIPE_RW_VPD} FMAP 0x3fc "$(printf '\010')" +patch_file "${TO_IMAGE_WIPE_RW_VPD}" FMAP 0x3fc "$(printf '\010')" cp -f "${TMP}.expected.full" "${TMP}.expected.full.empty_rw_vpd" "${FUTILITY}" load_fmap "${TMP}.expected.full.empty_rw_vpd" \ RW_VPD:"${TMP}.to/RW_VPD" @@ -371,20 +376,20 @@ --quirks preserve_me \ -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001,1 -# Test archive and manifest. +# Test archive and manifest. CL_TAG is for custom_label_tag. A="${TMP}.archive" mkdir -p "${A}/bin" -echo 'echo "${WL_TAG}"' >"${A}/bin/vpd" +echo "echo \"\${CL_TAG}\"" >"${A}/bin/vpd" chmod +x "${A}/bin/vpd" cp -f "${LINK_BIOS}" "${A}/bios.bin" echo "TEST: Manifest (--manifest, bios.bin)" -${FUTILITY} update -a "${A}" --manifest >"${TMP}.json.out" +"${FUTILITY}" update -a "${A}" --manifest >"${TMP}.json.out" cmp "${TMP}.json.out" "${SCRIPT_DIR}/futility/link_bios.manifest.json" mv -f "${A}/bios.bin" "${A}/image.bin" echo "TEST: Manifest (--manifest, image.bin)" -${FUTILITY} update -a "${A}" --manifest >"${TMP}.json.out" +"${FUTILITY}" update -a "${A}" --manifest >"${TMP}.json.out" cmp "${TMP}.json.out" "${SCRIPT_DIR}/futility/link_image.manifest.json" @@ -395,44 +400,46 @@ echo "TEST: Output (--mode=output)" mkdir -p "${TMP}.output" -${FUTILITY} update -i "${LINK_BIOS}" --mode=output --output_dir="${TMP}.output" +"${FUTILITY}" update -i "${LINK_BIOS}" --mode=output \ + --output_dir="${TMP}.output" cmp "${LINK_BIOS}" "${TMP}.output/image.bin" mkdir -p "${A}/keyset" cp -f "${LINK_BIOS}" "${A}/image.bin" -cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.WL" -cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.WL" -cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.WL" -${FUTILITY} gbb -s --rootkey="${TMP}.from/rootkey" "${A}/image.bin" -${FUTILITY} load_fmap "${A}/image.bin" VBLOCK_A:"${TMP}.from/VBLOCK_A" -${FUTILITY} load_fmap "${A}/image.bin" VBLOCK_B:"${TMP}.from/VBLOCK_B" +cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.CL" +cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.CL" +cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.CL" +"${FUTILITY}" gbb -s --rootkey="${TMP}.from/rootkey" "${A}/image.bin" +"${FUTILITY}" load_fmap "${A}/image.bin" VBLOCK_A:"${TMP}.from/VBLOCK_A" +"${FUTILITY}" load_fmap "${A}/image.bin" VBLOCK_B:"${TMP}.from/VBLOCK_B" -test_update "Full update (--archive, whitelabel, no VPD)" \ - "${A}/image.bin" "!Need VPD set for white" \ +test_update "Full update (--archive, custom label, no VPD)" \ + "${A}/image.bin" "!Need VPD set for custom" \ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 -test_update "Full update (--archive, whitelabel, no VPD - factory mode)" \ +test_update "Full update (--archive, custom label, no VPD - factory mode)" \ "${LINK_BIOS}" "${A}/image.bin" \ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --mode=factory -test_update "Full update (--archive, whitelabel, no VPD - quirk mode)" \ +test_update "Full update (--archive, custom label, no VPD - quirk mode)" \ "${LINK_BIOS}" "${A}/image.bin" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --quirks=allow_empty_wltag + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 \ + --quirks=allow_empty_custom_label_tag -test_update "Full update (--archive, WL, single package)" \ +test_update "Full update (--archive, custom label, single package)" \ "${A}/image.bin" "${LINK_BIOS}" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --signature_id=WL + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --signature_id=CL -WL_TAG="WL" PATH="${A}/bin:${PATH}" \ - test_update "Full update (--archive, WL, fake vpd)" \ +CL_TAG="CL" PATH="${A}/bin:${PATH}" \ + test_update "Full update (--archive, custom label, fake vpd)" \ "${A}/image.bin" "${LINK_BIOS}" \ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 echo "TEST: Output (-a, --mode=output)" mkdir -p "${TMP}.outa" cp -f "${A}/image.bin" "${TMP}.emu" -WL_TAG="WL" PATH="${A}/bin:${PATH}" \ - ${FUTILITY} update -a "${A}" --mode=output --emu="${TMP}.emu" \ +CL_TAG="CL" PATH="${A}/bin:${PATH}" \ + "${FUTILITY}" update -a "${A}" --mode=output --emu="${TMP}.emu" \ --output_dir="${TMP}.outa" cmp "${LINK_BIOS}" "${TMP}.outa/image.bin" @@ -442,13 +449,13 @@ mv "${A}/image.bin" "${A}/images/bios_coral.bin" cp -f "${PEPPY_BIOS}" "${A}/images/bios_peppy.bin" cp -f "${LINK_BIOS}" "${A}/images/bios_link.bin" -cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.whitetip-wl" -cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.whitetip-wl" -cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.whitetip-wl" +cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.customtip-cl" +cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.customtip-cl" +cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.customtip-cl" cp -f "${PEPPY_BIOS}" "${FROM_IMAGE}.ap" cp -f "${LINK_BIOS}" "${FROM_IMAGE}.al" -patch_file ${FROM_IMAGE}.ap FW_MAIN_A 0 "corrupted" -patch_file ${FROM_IMAGE}.al FW_MAIN_A 0 "corrupted" +patch_file "${FROM_IMAGE}.ap" FW_MAIN_A 0 "corrupted" +patch_file "${FROM_IMAGE}.al" FW_MAIN_A 0 "corrupted" test_update "Full update (--archive, model=link)" \ "${FROM_IMAGE}.al" "${LINK_BIOS}" \ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=link @@ -458,28 +465,28 @@ test_update "Full update (--archive, model=unknown)" \ "${FROM_IMAGE}.ap" "!Unsupported model: 'unknown'" \ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=unknown -test_update "Full update (--archive, model=whitetip, signature_id=WL)" \ +test_update "Full update (--archive, model=customtip, signature_id=CL)" \ "${FROM_IMAGE}.al" "${LINK_BIOS}" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=whitetip \ - --signature_id=whitetip-wl + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=customtip \ + --signature_id=customtip-cl -WL_TAG="wl" PATH="${A}/bin:${PATH}" \ - test_update "Full update (-a, model=WL, fake VPD)" \ +CL_TAG="cl" PATH="${A}/bin:${PATH}" \ + test_update "Full update (-a, model=customtip, fake VPD)" \ "${FROM_IMAGE}.al" "${LINK_BIOS}" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=whitetip + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=customtip -# WL-Unibuild without default keys -test_update "Full update (--a, model=WL, no VPD, no default keys)" \ - "${FROM_IMAGE}.al" "!Need VPD set for white" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=whitetip +# Custom label + Unibuild without default keys +test_update "Full update (--a, model=customtip, no VPD, no default keys)" \ + "${FROM_IMAGE}.al" "!Need VPD set for custom" \ + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=customtip -# WL-Unibuild with default keys as model name -cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.whitetip" -cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.whitetip" -cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.whitetip" -test_update "Full update (-a, model=WL, no VPD, default keys)" \ +# Custom label + Unibuild with default keys as model name +cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.customtip" +cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.customtip" +cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.customtip" +test_update "Full update (-a, model=customtip, no VPD, default keys)" \ "${FROM_IMAGE}.al" "${LINK_BIOS}" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=whitetip + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=customtip # Test special programmer if type flashrom >/dev/null 2>&1; then @@ -507,13 +514,16 @@ echo "min_platform_version=3" >"${TMP}.quirk" cp -f "${TO_IMAGE}" "${TO_IMAGE}.quirk" - ${FUTILITY} dump_fmap -x "${TO_IMAGE}" "BOOT_STUB:${TMP}.cbfs" + "${FUTILITY}" dump_fmap -x "${TO_IMAGE}" "BOOT_STUB:${TMP}.cbfs" # Create a fake CBFS using FW_MAIN_A size. truncate -s $((0x000dffc0)) "${TMP}.cbfs" - ${FUTILITY} load_fmap "${TO_IMAGE}.quirk" "FW_MAIN_A:${TMP}.cbfs" + "${FUTILITY}" load_fmap "${TO_IMAGE}.quirk" "FW_MAIN_A:${TMP}.cbfs" cbfstool "${TO_IMAGE}.quirk" add -r FW_MAIN_A -n updater_quirks \ -f "${TMP}.quirk" -t raw test_update "Full update (failure by CBFS quirks)" \ "${FROM_IMAGE}" "!Need platform version >= 3 (current is 2)" \ -i "${TO_IMAGE}.quirk" --wp=0 --sys_props 0,0x10001,1,2 fi + +rm -rf "${TMP}"* +exit 0
diff --git a/tests/gen_fuzz_test_cases.sh b/tests/gen_fuzz_test_cases.sh index 2b4255d..3e4ca99 100755 --- a/tests/gen_fuzz_test_cases.sh +++ b/tests/gen_fuzz_test_cases.sh
@@ -12,7 +12,7 @@ . "$(dirname "$0")/common.sh" # Use a different directory for fuzzing test cases. -TESTKEY_DIR=${TESTKEY_DIR:-$(realpath ${SCRIPT_DIR}/../tests/testkeys)} +TESTKEY_DIR=${TESTKEY_DIR:-$(realpath "${SCRIPT_DIR}"/../tests/testkeys)} TESTCASE_DIR=${BUILD_DIR}/fuzz_testcases TEST_IMAGE_FILE=${TESTCASE_DIR}/testimage TEST_IMAGE_SIZE=500000 @@ -26,42 +26,43 @@ echo "Generating keyblocks..." # Firmware keyblock - RSA8192/SHA512 root key, RSA4096/SHA512 firmware # signing key. - ${FUTILITY} vbutil_keyblock \ - --pack ${TESTCASE_DIR}/firmware.keyblock \ - --datapubkey ${TESTKEY_DIR}/key_rsa4096.sha512.vbpubk \ - --signprivate ${TESTKEY_DIR}/key_rsa8192.sha1.vbprivk + "${FUTILITY}" vbutil_keyblock \ + --pack "${TESTCASE_DIR}/firmware.keyblock" \ + --datapubkey "${TESTKEY_DIR}/key_rsa4096.sha512.vbpubk" \ + --signprivate "${TESTKEY_DIR}/key_rsa8192.sha1.vbprivk" # Kernel keyblock - RSA4096/SHA512 kernel signing subkey, RSA4096/SHA512 # kernel signing key. - ${FUTILITY} vbutil_keyblock \ - --pack ${TESTCASE_DIR}/kernel.keyblock \ - --datapubkey ${TESTKEY_DIR}/key_rsa4096.sha512.vbpubk \ - --signprivate ${TESTKEY_DIR}/key_rsa4096.sha1.vbprivk \ + "${FUTILITY}" vbutil_keyblock \ + --pack "${TESTCASE_DIR}/kernel.keyblock" \ + --datapubkey "${TESTKEY_DIR}/key_rsa4096.sha512.vbpubk" \ + --signprivate "${TESTKEY_DIR}/key_rsa4096.sha1.vbprivk" \ --flags 15 echo "Generating signed firmware test image..." - ${FUTILITY} vbutil_firmware \ - --vblock ${TESTCASE_DIR}/firmware.vblock \ - --keyblock ${TESTCASE_DIR}/firmware.keyblock\ - --signprivate ${TESTKEY_DIR}/key_rsa4096.sha256.vbprivk \ + "${FUTILITY}" vbutil_firmware \ + --vblock "${TESTCASE_DIR}/firmware.vblock" \ + --keyblock "${TESTCASE_DIR}/firmware.keyblock" \ + --signprivate "${TESTKEY_DIR}/key_rsa4096.sha256.vbprivk" \ --version 1 \ - --fv $1 \ - --kernelkey ${TESTKEY_DIR}/key_rsa4096.sha512.vbpubk + --fv "$1" \ + --kernelkey "${TESTKEY_DIR}/key_rsa4096.sha512.vbpubk" # TODO(gauravsh): ALso test with (optional) flags. - cp ${TESTKEY_DIR}/key_rsa8192.sha512.vbpubk ${TESTCASE_DIR}/root_key.vbpubk + cp "${TESTKEY_DIR}/key_rsa8192.sha512.vbpubk" \ + "${TESTCASE_DIR}/root_key.vbpubk" echo "Generating signed kernel test image..." - ${FUTILITY} vbutil_kernel \ - --pack ${TESTCASE_DIR}/kernel.vblock.image \ - --keyblock ${TESTCASE_DIR}/kernel.keyblock \ - --signprivate ${TESTKEY_DIR}/key_rsa4096.sha256.vbprivk \ + "${FUTILITY}" vbutil_kernel \ + --pack "${TESTCASE_DIR}/kernel.vblock.image" \ + --keyblock "${TESTCASE_DIR}/kernel.keyblock" \ + --signprivate "${TESTKEY_DIR}/key_rsa4096.sha256.vbprivk" \ --version 1 \ - --vmlinuz ${TEST_IMAGE_FILE} \ - --bootloader ${TEST_BOOTLOADER_FILE} \ - --config ${TEST_CONFIG_FILE} + --vmlinuz "${TEST_IMAGE_FILE}" \ + --bootloader "${TEST_BOOTLOADER_FILE}" \ + --config "${TEST_CONFIG_FILE}" # TODO(gauravsh): Also test with (optional) padding. - cp ${TESTKEY_DIR}/key_rsa4096.sha512.vbpubk \ - ${TESTCASE_DIR}/firmware_key.vbpubk + cp "${TESTKEY_DIR}/key_rsa4096.sha512.vbpubk" \ + "${TESTCASE_DIR}/firmware_key.vbpubk" } function pre_work { @@ -69,18 +70,17 @@ # NOTE: The kernel and config file can't really be random, but the bootloader # can. That's probably close enough. echo "Generating test image file..." - dd if=/dev/urandom of=${TEST_IMAGE_FILE} bs=${TEST_IMAGE_SIZE} count=1 + dd if=/dev/urandom of="${TEST_IMAGE_FILE}" bs="${TEST_IMAGE_SIZE}" count=1 echo "Generating test bootloader file..." # TODO(gauravsh): Use a valid bootloader here? - dd if=/dev/urandom of=${TEST_BOOTLOADER_FILE} bs=${TEST_BOOTLOADER_SIZE} \ + dd if=/dev/urandom of="${TEST_BOOTLOADER_FILE}" bs="${TEST_BOOTLOADER_SIZE}" \ count=1 echo "Generating test config file..." # TODO(gauravsh): Use a valid config file here? - dd if=/dev/urandom of=${TEST_CONFIG_FILE} bs=${TEST_CONFIG_SIZE} count=1 + dd if=/dev/urandom of="${TEST_CONFIG_FILE}" bs="${TEST_CONFIG_SIZE}" count=1 } -mkdir -p ${TESTCASE_DIR} +mkdir -p "${TESTCASE_DIR}" pre_work check_test_keys -generate_fuzzing_images ${TEST_IMAGE_FILE} - +generate_fuzzing_images "${TEST_IMAGE_FILE}"
diff --git a/tests/gen_test_cases.sh b/tests/gen_test_cases.sh index 540fc2a..80ed90c 100755 --- a/tests/gen_test_cases.sh +++ b/tests/gen_test_cases.sh
@@ -17,17 +17,17 @@ function generate_test_signatures { echo "Generating test signatures..." algorithmcounter=0 - for keylen in ${key_lengths[@]} + for keylen in "${key_lengths[@]}" do - for hashalgo in ${hash_algos[@]} + for hashalgo in "${hash_algos[@]}" do - openssl dgst -${hashalgo} -binary ${TEST_FILE} > \ - ${TEST_FILE}.${hashalgo}.digest - ${BIN_DIR}/signature_digest_utility $algorithmcounter \ - ${TEST_FILE} | openssl rsautl \ - -sign -pkcs -inkey ${TESTKEY_DIR}/key_rsa${keylen}.pem \ - > ${TEST_FILE}.rsa${keylen}_${hashalgo}.sig - let algorithmcounter=algorithmcounter+1 + openssl dgst "-${hashalgo}" -binary "${TEST_FILE}" > \ + "${TEST_FILE}.${hashalgo}.digest" + "${BIN_DIR}/signature_digest_utility" "$algorithmcounter" \ + "${TEST_FILE}" | openssl rsautl \ + -sign -pkcs -inkey "${TESTKEY_DIR}/key_rsa${keylen}.pem" \ + > "${TEST_FILE}.rsa${keylen}_${hashalgo}.sig" + algorithmcounter=$((algorithmcounter + 1)) done done } @@ -39,10 +39,10 @@ echo "(skipping, file already exists)" return fi - dd if=/dev/urandom of=${TEST_FILE} bs=${TEST_FILE_SIZE} count=1 + dd if=/dev/urandom of="${TEST_FILE}" bs="${TEST_FILE_SIZE}" count=1 } -mkdir -p ${TESTCASE_DIR} +mkdir -p "${TESTCASE_DIR}" check_test_keys generate_test_file generate_test_signatures
diff --git a/tests/gen_test_keys.sh b/tests/gen_test_keys.sh index 04315ac..37722fb 100755 --- a/tests/gen_test_keys.sh +++ b/tests/gen_test_keys.sh
@@ -17,11 +17,11 @@ function generate_keys { key_index=0 key_name_base="${TESTKEY_DIR}/key_rsa" - for i in ${key_lengths[@]} + for i in "${key_lengths[@]}" do key_base="${key_name_base}${i}" if [ -f "${key_base}.keyb" ]; then - key_index=$((${key_index} + 1)) + key_index=$((key_index + 1)) continue fi @@ -33,34 +33,33 @@ bits="${i%%_exp${exp}}" fi - openssl genrsa -${exp} -out ${key_base}.pem ${bits} + openssl genrsa "-${exp}" -out "${key_base}.pem" "${bits}" # Generate self-signed certificate from key. - openssl req -batch -new -x509 -key ${key_base}.pem \ - -out ${key_base}.crt + openssl req -batch -new -x509 -key "${key_base}.pem" \ + -out "${key_base}.crt" # Generate pre-processed key for use by RSA signature verification code. - ${BIN_DIR}/dumpRSAPublicKey -cert ${key_base}.crt \ - > ${key_base}.keyb + "${BIN_DIR}/dumpRSAPublicKey" -cert "${key_base}.crt" > "${key_base}.keyb" alg_index=0 - for sha_type in ${sha_types[@]} + for sha_type in "${sha_types[@]}" do - alg=$((${key_index} * 3 + ${alg_index})) + alg=$((key_index * 3 + alg_index)) # wrap the public key - ${FUTILITY} vbutil_key \ + "${FUTILITY}" vbutil_key \ --pack "${key_base}.sha${sha_type}.vbpubk" \ --key "${key_base}.keyb" \ --version 1 \ --algorithm ${alg} # wrap the private key - ${FUTILITY} vbutil_key \ + "${FUTILITY}" vbutil_key \ --pack "${key_base}.sha${sha_type}.vbprivk" \ --key "${key_base}.pem" \ --algorithm ${alg} - alg_index=$((${alg_index} + 1)) + alg_index=$((alg_index} + 1)) done - key_index=$((${key_index} + 1)) + key_index=$((key_index + 1)) done }
diff --git a/tests/gen_test_vbpubks.sh b/tests/gen_test_vbpubks.sh index 8ea2759..a318d3d 100755 --- a/tests/gen_test_vbpubks.sh +++ b/tests/gen_test_vbpubks.sh
@@ -11,16 +11,16 @@ function generate_vpubks { algorithmcounter=0 - for keylen in ${key_lengths[@]} + for keylen in "${key_lengths[@]}" do - for hashalgo in ${hash_algos[@]} + for hashalgo in "${hash_algos[@]}" do - ${FUTILITY} vbutil_key --pack \ - --in ${TESTKEY_DIR}/key_rsa${keylen}.keyb \ - --out ${TESTKEY_DIR}/key_rsa${keylen}.${hashalgo}.vbpubk \ + "${FUTILITY}" vbutil_key --pack \ + --in "${TESTKEY_DIR}/key_rsa${keylen}.keyb" \ + --out "${TESTKEY_DIR}/key_rsa${keylen}.${hashalgo}.vbpubk" \ --version 1 \ - --algorithm ${algorithmcounter} - let algorithmcounter=algorithmcounter+1 + --algorithm "${algorithmcounter}" + algorithmcounter=$((algorithmcounter + 1)) done done }
diff --git a/tests/gpt_misc_tests.c b/tests/gpt_misc_tests.c index e0a8d56..e7ffccf 100644 --- a/tests/gpt_misc_tests.c +++ b/tests/gpt_misc_tests.c
@@ -8,8 +8,8 @@ #include "2api.h" #include "cgptlib.h" #include "cgptlib_internal.h" +#include "common/tests.h" #include "gpt.h" -#include "test_common.h" #define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args) #define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, " calls") @@ -29,7 +29,7 @@ static int disk_read_to_fail; static int disk_write_to_fail; -static VbExDiskHandle_t handle; +static vb2ex_disk_handle_t handle; static uint8_t mock_disk[MOCK_SECTOR_SIZE * MOCK_SECTOR_COUNT]; static GptHeader *mock_gpt_primary = (GptHeader*)&mock_disk[MOCK_SECTOR_SIZE * 1]; @@ -91,7 +91,7 @@ /* Mocks */ -vb2_error_t VbExDiskRead(VbExDiskHandle_t h, uint64_t lba_start, +vb2_error_t VbExDiskRead(vb2ex_disk_handle_t h, uint64_t lba_start, uint64_t lba_count, void *buffer) { LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count); @@ -105,7 +105,7 @@ return VB2_SUCCESS; } -vb2_error_t VbExDiskWrite(VbExDiskHandle_t h, uint64_t lba_start, +vb2_error_t VbExDiskWrite(vb2ex_disk_handle_t h, uint64_t lba_start, uint64_t lba_count, const void *buffer) { LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count); @@ -207,7 +207,7 @@ * Invalidate primary GPT header and check that it is * repaired by GptRepair(). * - * This would normally be called by LoadKernel()->GptInit() + * This would normally be called by vb2api_load_kernel()->GptInit() * but this callback is mocked in these tests. */ ResetMocks(); @@ -232,7 +232,7 @@ * Invalidate secondary GPT header and check that it can be * repaired by GptRepair(). * - * This would normally be called by LoadKernel()->GptInit() + * This would normally be called by vb2api_load_kernel()->GptInit() * but this callback is mocked in these tests. */ ResetMocks();
diff --git a/tests/hmac_test.c b/tests/hmac_test.c index ed77d7b..708711f 100644 --- a/tests/hmac_test.c +++ b/tests/hmac_test.c
@@ -10,7 +10,7 @@ #include "2sha.h" #include "2hmac.h" -#include "test_common.h" +#include "common/tests.h" const char short_key[] = "key"; const char message[] = "The quick brown fox jumps over the lazy dog";
diff --git a/tests/load_kernel_tests.sh b/tests/load_kernel_tests.sh index 45eedf4..cd1bd63 100755 --- a/tests/load_kernel_tests.sh +++ b/tests/load_kernel_tests.sh
@@ -27,21 +27,21 @@ dd if=/dev/urandom bs=32768 count=1 of="dummy_kernel.bin" # Pack kernel data key using original vboot utilities. -${FUTILITY} vbutil_key --pack datakey.test \ - --key ${TESTKEY_DIR}/key_rsa2048.keyb --algorithm 4 +"${FUTILITY}" vbutil_key --pack datakey.test \ + --key "${TESTKEY_DIR}/key_rsa2048.keyb" --algorithm 4 # Keyblock with kernel data key is signed by kernel subkey # Flags=21 means dev=0 rec=0 minios=0 -${FUTILITY} vbutil_keyblock --pack keyblock.test \ +"${FUTILITY}" vbutil_keyblock --pack keyblock.test \ --datapubkey datakey.test \ --flags 21 \ - --signprivate ${SCRIPT_DIR}/devkeys/kernel_subkey.vbprivk + --signprivate "${SCRIPT_DIR}/devkeys/kernel_subkey.vbprivk" # Kernel preamble is signed with the kernel data key -${FUTILITY} vbutil_kernel \ +"${FUTILITY}" vbutil_kernel \ --pack "kernel.test" \ --keyblock "keyblock.test" \ - --signprivate ${TESTKEY_DIR}/key_rsa2048.sha256.vbprivk \ + --signprivate "${TESTKEY_DIR}/key_rsa2048.sha256.vbprivk" \ --version 1 \ --arch arm \ --vmlinuz "dummy_kernel.bin" \ @@ -51,9 +51,9 @@ echo 'Verifying test kernel' # Verify the kernel -${FUTILITY} vbutil_kernel \ +"${FUTILITY}" vbutil_kernel \ --verify "kernel.test" \ - --signpubkey ${SCRIPT_DIR}/devkeys/kernel_subkey.vbpubk + --signpubkey "${SCRIPT_DIR}/devkeys/kernel_subkey.vbpubk" happy 'Kernel verification succeeded' @@ -69,7 +69,7 @@ # And verify it using futility echo 'Verifying test disk image' -${BUILD_RUN}/tests/verify_kernel disk.test \ - ${SCRIPT_DIR}/devkeys/kernel_subkey.vbpubk +"${BUILD_RUN}/tests/verify_kernel" disk.test \ + "${SCRIPT_DIR}/devkeys/kernel_subkey.vbpubk" happy 'Image verification succeeded'
diff --git a/tests/run_cgpt_tests.sh b/tests/run_cgpt_tests.sh index 3f18624..7f59205 100755 --- a/tests/run_cgpt_tests.sh +++ b/tests/run_cgpt_tests.sh
@@ -10,27 +10,26 @@ . "$(dirname "$0")/common.sh" CGPT=$(readlink -f "$1") -[ -x "$CGPT" ] || error "Can't execute $CGPT" +[ -x ""${CGPT}"" ] || error "Can't execute $CGPT" -MTD="${@:2}" +MTD=("${@:2}") # Run tests in a dedicated directory for easy cleanup or debugging. DIR="${TEST_DIR}/cgpt_test_dir" [ -d "$DIR" ] || mkdir -p "$DIR" -warning "testing $CGPT in $DIR" +warning "testing "${CGPT}" in $DIR" cd "$DIR" assert_fail() { set +e - "$@" 2>/dev/null - if [ $? == 0 ]; then + if "$@" 2>/dev/null; then error "$*" " should have failed but did not" fi set -e } # Test failure on non existing file. -assert_fail ${CGPT} show $MTD blah_404_haha +assert_fail "${CGPT}" show "${MTD[@]}" blah_404_haha echo "Create an empty file to use as the device..." NUM_SECTORS=1000 @@ -76,264 +75,271 @@ RANDOM_DRIVE_GUID='12345678-0000-1111-2222-123456789ABC' -$CGPT create $MTD ${DEV} +"${CGPT}" create "${MTD[@]}" ${DEV} run_basic_tests() { echo "Create a bunch of partitions, using the real GUID types..." - $CGPT add $MTD -b ${DATA_START} -s ${DATA_SIZE} -t ${DATA_GUID} \ + "${CGPT}" add "${MTD[@]}" -b ${DATA_START} -s ${DATA_SIZE} -t ${DATA_GUID} \ -l "${DATA_LABEL}" ${DEV} - $CGPT add $MTD -b ${KERN_START} -s ${KERN_SIZE} -t ${KERN_GUID} \ + "${CGPT}" add "${MTD[@]}" -b ${KERN_START} -s ${KERN_SIZE} -t ${KERN_GUID} \ -l "${KERN_LABEL}" ${DEV} - $CGPT add $MTD -b ${ROOTFS_START} -s ${ROOTFS_SIZE} -t ${ROOTFS_GUID} \ - -l "${ROOTFS_LABEL}" ${DEV} - $CGPT add $MTD -b ${ESP_START} -s ${ESP_SIZE} -t ${ESP_GUID} \ + "${CGPT}" add "${MTD[@]}" -b ${ROOTFS_START} -s ${ROOTFS_SIZE} \ + -t ${ROOTFS_GUID} -l "${ROOTFS_LABEL}" ${DEV} + "${CGPT}" add "${MTD[@]}" -b ${ESP_START} -s ${ESP_SIZE} -t ${ESP_GUID} \ -l "${ESP_LABEL}" ${DEV} - $CGPT add $MTD -b ${FUTURE_START} -s ${FUTURE_SIZE} -t ${FUTURE_GUID} \ - -l "${FUTURE_LABEL}" ${DEV} - $CGPT add $MTD -b ${RANDOM_START} -s ${RANDOM_SIZE} -t ${RANDOM_GUID} \ - -l "${RANDOM_LABEL}" ${DEV} + "${CGPT}" add "${MTD[@]}" -b ${FUTURE_START} -s ${FUTURE_SIZE} \ + -t ${FUTURE_GUID} -l "${FUTURE_LABEL}" ${DEV} + "${CGPT}" add "${MTD[@]}" -b ${RANDOM_START} -s ${RANDOM_SIZE} \ + -t ${RANDOM_GUID} -l "${RANDOM_LABEL}" ${DEV} echo "Extract the start and size of given partitions..." - X=$($CGPT show $MTD -b -i $DATA_NUM ${DEV}) - Y=$($CGPT show $MTD -s -i $DATA_NUM ${DEV}) + X=$("${CGPT}" show "${MTD[@]}" -b -i $DATA_NUM ${DEV}) + Y=$("${CGPT}" show "${MTD[@]}" -s -i $DATA_NUM ${DEV}) [ "$X $Y" = "$DATA_START $DATA_SIZE" ] || error - X=$($CGPT show $MTD -b -i $KERN_NUM ${DEV}) - Y=$($CGPT show $MTD -s -i $KERN_NUM ${DEV}) + X=$("${CGPT}" show "${MTD[@]}" -b -i $KERN_NUM ${DEV}) + Y=$("${CGPT}" show "${MTD[@]}" -s -i $KERN_NUM ${DEV}) [ "$X $Y" = "$KERN_START $KERN_SIZE" ] || error - X=$($CGPT show $MTD -b -i $ROOTFS_NUM ${DEV}) - Y=$($CGPT show $MTD -s -i $ROOTFS_NUM ${DEV}) + X=$("${CGPT}" show "${MTD[@]}" -b -i $ROOTFS_NUM ${DEV}) + Y=$("${CGPT}" show "${MTD[@]}" -s -i $ROOTFS_NUM ${DEV}) [ "$X $Y" = "$ROOTFS_START $ROOTFS_SIZE" ] || error - X=$($CGPT show $MTD -b -i $ESP_NUM ${DEV}) - Y=$($CGPT show $MTD -s -i $ESP_NUM ${DEV}) + X=$("${CGPT}" show "${MTD[@]}" -b -i $ESP_NUM ${DEV}) + Y=$("${CGPT}" show "${MTD[@]}" -s -i $ESP_NUM ${DEV}) [ "$X $Y" = "$ESP_START $ESP_SIZE" ] || error - X=$($CGPT show $MTD -b -i $FUTURE_NUM ${DEV}) - Y=$($CGPT show $MTD -s -i $FUTURE_NUM ${DEV}) + X=$("${CGPT}" show "${MTD[@]}" -b -i $FUTURE_NUM ${DEV}) + Y=$("${CGPT}" show "${MTD[@]}" -s -i $FUTURE_NUM ${DEV}) [ "$X $Y" = "$FUTURE_START $FUTURE_SIZE" ] || error - X=$($CGPT show $MTD -b -i $RANDOM_NUM ${DEV}) - Y=$($CGPT show $MTD -s -i $RANDOM_NUM ${DEV}) + X=$("${CGPT}" show "${MTD[@]}" -b -i $RANDOM_NUM ${DEV}) + Y=$("${CGPT}" show "${MTD[@]}" -s -i $RANDOM_NUM ${DEV}) [ "$X $Y" = "$RANDOM_START $RANDOM_SIZE" ] || error echo "Change the beginning..." DATA_START=$((DATA_START + 10)) - $CGPT add $MTD -i 1 -b ${DATA_START} ${DEV} || error - X=$($CGPT show $MTD -b -i 1 ${DEV}) + "${CGPT}" add "${MTD[@]}" -i 1 -b ${DATA_START} ${DEV} || error + X=$("${CGPT}" show "${MTD[@]}" -b -i 1 ${DEV}) [ "$X" = "$DATA_START" ] || error echo "Change the size..." DATA_SIZE=$((DATA_SIZE + 10)) - $CGPT add $MTD -i 1 -s ${DATA_SIZE} ${DEV} || error - X=$($CGPT show $MTD -s -i 1 ${DEV}) + "${CGPT}" add "${MTD[@]}" -i 1 -s ${DATA_SIZE} ${DEV} || error + X=$("${CGPT}" show "${MTD[@]}" -s -i 1 ${DEV}) [ "$X" = "$DATA_SIZE" ] || error echo "Change the type..." - $CGPT add $MTD -i 1 -t reserved ${DEV} || error - X=$($CGPT show $MTD -t -i 1 ${DEV} | tr 'A-Z' 'a-z') + "${CGPT}" add "${MTD[@]}" -i 1 -t reserved ${DEV} || error + X=$("${CGPT}" show "${MTD[@]}" -t -i 1 ${DEV} | tr '[:upper:]' '[:lower:]') [ "$X" = "$FUTURE_GUID" ] || error # arbitrary value - $CGPT add $MTD -i 1 -t 610a563a-a55c-4ae0-ab07-86e5bb9db67f ${DEV} || error - X=$($CGPT show $MTD -t -i 1 ${DEV}) + "${CGPT}" add "${MTD[@]}" -i 1 -t 610a563a-a55c-4ae0-ab07-86e5bb9db67f \ + ${DEV} || error + X=$("${CGPT}" show "${MTD[@]}" -t -i 1 ${DEV}) [ "$X" = "610A563A-A55C-4AE0-AB07-86E5BB9DB67F" ] || error - $CGPT add $MTD -i 1 -t data ${DEV} || error - X=$($CGPT show $MTD -t -i 1 ${DEV} | tr 'A-Z' 'a-z') + "${CGPT}" add "${MTD[@]}" -i 1 -t data ${DEV} || error + X=$("${CGPT}" show "${MTD[@]}" -t -i 1 ${DEV} | tr '[:upper:]' '[:lower:]') [ "$X" = "$DATA_GUID" ] || error - ORIG_ID=$($CGPT show $MTD -v ${DEV} | \ + ORIG_ID=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | \ grep -i "disk uuid" | head -1 | awk ' { print $3 } ' ) [ ! "$ORIG_ID" = "$RANDOM_DRIVE_GUID" ] || error - $CGPT edit $MTD -u ${RANDOM_DRIVE_GUID} ${DEV} || error - X=$($CGPT show $MTD -v ${DEV} | grep -i "disk uuid" | \ + "${CGPT}" edit "${MTD[@]}" -u ${RANDOM_DRIVE_GUID} ${DEV} || error + X=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | grep -i "disk uuid" | \ head -1 | awk ' { print $3 } ' ) [ "$X" = "${RANDOM_DRIVE_GUID}" ] || error - $CGPT edit $MTD -u ${ORIG_ID} ${DEV} || error - X=$($CGPT show $MTD -v ${DEV} | grep -i "disk uuid" | \ + "${CGPT}" edit "${MTD[@]}" -u "${ORIG_ID}" ${DEV} || error + X=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | grep -i "disk uuid" | \ head -1 | awk ' { print $3 } ' ) [ "$X" = "${ORIG_ID}" ] || error } run_basic_tests -ORIG_ID=$($CGPT show $MTD -v ${DEV} | \ +ORIG_ID=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | \ grep -i "disk uuid" | awk ' { print $3 } ' ) [ ! "$ORIG_ID" = "$RANDOM_DRIVE_GUID" ] || error -$CGPT edit $MTD -u ${RANDOM_DRIVE_GUID} ${DEV} || error -X=$($CGPT show $MTD -v ${DEV} | grep -i "disk uuid" | \ +"${CGPT}" edit "${MTD[@]}" -u ${RANDOM_DRIVE_GUID} ${DEV} || error +X=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | grep -i "disk uuid" | \ head -1 | awk ' { print $3 } ' ) [ "$X" = "${RANDOM_DRIVE_GUID}" ] || error -$CGPT edit $MTD -u ${ORIG_ID} ${DEV} || error -X=$($CGPT show $MTD -v ${DEV} | grep -i "disk uuid" | \ +"${CGPT}" edit "${MTD[@]}" -u "${ORIG_ID}" ${DEV} || error +X=$("${CGPT}" show "${MTD[@]}" -v ${DEV} | grep -i "disk uuid" | \ awk ' { print $3 } ' ) [ "$X" = "${ORIG_ID}" ] || error echo "Set the boot partition.." -$CGPT boot $MTD -i ${KERN_NUM} ${DEV} >/dev/null +"${CGPT}" boot "${MTD[@]}" -i ${KERN_NUM} ${DEV} >/dev/null echo "Check the PMBR's idea of the boot partition..." -X=$($CGPT boot $MTD ${DEV}) -Y=$($CGPT show $MTD -u -i $KERN_NUM $DEV) +X=$("${CGPT}" boot "${MTD[@]}" ${DEV}) +Y=$("${CGPT}" show "${MTD[@]}" -u -i $KERN_NUM $DEV) [ "$X" = "$Y" ] || error # Input: sequence of priorities # Output: ${DEV} has kernel partitions with the given priorities make_pri() { local idx=0 - $CGPT create $MTD ${DEV} + "${CGPT}" create "${MTD[@]}" ${DEV} for pri in "$@"; do idx=$((idx+1)) - $CGPT add $MTD -t kernel -l "kern$idx" -b $((100 + 2 * $idx)) -s 1 -P $pri ${DEV} + "${CGPT}" add "${MTD[@]}" -t kernel -l "kern$idx" -b $((100 + 2 * idx)) \ + -s 1 -P $pri ${DEV} done } # Output: returns string containing priorities of all kernels get_pri() { - echo $( - for idx in $($CGPT find $MTD -t kernel ${DEV} | sed -e s@${DEV}@@); do - $CGPT show $MTD -i $idx -P ${DEV} + local output=() + for idx in $("${CGPT}" find "${MTD[@]}" -t kernel ${DEV} | sed -e s@${DEV}@@); + do + output+=("$("${CGPT}" show "${MTD[@]}" -i "$idx" -P ${DEV})") done - ) + echo "${output[@]}" } # Input: list of priorities # Operation: expects ${DEV} to contain those kernel priorities assert_pri() { local expected="$*" - local actual=$(get_pri) + local actual + actual=$(get_pri) [ "$actual" = "$expected" ] || \ error 1 "expected priority \"$expected\", actual priority \"$actual\"" } # no kernels at all. This should do nothing. -$CGPT create $MTD ${DEV} +"${CGPT}" create "${MTD[@]}" ${DEV} run_prioritize_tests() { echo "Test the cgpt prioritize command..." - $CGPT add $MTD -t rootfs -b 100 -s 1 ${DEV} - $CGPT prioritize $MTD ${DEV} + "${CGPT}" add "${MTD[@]}" -t rootfs -b 100 -s 1 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" ${DEV} assert_pri "" # common install/upgrade sequence make_pri 2 0 0 - $CGPT prioritize $MTD -i 1 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -i 1 ${DEV} assert_pri 1 0 0 - $CGPT prioritize $MTD -i 2 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -i 2 ${DEV} assert_pri 1 2 0 - $CGPT prioritize $MTD -i 1 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -i 1 ${DEV} assert_pri 2 1 0 - $CGPT prioritize $MTD -i 2 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -i 2 ${DEV} assert_pri 1 2 0 # lots of kernels, all same starting priority, should go to priority 1 make_pri 8 8 8 8 8 8 8 8 8 8 8 0 0 8 - $CGPT prioritize $MTD ${DEV} + "${CGPT}" prioritize "${MTD[@]}" ${DEV} assert_pri 1 1 1 1 1 1 1 1 1 1 1 0 0 1 # now raise them all up again - $CGPT prioritize $MTD -P 4 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -P 4 ${DEV} assert_pri 4 4 4 4 4 4 4 4 4 4 4 0 0 4 # set one of them higher, should leave the rest alone - $CGPT prioritize $MTD -P 5 -i 3 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -P 5 -i 3 ${DEV} assert_pri 4 4 5 4 4 4 4 4 4 4 4 0 0 4 # set one of them lower, should bring the rest down - $CGPT prioritize $MTD -P 3 -i 4 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -P 3 -i 4 ${DEV} assert_pri 1 1 2 3 1 1 1 1 1 1 1 0 0 1 # raise a group by including the friends of one partition - $CGPT prioritize $MTD -P 6 -i 1 -f ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -P 6 -i 1 -f ${DEV} assert_pri 6 6 4 5 6 6 6 6 6 6 6 0 0 6 # resurrect one, should not affect the others make_pri 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - $CGPT prioritize $MTD -i 2 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -i 2 ${DEV} assert_pri 0 1 0 0 0 0 0 0 0 0 0 0 0 0 # resurrect one and all its friends make_pri 0 0 0 0 0 0 0 0 1 2 0 0 0 0 - $CGPT prioritize $MTD -P 5 -i 2 -f ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -P 5 -i 2 -f ${DEV} assert_pri 5 5 5 5 5 5 5 5 3 4 5 5 5 5 # no options should maintain the same order - $CGPT prioritize $MTD ${DEV} + "${CGPT}" prioritize "${MTD[@]}" ${DEV} assert_pri 3 3 3 3 3 3 3 3 1 2 3 3 3 3 # squish all the ranks make_pri 1 1 2 2 3 3 4 4 5 5 0 6 7 7 - $CGPT prioritize $MTD -P 6 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -P 6 ${DEV} assert_pri 1 1 1 1 2 2 3 3 4 4 0 5 6 6 # squish the ranks by not leaving room make_pri 1 1 2 2 3 3 4 4 5 5 0 6 7 7 - $CGPT prioritize $MTD -P 7 -i 3 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -P 7 -i 3 ${DEV} assert_pri 1 1 7 1 2 2 3 3 4 4 0 5 6 6 # squish the ranks while bringing the friends along make_pri 1 1 2 2 3 3 4 4 5 5 0 6 7 7 - $CGPT prioritize $MTD -P 6 -i 3 -f ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -P 6 -i 3 -f ${DEV} assert_pri 1 1 6 6 1 1 2 2 3 3 0 4 5 5 # squish them pretty hard make_pri 1 1 2 2 3 3 4 4 5 5 0 6 7 7 - $CGPT prioritize $MTD -P 2 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -P 2 ${DEV} assert_pri 1 1 1 1 1 1 1 1 1 1 0 1 2 2 # squish them really really hard (nobody gets reduced to zero, though) make_pri 1 1 2 2 3 3 4 4 5 5 0 6 7 7 - $CGPT prioritize $MTD -P 1 -i 3 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -P 1 -i 3 ${DEV} assert_pri 1 1 1 1 1 1 1 1 1 1 0 1 1 1 make_pri 15 15 14 14 13 13 12 12 11 11 10 10 9 9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 0 - $CGPT prioritize $MTD -i 3 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -i 3 ${DEV} assert_pri 14 14 15 13 12 12 11 11 10 10 9 9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 1 1 0 - $CGPT prioritize $MTD -i 5 ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -i 5 ${DEV} assert_pri 13 13 14 12 15 11 10 10 9 9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 1 1 1 1 0 # but if I bring friends I don't have to squish - $CGPT prioritize $MTD -i 1 -f ${DEV} + "${CGPT}" prioritize "${MTD[@]}" -i 1 -f ${DEV} assert_pri 15 15 13 12 14 11 10 10 9 9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 1 1 1 1 0 } run_prioritize_tests echo "Test cgpt repair command" -$CGPT repair $MTD ${DEV} -($CGPT show $MTD ${DEV} | grep -q INVALID) && error +"${CGPT}" repair "${MTD[@]}" ${DEV} +("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q INVALID) && error # Zero primary header and partition table and try to repair it. dd if=/dev/zero of=${DEV} conv=notrunc bs=512 count=33 2>/dev/null -$CGPT show $MTD ${DEV} | grep -q INVALID -$CGPT repair $MTD ${DEV} -($CGPT show $MTD ${DEV} | grep -q INVALID) && error +"${CGPT}" show "${MTD[@]}" ${DEV} | grep -q INVALID +"${CGPT}" repair "${MTD[@]}" ${DEV} +("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q INVALID) && error # Zero secondary header and partition table and try to repair it. -dd if=/dev/zero of=${DEV} seek=$(($NUM_SECTORS - 33)) conv=notrunc bs=512 count=33 2>/dev/null -$CGPT show $MTD ${DEV} | grep -q INVALID -$CGPT repair $MTD ${DEV} -($CGPT show $MTD ${DEV} | grep -q INVALID) && error +dd if=/dev/zero of=${DEV} seek=$((NUM_SECTORS - 33)) conv=notrunc bs=512 \ + count=33 2>/dev/null +"${CGPT}" show "${MTD[@]}" ${DEV} | grep -q INVALID +"${CGPT}" repair "${MTD[@]}" ${DEV} +("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q INVALID) && error echo "Test with IGNOREME primary GPT..." -$CGPT create $MTD ${DEV} -$CGPT legacy $MTD -p ${DEV} -$CGPT show $MTD ${DEV} | egrep -q "IGNORED.*Pri GPT" 2>/dev/null -($CGPT show $MTD ${DEV} | grep -q "Pri GPT table" 2>/dev/null) && error -$CGPT repair $MTD ${DEV} 2>/dev/null -$CGPT show $MTD ${DEV} | egrep -q "IGNORED.*Pri GPT" 2>/dev/null -($CGPT show $MTD ${DEV} | grep -q "Pri GPT table" 2>/dev/null) && error -$CGPT legacy $MTD -e ${DEV} 2>/dev/null -($CGPT show $MTD ${DEV} | egrep -q "IGNORED.*Pri GPT") && error -$CGPT show $MTD ${DEV} | grep -q "Pri GPT table" +"${CGPT}" create "${MTD[@]}" ${DEV} +"${CGPT}" legacy "${MTD[@]}" -p ${DEV} +"${CGPT}" show "${MTD[@]}" ${DEV} | grep -q -E "IGNORED.*Pri GPT" 2>/dev/null +("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q "Pri GPT table" 2>/dev/null) && \ + error +"${CGPT}" repair "${MTD[@]}" ${DEV} 2>/dev/null +"${CGPT}" show "${MTD[@]}" ${DEV} | grep -q -E "IGNORED.*Pri GPT" 2>/dev/null +("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q "Pri GPT table" 2>/dev/null) && \ + error +"${CGPT}" legacy "${MTD[@]}" -e ${DEV} 2>/dev/null +("${CGPT}" show "${MTD[@]}" ${DEV} | grep -q -E "IGNORED.*Pri GPT") && error +"${CGPT}" show "${MTD[@]}" ${DEV} | grep -q "Pri GPT table" -$CGPT create $MTD ${DEV} -$CGPT legacy $MTD -p ${DEV} +"${CGPT}" create "${MTD[@]}" ${DEV} +"${CGPT}" legacy "${MTD[@]}" -p ${DEV} run_basic_tests 2>/dev/null -$CGPT create $MTD ${DEV} -$CGPT legacy $MTD -p ${DEV} +"${CGPT}" create "${MTD[@]}" ${DEV} +"${CGPT}" legacy "${MTD[@]}" -p ${DEV} run_prioritize_tests 2>/dev/null # Now make sure that we don't need write access if we're just looking. @@ -341,48 +347,47 @@ chmod 0444 ${DEV} # These should fail -$CGPT create $MTD -z ${DEV} 2>/dev/null && error -$CGPT add $MTD -i 2 -P 3 ${DEV} 2>/dev/null && error -$CGPT repair $MTD ${DEV} 2>/dev/null && error -$CGPT prioritize $MTD -i 3 ${DEV} 2>/dev/null && error +"${CGPT}" create "${MTD[@]}" -z ${DEV} 2>/dev/null && error +"${CGPT}" add "${MTD[@]}" -i 2 -P 3 ${DEV} 2>/dev/null && error +"${CGPT}" repair "${MTD[@]}" ${DEV} 2>/dev/null && error +"${CGPT}" prioritize "${MTD[@]}" -i 3 ${DEV} 2>/dev/null && error # Most 'boot' usage should fail too. -$CGPT boot $MTD -p ${DEV} 2>/dev/null && error +"${CGPT}" boot "${MTD[@]}" -p ${DEV} 2>/dev/null && error dd if=/dev/zero of=fake_mbr.bin bs=100 count=1 2>/dev/null -$CGPT boot $MTD -b fake_mbr.bin ${DEV} 2>/dev/null && error -$CGPT boot $MTD -i 2 ${DEV} 2>/dev/null && error +"${CGPT}" boot "${MTD[@]}" -b fake_mbr.bin ${DEV} 2>/dev/null && error +"${CGPT}" boot "${MTD[@]}" -i 2 ${DEV} 2>/dev/null && error -$CGPT boot $MTD ${DEV} >/dev/null -$CGPT show $MTD ${DEV} >/dev/null -$CGPT find $MTD -t kernel ${DEV} >/dev/null +"${CGPT}" boot "${MTD[@]}" ${DEV} >/dev/null +"${CGPT}" show "${MTD[@]}" ${DEV} >/dev/null +"${CGPT}" find "${MTD[@]}" -t kernel ${DEV} >/dev/null # Enable write access again to test boundary in off device storage chmod 600 ${DEV} # GPT too small dd if=/dev/zero of=${DEV} bs=5632 count=1 -assert_fail $CGPT create -D 1024 ${DEV} +assert_fail ""${CGPT}"" create -D 1024 ${DEV} # GPT is just right for 16 entries (512 + 512 + 16 * 128) * 2 = 6144 dd if=/dev/zero of=${DEV} bs=6144 count=1 -$CGPT create -D 1024 ${DEV} +"${CGPT}" create -D 1024 ${DEV} # Create a small 8K file to simulate Flash NOR section dd if=/dev/zero of=${DEV} bs=8K count=1 # Drive size is not multiple of 512 -assert_fail $CGPT create -D 511 ${DEV} -assert_fail $CGPT create -D 513 ${DEV} -MTD="-D 1024" +assert_fail ""${CGPT}"" create -D 511 ${DEV} +assert_fail ""${CGPT}"" create -D 513 ${DEV} # Create a GPT table for a device of 1024 bytes (2 sectors) -$CGPT create $MTD ${DEV} +"${CGPT}" create -D 1024 ${DEV} # Make sure number of entries is reasonable for 8KiB GPT -X=$($CGPT show -D 1024 -d ${DEV} | grep -c "Number of entries: 24") +X=$("${CGPT}" show -D 1024 -d ${DEV} | grep -c "Number of entries: 24") [ "$X" = "2" ] || error # This fails because header verification is off due to different drive size -assert_fail $CGPT show ${DEV} +assert_fail ""${CGPT}"" show ${DEV} # But this passes because we pass in correct drive size -$CGPT show $MTD ${DEV} +"${CGPT}" show -D 1024 ${DEV} # This fails because beginning sector is over the size of the device -assert_fail $CGPT add $MTD -b 2 -s 1 -t data ${DEV} +assert_fail ""${CGPT}"" add -D 1024 -b 2 -s 1 -t data ${DEV} # This fails because partition size is over the size of the device -assert_fail $CGPT add $MTD -b 0 -s 3 -t data ${DEV} +assert_fail ""${CGPT}"" add -D 1024 -b 0 -s 3 -t data ${DEV} echo "Done."
diff --git a/tests/run_preamble_tests.sh b/tests/run_preamble_tests.sh index 429213c..2390215 100755 --- a/tests/run_preamble_tests.sh +++ b/tests/run_preamble_tests.sh
@@ -34,10 +34,8 @@ for rr in $algs; do if [ "$r" = "$rr" ]; then what="verify" - cmp="-ne" else what="reject" - cmp="-eq" fi : $(( tests++ )) echo -n "${what} fw_${d}_${r}.vblock with root_${rr}.vbpubk ... " @@ -45,7 +43,9 @@ --verify "${V2DIR}/fw_${d}_${r}.vblock" \ --signpubkey "${DATADIR}/root_${rr}.vbpubk" \ --fv "${DATADIR}/FWDATA" >/dev/null 2>&1 - if [ "$?" "$cmp" 0 ]; then + if [[ ( $? != 0 && $what == "verify" ) || \ + ( $? == 0 && $what == "reject" ) ]] + then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else @@ -62,17 +62,17 @@ for rr in $algs; do if [ "$r" = "$rr" ]; then what="verify" - cmp="-ne" else what="reject" - cmp="-eq" fi : $(( tests++ )) echo -n "${what} kern_${d}_${r}.vblock with root_${rr}.vbpubk ... " "${FUTILITY}" vbutil_kernel \ --verify "${V2DIR}/kern_${d}_${r}.vblock" \ --signpubkey "${DATADIR}/root_${rr}.vbpubk" >/dev/null 2>&1 - if [ "$?" "$cmp" 0 ]; then + if [[ ( $? != 0 && $what == "verify" ) || \ + ( $? == 0 && $what == "reject" ) ]] + then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else @@ -88,9 +88,9 @@ for r in $algs; do : $(( tests++ )) echo -n "verify kern_${d}_${r}.vblock with hash only ... " - "${FUTILITY}" vbutil_kernel \ + if ! "${FUTILITY}" vbutil_kernel \ --verify "${V2DIR}/kern_${d}_${r}.vblock" >/dev/null 2>&1 - if [ "$?" -ne 0 ]; then + then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else
diff --git a/tests/run_vbutil_kernel_arg_tests.sh b/tests/run_vbutil_kernel_arg_tests.sh index 95317ec..6367662 100755 --- a/tests/run_vbutil_kernel_arg_tests.sh +++ b/tests/run_vbutil_kernel_arg_tests.sh
@@ -44,7 +44,7 @@ while [ "$b" -lt "${#BOOT_VALS[*]}" ]; do echo -n "pack kern_${k}_${b}.vblock ... " : $(( tests++ )) - "${FUTILITY}" vbutil_kernel \ + if ! "${FUTILITY}" vbutil_kernel \ --pack "${TMPDIR}/kern_${k}_${b}.vblock" \ --keyblock "${KEYBLOCK}" \ --signprivate "${SIGNPRIVATE}" \ @@ -53,7 +53,7 @@ --config "${CONFIG}" \ "${KERN_VALS[$k]}" \ "${BOOT_VALS[$k]}" >/dev/null - if [ "$?" -ne 0 ]; then + then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else @@ -65,12 +65,12 @@ done # Now unpack it -for v in ${TMPDIR}/kern_*.vblock; do +for v in "${TMPDIR}"/kern_*.vblock; do : $(( tests++ )) vv=$(basename "$v") echo -n "verify $vv ... " - "${FUTILITY}" vbutil_kernel --verify "$v" >/dev/null - if [ "$?" -ne 0 ]; then + if ! "${FUTILITY}" vbutil_kernel --verify "$v" >/dev/null + then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else @@ -78,9 +78,9 @@ fi : $(( tests++ )) echo -n "verify $vv signed ... " - "${FUTILITY}" vbutil_kernel --verify "$v" \ + if ! "${FUTILITY}" vbutil_kernel --verify "$v" \ --signpubkey "${SIGNPUBLIC}" >/dev/null - if [ "$?" -ne 0 ]; then + then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else @@ -100,7 +100,7 @@ USB_SIGNPUBKEY="${DEVKEYS}/recovery_key.vbpubk" echo -n "pack USB kernel ... " : $(( tests++ )) -"${FUTILITY}" vbutil_kernel \ +if ! "${FUTILITY}" vbutil_kernel \ --pack "${USB_KERN}" \ --keyblock "${USB_KEYBLOCK}" \ --signprivate "${USB_SIGNPRIVATE}" \ @@ -109,7 +109,7 @@ --bootloader "${BIG}" \ --vmlinuz "${BIG}" \ --arch arm -if [ "$?" -ne 0 ]; then +then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else @@ -119,10 +119,10 @@ # And verify it. echo -n "verify USB kernel ... " : $(( tests++ )) -"${FUTILITY}" vbutil_kernel \ +if ! "${FUTILITY}" vbutil_kernel \ --verify "${USB_KERN}" \ --signpubkey "${USB_SIGNPUBKEY}" >/dev/null -if [ "$?" -ne 0 ]; then +then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else @@ -139,13 +139,13 @@ SSD_SIGNPUBKEY="${DEVKEYS}/kernel_subkey.vbpubk" echo -n "repack to SSD kernel ... " : $(( tests++ )) -"${FUTILITY}" vbutil_kernel \ +if ! "${FUTILITY}" vbutil_kernel \ --repack "${SSD_KERN}" \ --vblockonly \ --keyblock "${SSD_KEYBLOCK}" \ --signprivate "${SSD_SIGNPRIVATE}" \ --oldblob "${TMPDIR}/usb_kern.bin" >/dev/null -if [ "$?" -ne 0 ]; then +then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else @@ -155,14 +155,14 @@ # To verify it, we have to replace the vblock from the original image. tempfile="${TMPDIR}/foo.bin" cat "${SSD_KERN}" > "$tempfile" -dd if="${USB_KERN}" bs=65536 skip=1 >> $tempfile 2>/dev/null +dd if="${USB_KERN}" bs=65536 skip=1 >> "$tempfile" 2>/dev/null echo -n "verify SSD kernel ... " : $(( tests++ )) -"${FUTILITY}" vbutil_kernel \ +if ! "${FUTILITY}" vbutil_kernel \ --verify "$tempfile" \ --signpubkey "${SSD_SIGNPUBKEY}" >/dev/null -if [ "$?" -ne 0 ]; then +then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else @@ -170,7 +170,7 @@ fi # Finally make sure that the kernel command line stays good. -orig=$(cat "${CONFIG}" | tr '\012' ' ') +orig=$(tr '\012' ' ' < "${CONFIG}") packed=$("${FUTILITY}" dump_kernel_config "${USB_KERN}") echo -n "check USB kernel config ..." : $(( tests++ )) @@ -184,7 +184,7 @@ repacked=$("${FUTILITY}" dump_kernel_config "${tempfile}") echo -n "check SSD kernel config ..." : $(( tests++ )) -if [ "$orig" != "$packed" ]; then +if [ "$orig" != "$repacked" ]; then echo -e "${COL_RED}FAILED${COL_STOP}" : $(( errs++ )) else
diff --git a/tests/run_vbutil_tests.sh b/tests/run_vbutil_tests.sh index 84f66d1..b9db2a7 100755 --- a/tests/run_vbutil_tests.sh +++ b/tests/run_vbutil_tests.sh
@@ -18,21 +18,19 @@ echo -e "For signing key ${COL_YELLOW}RSA-$keylen/$hashalgo${COL_STOP}:" # Pack the key - ${FUTILITY} vbutil_key \ - --pack ${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbpubk \ - --key ${TESTKEY_DIR}/key_rsa${keylen}.keyb \ + if ! "${FUTILITY}" vbutil_key \ + --pack "${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbpubk" \ + --key "${TESTKEY_DIR}/key_rsa${keylen}.keyb" \ --version 1 \ - --algorithm $algonum - if [ $? -ne 0 ] + --algorithm "${algonum}" then return_code=255 fi # Unpack the key # TODO: should verify we get the same key back out? - ${FUTILITY} vbutil_key \ - --unpack ${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbpubk - if [ $? -ne 0 ] + if ! "${FUTILITY}" vbutil_key \ + --unpack "${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbpubk" then return_code=255 fi @@ -40,12 +38,12 @@ function test_vbutil_key_all { algorithmcounter=0 - for keylen in ${key_lengths[@]} + for keylen in "${key_lengths[@]}" do - for hashalgo in ${hash_algos[@]} + for hashalgo in "${hash_algos[@]}" do - test_vbutil_key_single $algorithmcounter $keylen $hashalgo - let algorithmcounter=algorithmcounter+1 + test_vbutil_key_single "$algorithmcounter" "$keylen" "$hashalgo" + algorithmcounter=$((algorithmcounter + 1)) done done } @@ -72,49 +70,45 @@ keyblockfile="${TESTKEY_SCRATCH_DIR}/" keyblockfile+="sign${signing_algonum}_data" keyblockfile+="${data_algonum}.keyblock" - rm -f ${keyblockfile} + rm -f "${keyblockfile}" # Wrap private key - ${FUTILITY} vbutil_key \ - --pack ${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbprivk \ - --key ${TESTKEY_DIR}/key_rsa${signing_keylen}.pem \ - --algorithm $signing_algonum - if [ $? -ne 0 ] + if ! "${FUTILITY}" vbutil_key \ + --pack "${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbprivk" \ + --key "${TESTKEY_DIR}/key_rsa${signing_keylen}.pem" \ + --algorithm "${signing_algonum}" then echo -e "${COL_RED}Wrap vbprivk${COL_STOP}" return_code=255 fi # Wrap public key - ${FUTILITY} vbutil_key \ - --pack ${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbpubk \ - --key ${TESTKEY_DIR}/key_rsa${signing_keylen}.keyb \ - --algorithm $signing_algonum - if [ $? -ne 0 ] + if ! "${FUTILITY}" vbutil_key \ + --pack "${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbpubk" \ + --key "${TESTKEY_DIR}/key_rsa${signing_keylen}.keyb" \ + --algorithm "${signing_algonum}" then echo -e "${COL_RED}Wrap vbpubk${COL_STOP}" return_code=255 fi # Pack - ${FUTILITY} vbutil_keyblock --pack ${keyblockfile} \ + if ! "${FUTILITY}" vbutil_keyblock --pack "${keyblockfile}" \ --datapubkey \ - ${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk \ + "${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk" \ --signprivate \ - ${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbprivk - if [ $? -ne 0 ] + "${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbprivk" then echo -e "${COL_RED}Pack${COL_STOP}" return_code=255 fi # Unpack - ${FUTILITY} vbutil_keyblock --unpack ${keyblockfile} \ + if ! "${FUTILITY}" vbutil_keyblock --unpack "${keyblockfile}" \ --datapubkey \ - ${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk2 \ + "${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk2" \ --signpubkey \ - ${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbpubk - if [ $? -ne 0 ] + "${TESTKEY_SCRATCH_DIR}/key_alg${algonum}.vbpubk" then echo -e "${COL_RED}Unpack${COL_STOP}" return_code=255 @@ -122,8 +116,8 @@ # Check if ! cmp -s \ - ${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk \ - ${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk2 + "${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk" \ + "${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk2" then echo -e "${COL_RED}Check${COL_STOP}" return_code=255 @@ -134,27 +128,24 @@ external signer.${COL_STOP}" # Pack using external signer # Pack - ${FUTILITY} vbutil_keyblock --pack ${keyblockfile} \ + if ! "${FUTILITY}" vbutil_keyblock --pack "${keyblockfile}" \ --datapubkey \ - ${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk \ + "${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk" \ --signprivate_pem \ - ${TESTKEY_DIR}/key_rsa${signing_keylen}.pem \ + "${TESTKEY_DIR}/key_rsa${signing_keylen}.pem" \ --pem_algorithm "${signing_algonum}" \ --externalsigner "${SCRIPT_DIR}/external_rsa_signer.sh" - - if [ $? -ne 0 ] then echo -e "${COL_RED}Pack${COL_STOP}" return_code=255 fi # Unpack - ${FUTILITY} vbutil_keyblock --unpack ${keyblockfile} \ + if ! "${FUTILITY}" vbutil_keyblock --unpack "${keyblockfile}" \ --datapubkey \ - ${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk2 \ + "${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk2" \ --signpubkey \ - ${TESTKEY_SCRATCH_DIR}/key_alg${signing_algonum}.vbpubk - if [ $? -ne 0 ] + "${TESTKEY_SCRATCH_DIR}/key_alg${signing_algonum}.vbpubk" then echo -e "${COL_RED}Unpack${COL_STOP}" return_code=255 @@ -162,8 +153,8 @@ # Check if ! cmp -s \ - ${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk \ - ${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk2 + "${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk" \ + "${TESTKEY_SCRATCH_DIR}/key_alg${data_algonum}.vbpubk2" then echo -e "${COL_RED}Check${COL_STOP}" return_code=255 @@ -177,22 +168,22 @@ # kernel signing algorithm signing_algorithmcounter=0 data_algorithmcounter=0 - for signing_keylen in ${key_lengths[@]} + for signing_keylen in "${key_lengths[@]}" do - for signing_hashalgo in ${hash_algos[@]} + for signing_hashalgo in "${hash_algos[@]}" do - let data_algorithmcounter=0 - for datakeylen in ${key_lengths[@]} + data_algorithmcounter=0 + for datakeylen in "${key_lengths[@]}" do - for datahashalgo in ${hash_algos[@]} + for datahashalgo in "${hash_algos[@]}" do test_vbutil_keyblock_single \ - $signing_algorithmcounter $signing_keylen $signing_hashalgo \ - $data_algorithmcounter $data_keylen $data_hashalgo - let data_algorithmcounter=data_algorithmcounter+1 + "$signing_algorithmcounter" "$signing_keylen" "$signing_hashalgo" \ + "$data_algorithmcounter" "$data_keylen" "$data_hashalgo" + data_algorithmcounter=$((data_algorithmcounter + 1)) done done - let signing_algorithmcounter=signing_algorithmcounter+1 + signing_algorithmcounter=$((signing_algorithmcounter + 1)) done done } @@ -223,4 +214,3 @@ fi exit $return_code -
diff --git a/tests/sha_benchmark.c b/tests/sha_benchmark.c index 27b1c10..d7ba31a 100644 --- a/tests/sha_benchmark.c +++ b/tests/sha_benchmark.c
@@ -10,8 +10,8 @@ #include "2common.h" #include "2sha.h" #include "2sysincludes.h" +#include "common/timer_utils.h" #include "host_common.h" -#include "timer_utils.h" #define TEST_BUFFER_SIZE 4000000
diff --git a/tests/subprocess_tests.c b/tests/subprocess_tests.c index 75d6e49..d65618f 100644 --- a/tests/subprocess_tests.c +++ b/tests/subprocess_tests.c
@@ -7,7 +7,7 @@ #include <string.h> #include "subprocess.h" -#include "test_common.h" +#include "common/tests.h" #define TEST_STRING "hello world" #define TEST_STRING_LN TEST_STRING "\n"
diff --git a/tests/test_using_qemu.sh b/tests/test_using_qemu.sh index 081d963..5ed2974 100755 --- a/tests/test_using_qemu.sh +++ b/tests/test_using_qemu.sh
@@ -24,11 +24,11 @@ # Don't exit on error, so we can capture the error code set +e -sudo chroot ${SYSROOT} ${QEMU_RUN} \ +sudo chroot "${SYSROOT}" "${QEMU_RUN}" \ -E LD_LIBRARY_PATH=/lib64:/lib:/usr/lib64:/usr/lib \ - -E HOME=${HOME} \ - -E BUILD=${BUILD_RUN} \ - -- $* + -E HOME="${HOME}" \ + -E BUILD="${BUILD_RUN}" \ + -- "$@" exit_code=$? set -e
diff --git a/tests/tlcl_tests.c b/tests/tlcl_tests.c index 328abbe..62d34af 100644 --- a/tests/tlcl_tests.c +++ b/tests/tlcl_tests.c
@@ -11,8 +11,8 @@ #include <string.h> #include "2api.h" +#include "common/tests.h" #include "host_common.h" -#include "test_common.h" #include "tlcl.h" #include "tlcl_internal.h"
diff --git a/tests/tpm_lite/tpmtest_fastenable.c b/tests/tpm_lite/tpmtest_fastenable.c index a93dfd7..226a41f 100644 --- a/tests/tpm_lite/tpmtest_fastenable.c +++ b/tests/tpm_lite/tpmtest_fastenable.c
@@ -15,7 +15,7 @@ #include <stdio.h> #include "host_common.h" -#include "test_common.h" +#include "common/tests.h" #include "tlcl.h" #include "tlcl_tests.h"
diff --git a/tests/tpm_lite/tpmtest_globallock.c b/tests/tpm_lite/tpmtest_globallock.c index 14f16de..52f7c8e 100644 --- a/tests/tpm_lite/tpmtest_globallock.c +++ b/tests/tpm_lite/tpmtest_globallock.c
@@ -11,7 +11,7 @@ #include <stdlib.h> #include "host_common.h" -#include "test_common.h" +#include "common/tests.h" #include "tlcl.h" #include "tlcl_tests.h"
diff --git a/tests/tpm_lite/tpmtest_redefine_unowned.c b/tests/tpm_lite/tpmtest_redefine_unowned.c index 0f89870..45bcd93 100644 --- a/tests/tpm_lite/tpmtest_redefine_unowned.c +++ b/tests/tpm_lite/tpmtest_redefine_unowned.c
@@ -11,7 +11,7 @@ #include <stdlib.h> #include "host_common.h" -#include "test_common.h" +#include "common/tests.h" #include "tlcl.h" #include "tlcl_tests.h"
diff --git a/tests/tpm_lite/tpmtest_spaceperm.c b/tests/tpm_lite/tpmtest_spaceperm.c index 8c9232b..70f2b99 100644 --- a/tests/tpm_lite/tpmtest_spaceperm.c +++ b/tests/tpm_lite/tpmtest_spaceperm.c
@@ -11,7 +11,7 @@ #include <stdlib.h> #include "host_common.h" -#include "test_common.h" +#include "common/tests.h" #include "tlcl.h" #include "tlcl_tests.h"
diff --git a/tests/tpm_lite/tpmtest_writelimit.c b/tests/tpm_lite/tpmtest_writelimit.c index 05e4a17..71562b0 100644 --- a/tests/tpm_lite/tpmtest_writelimit.c +++ b/tests/tpm_lite/tpmtest_writelimit.c
@@ -12,7 +12,7 @@ #include "2common.h" #include "host_common.h" -#include "test_common.h" +#include "common/tests.h" #include "tlcl.h" #include "tlcl_tests.h"
diff --git a/tests/vb20_api_kernel_tests.c b/tests/vb20_api_kernel_tests.c index b835251..bc585b4 100644 --- a/tests/vb20_api_kernel_tests.c +++ b/tests/vb20_api_kernel_tests.c
@@ -14,7 +14,7 @@ #include "2rsa.h" #include "2secdata.h" #include "2sysincludes.h" -#include "test_common.h" +#include "common/tests.h" #include "vboot_struct.h" /* Common context for tests */
diff --git a/tests/vb20_kernel_tests.c b/tests/vb20_kernel_tests.c index 8766114..05f21ab 100644 --- a/tests/vb20_kernel_tests.c +++ b/tests/vb20_kernel_tests.c
@@ -14,7 +14,7 @@ #include "2rsa.h" #include "2secdata.h" #include "2sysincludes.h" -#include "test_common.h" +#include "common/tests.h" /* Common context for tests */ static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
diff --git a/tests/vb20_rsa_padding_tests.c b/tests/vb20_rsa_padding_tests.c index 90ff42a..68c32a9 100644 --- a/tests/vb20_rsa_padding_tests.c +++ b/tests/vb20_rsa_padding_tests.c
@@ -9,10 +9,10 @@ #include "2common.h" #include "2rsa.h" #include "2sysincludes.h" +#include "common/tests.h" #include "file_keys.h" #include "host_key.h" #include "rsa_padding_test.h" -#include "test_common.h" vb2_error_t hwcrypto_modexp_return_value = VB2_SUCCESS; vb2_error_t vb2ex_hwcrypto_modexp(const struct vb2_public_key *key,
diff --git a/tests/vb21_host_common2_tests.c b/tests/vb21_host_common2_tests.c index b2ceb95..61ba986 100644 --- a/tests/vb21_host_common2_tests.c +++ b/tests/vb21_host_common2_tests.c
@@ -12,11 +12,11 @@ #include "2common.h" #include "2rsa.h" #include "2sysincludes.h" +#include "common/tests.h" #include "host_common.h" #include "host_common21.h" #include "host_key21.h" #include "host_signature21.h" -#include "test_common.h" #include "util_misc.h" static const uint8_t test_data[] = "This is some test data to sign.";
diff --git a/tests/vb21_host_common_tests.c b/tests/vb21_host_common_tests.c index 3ab5dbc..385a0c2 100644 --- a/tests/vb21_host_common_tests.c +++ b/tests/vb21_host_common_tests.c
@@ -8,10 +8,10 @@ #include "2common.h" #include "2rsa.h" #include "2sysincludes.h" +#include "common/tests.h" #include "host_common21.h" #include "host_key21.h" #include "host_signature21.h" -#include "test_common.h" static const uint8_t test_data[] = "This is some test data to sign.";
diff --git a/tests/vb21_host_key_tests.c b/tests/vb21_host_key_tests.c index e8eef9b..e0a1105 100644 --- a/tests/vb21_host_key_tests.c +++ b/tests/vb21_host_key_tests.c
@@ -11,10 +11,10 @@ #include "2common.h" #include "2rsa.h" #include "2sysincludes.h" +#include "common/tests.h" #include "host_common.h" #include "host_common21.h" #include "host_key21.h" -#include "test_common.h" /* Test only the algorithms we use */ struct alg_combo {
diff --git a/tests/vb21_host_misc_tests.c b/tests/vb21_host_misc_tests.c index f437803..dbf12e0 100644 --- a/tests/vb21_host_misc_tests.c +++ b/tests/vb21_host_misc_tests.c
@@ -10,10 +10,10 @@ #include "2common.h" #include "2sysincludes.h" +#include "common/tests.h" #include "host_common.h" #include "host_common21.h" #include "host_misc.h" -#include "test_common.h" static void misc_tests(void) {
diff --git a/tests/vb21_host_sig_tests.c b/tests/vb21_host_sig_tests.c index f337eaa..4a9abff 100644 --- a/tests/vb21_host_sig_tests.c +++ b/tests/vb21_host_sig_tests.c
@@ -11,11 +11,11 @@ #include "2common.h" #include "2rsa.h" #include "2sysincludes.h" +#include "common/tests.h" #include "host_common.h" #include "host_common21.h" #include "host_key21.h" #include "host_signature21.h" -#include "test_common.h" /* Test only the algorithms we use */ struct alg_combo {
diff --git a/tests/vb2_api_tests.c b/tests/vb2_api_tests.c index 15c9bd1..ca2f7e9 100644 --- a/tests/vb2_api_tests.c +++ b/tests/vb2_api_tests.c
@@ -14,7 +14,7 @@ #include "2rsa.h" #include "2secdata.h" #include "2sysincludes.h" -#include "test_common.h" +#include "common/tests.h" /* Common context for tests */ @@ -135,8 +135,10 @@ vb2_error_t vb2_check_dev_switch(struct vb2_context *c) { - if (force_dev_mode) + if (force_dev_mode) { + c->flags |= VB2_CONTEXT_DEVELOPER_MODE; sd->flags |= VB2_SD_FLAG_DEV_MODE_ENABLED; + } return retval_vb2_check_dev_switch; }
diff --git a/tests/vb2_auxfw_sync_tests.c b/tests/vb2_auxfw_sync_tests.c index bcdd67a..b9c869a 100644 --- a/tests/vb2_auxfw_sync_tests.c +++ b/tests/vb2_auxfw_sync_tests.c
@@ -13,9 +13,8 @@ #include "2misc.h" #include "2nvstorage.h" #include "2sysincludes.h" +#include "common/tests.h" #include "host_common.h" -#include "load_kernel_fw.h" -#include "test_common.h" #include "vboot_struct.h" /* Mock data */ @@ -25,7 +24,8 @@ static struct vb2_shared_data *sd; static struct vb2_gbb_header gbb; -static vb2_error_t auxfw_retval; +static vb2_error_t auxfw_check_retval; +static vb2_error_t auxfw_update_retval; static int auxfw_update_req; static enum vb2_auxfw_update_severity auxfw_mock_severity; static enum vb2_auxfw_update_severity auxfw_update_severity; @@ -46,7 +46,8 @@ memset(&gbb, 0, sizeof(gbb)); - auxfw_retval = VB2_SUCCESS; + auxfw_check_retval = VB2_SUCCESS; + auxfw_update_retval = VB2_SUCCESS; auxfw_mock_severity = VB2_AUXFW_NO_UPDATE; auxfw_update_severity = VB2_AUXFW_NO_UPDATE; auxfw_mock_display_available = 1; @@ -65,7 +66,7 @@ { *severity = auxfw_mock_severity; auxfw_update_severity = auxfw_mock_severity; - return VB2_SUCCESS; + return auxfw_check_retval; } vb2_error_t vb2ex_auxfw_update(void) @@ -77,7 +78,7 @@ if (auxfw_update_severity != VB2_AUXFW_NO_DEVICE && auxfw_update_severity != VB2_AUXFW_NO_UPDATE) auxfw_update_req = 1; - return auxfw_retval; + return auxfw_update_retval; } vb2_error_t vb2ex_auxfw_finalize(struct vb2_context *c) @@ -152,7 +153,13 @@ ResetMocks(); auxfw_mock_severity = VB2_AUXFW_FAST_UPDATE; - auxfw_retval = VB2_ERROR_UNKNOWN; + auxfw_check_retval = VB2_ERROR_UNKNOWN; + test_auxsync(VB2_ERROR_UNKNOWN, VB2_RECOVERY_AUXFW_UPDATE, + "Error checking auxfw"); + + ResetMocks(); + auxfw_mock_severity = VB2_AUXFW_FAST_UPDATE; + auxfw_update_retval = VB2_ERROR_UNKNOWN; test_auxsync(VB2_ERROR_UNKNOWN, VB2_RECOVERY_AUXFW_UPDATE, "Error updating auxfw"); }
diff --git a/tests/vb2_common2_tests.c b/tests/vb2_common2_tests.c index 5f065f8..e793e57 100644 --- a/tests/vb2_common2_tests.c +++ b/tests/vb2_common2_tests.c
@@ -12,10 +12,10 @@ #include "2common.h" #include "2rsa.h" #include "2sysincludes.h" +#include "common/tests.h" #include "file_keys.h" #include "host_common.h" #include "host_key21.h" -#include "test_common.h" static const uint8_t test_data[] = "This is some test data to sign."; static const uint32_t test_size = sizeof(test_data);
diff --git a/tests/vb2_common3_tests.c b/tests/vb2_common3_tests.c index 5805204..8e7a20c 100644 --- a/tests/vb2_common3_tests.c +++ b/tests/vb2_common3_tests.c
@@ -10,12 +10,12 @@ #include "2common.h" #include "2rsa.h" #include "2sysincludes.h" +#include "common/tests.h" #include "file_keys.h" #include "host_common.h" #include "host_keyblock.h" #include "host_key.h" #include "host_signature.h" -#include "test_common.h" static void resign_keyblock(struct vb2_keyblock *h, const struct vb2_private_key *key)
diff --git a/tests/vb2_common_tests.c b/tests/vb2_common_tests.c index d76c402..beb8461 100644 --- a/tests/vb2_common_tests.c +++ b/tests/vb2_common_tests.c
@@ -7,7 +7,7 @@ #include "2common.h" #include "2sysincludes.h" -#include "test_common.h" +#include "common/tests.h" #include "vboot_struct.h" /* For old struct sizes */ /* Mock data */
diff --git a/tests/vb2_crypto_tests.c b/tests/vb2_crypto_tests.c index c7d6676..6696feb 100644 --- a/tests/vb2_crypto_tests.c +++ b/tests/vb2_crypto_tests.c
@@ -12,7 +12,7 @@ #include "2rsa.h" #include "2sha.h" #include "2sysincludes.h" -#include "test_common.h" +#include "common/tests.h" #include "vboot_host.h" static void hash_algorithm_name_tests(void)
diff --git a/tests/vb2_ec_sync_tests.c b/tests/vb2_ec_sync_tests.c index f4631b7..f317561 100644 --- a/tests/vb2_ec_sync_tests.c +++ b/tests/vb2_ec_sync_tests.c
@@ -10,9 +10,8 @@ #include "2nvstorage.h" #include "2secdata.h" #include "2sysincludes.h" +#include "common/tests.h" #include "host_common.h" -#include "load_kernel_fw.h" -#include "test_common.h" #include "vboot_struct.h" /* Mock data */
diff --git a/tests/vb2_firmware_tests.c b/tests/vb2_firmware_tests.c index 681e5d6..933f608 100644 --- a/tests/vb2_firmware_tests.c +++ b/tests/vb2_firmware_tests.c
@@ -14,7 +14,7 @@ #include "2rsa.h" #include "2secdata.h" #include "2sysincludes.h" -#include "test_common.h" +#include "common/tests.h" /* Common context for tests */ static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
diff --git a/tests/vb2_firmware_tests.sh b/tests/vb2_firmware_tests.sh index 88b6e6a..51803e2 100755 --- a/tests/vb2_firmware_tests.sh +++ b/tests/vb2_firmware_tests.sh
@@ -50,34 +50,41 @@ local fw_algo=$2 local kern_algo=$3 - local root_rsa="$(algo_to_rsa ${root_algo})" - local fw_rsa="$(algo_to_rsa ${fw_algo})" - local kern_rsa="$(algo_to_rsa ${kern_algo})" + local root_rsa + local fw_rsa + local kern_rsa + root_rsa="$(algo_to_rsa "${root_algo}")" + fw_rsa="$(algo_to_rsa "${fw_algo}")" + kern_rsa="$(algo_to_rsa "${kern_algo}")" - local root_sha="$(algo_to_sha ${root_algo})" - local fw_sha="$(algo_to_sha ${fw_algo})" - local kern_sha="$(algo_to_sha ${kern_algo})" + local root_sha + local fw_sha + root_sha="$(algo_to_sha "${root_algo}")" + fw_sha="$(algo_to_sha "${fw_algo}")" # Pack keys using original vboot utilities - ${FUTILITY} vbutil_key --pack rootkey.test \ - --key "${TESTKEY_DIR}/key_${root_rsa}.keyb" --algorithm ${root_algo} - ${FUTILITY} vbutil_key --pack fwsubkey.test \ - --key "${TESTKEY_DIR}/key_${fw_rsa}.keyb" --algorithm ${fw_algo} - ${FUTILITY} vbutil_key --pack kernkey.test \ - --key "${TESTKEY_DIR}/key_${kern_rsa}.keyb" --algorithm ${kern_algo} + "${FUTILITY}" vbutil_key --pack rootkey.test \ + --key "${TESTKEY_DIR}/key_${root_rsa}.keyb" \ + --algorithm "${root_algo}" + "${FUTILITY}" vbutil_key --pack fwsubkey.test \ + --key "${TESTKEY_DIR}/key_${fw_rsa}.keyb" \ + --algorithm "${fw_algo}" + "${FUTILITY}" vbutil_key --pack kernkey.test \ + --key "${TESTKEY_DIR}/key_${kern_rsa}.keyb" \ + --algorithm "${kern_algo}" # Create a GBB with the root key - ${FUTILITY} gbb -c 128,2400,0,0 gbb.test - ${FUTILITY} gbb gbb.test -s --hwid='Test GBB' \ + "${FUTILITY}" gbb -c 128,2400,0,0 gbb.test + "${FUTILITY}" gbb gbb.test -s --hwid='Test GBB' \ --rootkey=rootkey.test # Keyblock with firmware subkey is signed by root key - ${FUTILITY} vbutil_keyblock --pack keyblock.test \ + "${FUTILITY}" vbutil_keyblock --pack keyblock.test \ --datapubkey fwsubkey.test \ --signprivate "${TESTKEY_DIR}/key_${root_rsa}.${root_sha}.vbprivk" # Firmware preamble is signed with the firmware subkey - ${FUTILITY} vbutil_firmware \ + "${FUTILITY}" vbutil_firmware \ --vblock vblock.test \ --keyblock keyblock.test \ --signprivate "${TESTKEY_DIR}/key_${fw_rsa}.${fw_sha}.vbprivk" \ @@ -89,7 +96,7 @@ "(root=${root_algo}, fw=${fw_algo}, kernel=${kern_algo})" # Verify the firmware using vboot2 checks - ${BUILD_RUN}/tests/vb20_verify_fw gbb.test vblock.test body.test + "${BUILD_RUN}/tests/vb20_verify_fw" gbb.test vblock.test body.test happy 'vb2_verify_fw succeeded' }
diff --git a/tests/vb2_gbb_tests.c b/tests/vb2_gbb_tests.c index 047fa42..51ebcf6 100644 --- a/tests/vb2_gbb_tests.c +++ b/tests/vb2_gbb_tests.c
@@ -7,7 +7,7 @@ #include "2common.h" #include "2misc.h" -#include "test_common.h" +#include "common/tests.h" /* Mock data */ static char gbb_data[4096 + sizeof(struct vb2_gbb_header)];
diff --git a/tests/vb2_host_flashrom_tests.c b/tests/vb2_host_flashrom_tests.c index 815657d..7cebc5e 100644 --- a/tests/vb2_host_flashrom_tests.c +++ b/tests/vb2_host_flashrom_tests.c
@@ -18,10 +18,10 @@ #include "2common.h" #include "2return_codes.h" +#include "common/tests.h" #include "host_misc.h" #include "flashrom.h" #include "subprocess.h" -#include "test_common.h" #define MOCK_TMPFILE_NAME "/tmp/vb2_unittest" #define MOCK_ROM_CONTENTS "bloop123"
diff --git a/tests/vb2_host_key_tests.c b/tests/vb2_host_key_tests.c index 82dd357..9c6fe28 100644 --- a/tests/vb2_host_key_tests.c +++ b/tests/vb2_host_key_tests.c
@@ -6,8 +6,8 @@ */ #include "2common.h" +#include "common/tests.h" #include "host_common.h" -#include "test_common.h" /* Public key utility functions */ static void public_key_tests(void)
diff --git a/tests/vb2_host_nvdata_flashrom_tests.c b/tests/vb2_host_nvdata_flashrom_tests.c index 068b23a..719f1d1 100644 --- a/tests/vb2_host_nvdata_flashrom_tests.c +++ b/tests/vb2_host_nvdata_flashrom_tests.c
@@ -17,9 +17,9 @@ #include "2constants.h" #include "2nvstorage.h" #include "2return_codes.h" +#include "common/tests.h" #include "crossystem_vbnv.h" #include "flashrom.h" -#include "test_common.h" /* Mocked flashrom only supports host programmer, and RW_NVRAM region. */
diff --git a/tests/vb2_kernel_tests.c b/tests/vb2_kernel_tests.c index 0b3e94c..6d32eb2 100644 --- a/tests/vb2_kernel_tests.c +++ b/tests/vb2_kernel_tests.c
@@ -7,15 +7,13 @@ #include "2api.h" #include "2common.h" -#include "2kernel.h" #include "2misc.h" #include "2nvstorage.h" #include "2rsa.h" #include "2secdata.h" #include "2sysincludes.h" -#include "test_common.h" -#include "vboot_struct.h" -#include "vboot_api.h" +#include "common/boot_mode.h" +#include "common/tests.h" /* Common context for tests */ static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] @@ -24,7 +22,7 @@ static struct vb2_shared_data *sd; static struct vb2_fw_preamble *fwpre; static const char fw_kernel_key_data[36] = "Test kernel key data"; -static enum vb2_boot_mode *boot_mode; +static struct vb2_kernel_params kparams; /* Mocked function data */ @@ -36,14 +34,19 @@ static int mock_read_res_fail_on_call; static int mock_secdata_fwmp_check_retval; -static int mock_vbtlk_expect_fixed; -static int mock_vbtlk_expect_removable; -static vb2_error_t mock_vbtlk_retval; +static int mock_commit_data_called; +static int mock_ec_sync_called; +static int mock_ec_sync_retval; +static int mock_battery_cutoff_called; +static int mock_kernel_flag; +static int mock_kernel_flag_set; +static int mock_kernel_version; /* Type of test to reset for */ enum reset_type { FOR_PHASE1, - FOR_NORMAL_BOOT, + FOR_PHASE2, + FOR_FINALIZE, }; static void reset_common_data(enum reset_type t) @@ -52,22 +55,23 @@ memset(workbuf, 0xaa, sizeof(workbuf)); + memset(&kparams, 0, sizeof(kparams)); + TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx), "vb2api_init failed"); sd = vb2_get_sd(ctx); vb2_nv_init(ctx); - vb2api_secdata_kernel_create(ctx); - vb2_secdata_kernel_init(ctx); - vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS, 0x20002); - mock_read_res_fail_on_call = 0; mock_secdata_fwmp_check_retval = VB2_SUCCESS; - mock_vbtlk_expect_fixed = 0; - mock_vbtlk_expect_removable = 0; - mock_vbtlk_retval = VB2_SUCCESS; - + mock_commit_data_called = 0; + mock_ec_sync_called = 0; + mock_ec_sync_retval = VB2_SUCCESS; + mock_battery_cutoff_called = 0; + mock_kernel_flag = 0; + mock_kernel_flag_set = 0; + mock_kernel_version = 0x10002; /* Recovery key in mock GBB */ memset(&mock_gbb, 0, sizeof(mock_gbb)); @@ -82,15 +86,8 @@ mock_gbb.h.recovery_key_size = mock_gbb.recovery_key.key_offset + mock_gbb.recovery_key.key_size; - - /* For boot_mode */ - boot_mode = (enum vb2_boot_mode *)&ctx->boot_mode; - if (t == FOR_PHASE1) - *boot_mode = VB2_BOOT_MODE_BROKEN_SCREEN; - else if (t == FOR_NORMAL_BOOT) - *boot_mode = VB2_BOOT_MODE_NORMAL; - else - *boot_mode = VB2_BOOT_MODE_UNDEFINED; + mock_gbb.h.major_version = VB2_GBB_MAJOR_VER; + mock_gbb.h.minor_version = VB2_GBB_MINOR_VER; if (t == FOR_PHASE1) { uint8_t *kdata; @@ -108,6 +105,11 @@ sd->preamble_size = sizeof(*fwpre) + k->key_size; vb2_set_workbuf_used(ctx, sd->preamble_offset + sd->preamble_size); + } else if (t == FOR_FINALIZE) { + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); + vb2_nv_set(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0xffffffff); + sd->kernel_version_secdata = mock_kernel_version; + sd->kernel_version = mock_kernel_version; } }; @@ -118,6 +120,34 @@ return mock_secdata_fwmp_check_retval; } +vb2_error_t vb2api_ec_sync(struct vb2_context *c) +{ + mock_ec_sync_called = 1; + return mock_ec_sync_retval; +} + +vb2_error_t vb2api_auxfw_sync(struct vb2_context *c) +{ + return VB2_SUCCESS; +} + +vb2_error_t vb2ex_ec_battery_cutoff(void) +{ + TEST_EQ(mock_ec_sync_called, 1, + " battery cutoff must happen after EC sync"); + mock_battery_cutoff_called = 1; + return VB2_SUCCESS; +} + +const uint8_t *vb2_secdata_kernel_get_ec_hash(struct vb2_context *c) +{ + /* + * Return NULL to prevent EC reboot due to + * VB2_SD_FLAG_ECSYNC_HMIR_UPDATED. + */ + return NULL; +} + struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) { return &mock_gbb.h; @@ -149,24 +179,41 @@ return VB2_SUCCESS; } -vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t disk_flags) +vb2_error_t vb2ex_commit_data(struct vb2_context *c) { - /* - * TODO: Currently we don't have a good way of testing for an ordered - * sequence of VB_DISK_FLAG_FIXED and then VB_DISK_FLAG_REMOVABLE. If - * both are set, then just assume success. - */ - if (mock_vbtlk_expect_fixed && mock_vbtlk_expect_removable) - return mock_vbtlk_retval; + mock_commit_data_called = 1; + return VB2_SUCCESS; +} - TEST_EQ(!!mock_vbtlk_expect_fixed, - !!(disk_flags & VB_DISK_FLAG_FIXED), - " VbTryLoadKernel unexpected fixed disk call"); - TEST_EQ(!!mock_vbtlk_expect_removable, - !!(disk_flags & VB_DISK_FLAG_REMOVABLE), - " VbTryLoadKernel unexpected removable disk call"); +void vb2_secdata_kernel_set(struct vb2_context *c, + enum vb2_secdata_kernel_param param, + uint32_t value) +{ + switch (param) { + case VB2_SECDATA_KERNEL_FLAGS: + mock_kernel_flag = value; + mock_kernel_flag_set = 1; + break; + case VB2_SECDATA_KERNEL_VERSIONS: + mock_kernel_version = value; + break; + default: + vb2ex_abort(); + } +} - return mock_vbtlk_retval; +uint32_t vb2_secdata_kernel_get(struct vb2_context *c, + enum vb2_secdata_kernel_param param) +{ + switch (param) { + case VB2_SECDATA_KERNEL_FLAGS: + return mock_kernel_flag; + case VB2_SECDATA_KERNEL_VERSIONS: + return mock_kernel_version; + default: + vb2ex_abort(); + } + return 0; } /* Tests */ @@ -178,6 +225,7 @@ /* Test successful call */ reset_common_data(FOR_PHASE1); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 good"); /* Make sure normal key was loaded */ TEST_EQ(sd->kernel_key_offset, sd->preamble_offset + @@ -194,12 +242,12 @@ TEST_EQ(k->key_size, sizeof(fw_kernel_key_data), " key_size"); TEST_EQ(memcmp((uint8_t *)k + k->key_offset, fw_kernel_key_data, k->key_size), 0, " key data"); - TEST_EQ(sd->kernel_version_secdata, 0x20002, + TEST_EQ(sd->kernel_version_secdata, 0x10002, " secdata_kernel version"); /* Test successful call in recovery mode */ reset_common_data(FOR_PHASE1); - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_BROKEN_SCREEN, 123); /* No preamble needed in recovery mode */ sd->workbuf_used = sd->preamble_offset; sd->preamble_offset = sd->preamble_size = 0; @@ -220,12 +268,12 @@ TEST_EQ(memcmp((uint8_t *)k + k->key_offset, mock_gbb.recovery_key_data, k->key_size), 0, " key data"); - TEST_EQ(sd->kernel_version_secdata, 0x20002, + TEST_EQ(sd->kernel_version_secdata, 0x10002, " secdata_kernel version"); /* Test flags for experimental features in non-recovery path */ reset_common_data(FOR_PHASE1); - ctx->flags &= ~VB2_CONTEXT_RECOVERY_MODE; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 non-rec good"); /* Make sure phone recovery functionality is enabled, but UI disabled */ TEST_EQ(vb2api_phone_recovery_enabled(ctx), 1, @@ -239,26 +287,15 @@ /* * Test flags are unchanged for experimental features in recovery path */ - - /* Set 8 bits to 0 */ reset_common_data(FOR_PHASE1); - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; - vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS, 0); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_BROKEN_SCREEN, 123); TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 rec good"); - TEST_EQ(vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_FLAGS), 0, - "VB2_SECDATA_KERNEL_FLAGS remains unchanged in recovery path"); - - /* Set 8 bits to 1 */ - reset_common_data(FOR_PHASE1); - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; - vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS, UINT8_MAX); - TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 rec good"); - TEST_EQ(vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_FLAGS), - UINT8_MAX, + TEST_EQ(mock_kernel_flag_set, 0, "VB2_SECDATA_KERNEL_FLAGS remains unchanged in recovery path"); /* Bad secdata_fwmp causes failure in normal mode only */ reset_common_data(FOR_PHASE1); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); mock_secdata_fwmp_check_retval = VB2_ERROR_SECDATA_FWMP_CRC; TEST_EQ(vb2api_kernel_phase1(ctx), mock_secdata_fwmp_check_retval, "phase1 bad secdata_fwmp"); @@ -266,15 +303,15 @@ VB2_RECOVERY_SECDATA_FWMP_INIT, " recovery reason"); reset_common_data(FOR_PHASE1); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_BROKEN_SCREEN, 123); mock_secdata_fwmp_check_retval = VB2_ERROR_SECDATA_FWMP_CRC; - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 bad secdata_fwmp rec"); TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), VB2_RECOVERY_NOT_REQUESTED, " no recovery"); /* Failures while reading recovery key */ reset_common_data(FOR_PHASE1); - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_BROKEN_SCREEN, 123); mock_gbb.h.recovery_key_size = sd->workbuf_size - 1; mock_gbb.recovery_key.key_size = mock_gbb.h.recovery_key_size - sizeof(mock_gbb.recovery_key); @@ -282,60 +319,179 @@ "phase1 rec workbuf key"); TEST_EQ(sd->kernel_key_offset, 0, " workbuf key offset"); TEST_EQ(sd->kernel_key_size, 0, " workbuf key size"); - mock_gbb.h.flags |= VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY; - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); TEST_ABORT(vb2api_kernel_phase1(ctx), " fatal for manual recovery"); reset_common_data(FOR_PHASE1); - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_BROKEN_SCREEN, 123); mock_read_res_fail_on_call = 1; TEST_EQ(vb2api_kernel_phase1(ctx), VB2_SUCCESS, "phase1 rec gbb read key"); TEST_EQ(sd->kernel_key_offset, 0, " workbuf key offset"); TEST_EQ(sd->kernel_key_size, 0, " workbuf key size"); - mock_gbb.h.flags |= VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY; - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); mock_read_res_fail_on_call = 1; TEST_ABORT(vb2api_kernel_phase1(ctx), " fatal for manual recovery"); /* Failures while parsing subkey from firmware preamble */ reset_common_data(FOR_PHASE1); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); sd->preamble_size = 0; TEST_EQ(vb2api_kernel_phase1(ctx), VB2_ERROR_API_KPHASE1_PREAMBLE, "phase1 fw preamble"); } -static void normal_boot_tests(void) +static void phase2_tests(void) { - reset_common_data(FOR_NORMAL_BOOT); - mock_vbtlk_expect_fixed = 1; - TEST_EQ(vb2_normal_boot(ctx), VB2_SUCCESS, - "vb2_normal_boot() returns VB2_SUCCESS"); + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); + TEST_SUCC(vb2api_kernel_phase2(ctx), "Normal mode"); + TEST_EQ(mock_ec_sync_called, 1, " EC sync"); - reset_common_data(FOR_NORMAL_BOOT); - mock_vbtlk_expect_fixed = 1; - mock_vbtlk_retval = VB2_ERROR_MOCK; - TEST_EQ(vb2_normal_boot(ctx), VB2_ERROR_MOCK, - "vb2_normal_boot() returns VB2_ERROR_MOCK"); - - reset_common_data(FOR_NORMAL_BOOT); + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 1); - TEST_EQ(vb2_normal_boot(ctx), VB2_REQUEST_REBOOT, - "vb2_normal_boot() reboot to reset NVRAM display request"); + TEST_EQ(vb2api_kernel_phase2(ctx), VB2_REQUEST_REBOOT, + "Normal mode with display request: rebooting"); TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST), 0, " display request reset"); - reset_common_data(FOR_NORMAL_BOOT); + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); + TEST_SUCC(vb2api_kernel_phase2(ctx), "Developer mode"); + TEST_EQ(mock_ec_sync_called, 1, " EC sync"); + + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DIAGNOSTICS); + TEST_SUCC(vb2api_kernel_phase2(ctx), "Diagnostics mode"); + TEST_EQ(mock_ec_sync_called, 1, " EC sync"); + + /* Commit data for recovery mode */ + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); + TEST_SUCC(vb2api_kernel_phase2(ctx), "Manual recovery mode"); + TEST_EQ(mock_commit_data_called, 1, " commit data"); + TEST_EQ(mock_ec_sync_called, 0, " EC sync"); + + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_BROKEN_SCREEN, 123); + TEST_SUCC(vb2api_kernel_phase2(ctx), "Broken screen mode"); + TEST_EQ(mock_commit_data_called, 1, " commit data"); + TEST_EQ(mock_ec_sync_called, 0, " EC sync"); + + /* Boot recovery - memory retraining */ + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_TRAIN_AND_REBOOT); + TEST_EQ(vb2api_kernel_phase2(ctx), VB2_REQUEST_REBOOT, + "Recovery train and reboot"); + + /* Clear VB2_NV_DIAG_REQUEST */ + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1); - TEST_EQ(vb2_normal_boot(ctx), VB2_REQUEST_REBOOT, - "vb2_normal_boot() reboot to reset NVRAM diag request"); + TEST_SUCC(vb2api_kernel_phase2(ctx), "Normal mode with DIAG_REQUEST"); TEST_EQ(vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST), 0, - " diag request reset");} + " clear VB2_NV_DIAG_REQUEST"); + TEST_EQ(mock_commit_data_called, 1, " commit data"); + + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DIAGNOSTICS); + vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1); + TEST_SUCC(vb2api_kernel_phase2(ctx), "Diagnostics mode"); + TEST_EQ(vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST), 0, + " clear VB2_NV_DIAG_REQUEST"); + TEST_EQ(mock_commit_data_called, 1, " commit data"); + + /* Battery cutoff called after EC sync */ + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); + vb2_nv_set(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST, 1); + TEST_EQ(vb2api_kernel_phase2(ctx), VB2_REQUEST_SHUTDOWN, + "Set VB2_NV_BATTERY_CUTOFF_REQUEST"); + TEST_EQ(mock_battery_cutoff_called, 1, + " battery_cutoff called after EC sync"); + + /* Return EC sync error */ + reset_common_data(FOR_PHASE2); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); + mock_ec_sync_retval = VB2_ERROR_MOCK; + TEST_EQ(vb2api_kernel_phase2(ctx), VB2_ERROR_MOCK, + "Return EC sync error"); + + /* Undefined boot mode */ + reset_common_data(FOR_PHASE2); + TEST_EQ(vb2api_kernel_phase2(ctx), VB2_ERROR_ESCAPE_NO_BOOT, + "Undefined boot mode"); +} + +static void finalize_tests(void) +{ + /* Kernel version roll forward */ + reset_common_data(FOR_FINALIZE); + sd->kernel_version = 0x20003; + TEST_EQ(vb2api_kernel_finalize(ctx), VB2_SUCCESS, + "Kernel version roll forward"); + TEST_EQ(mock_kernel_version, 0x20003, " kernel version"); + + reset_common_data(FOR_FINALIZE); + vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_TRYING); + sd->kernel_version = 0x20003; + TEST_EQ(vb2api_kernel_finalize(ctx), VB2_SUCCESS, + "Don't roll forward kernel when trying new FW"); + TEST_EQ(mock_kernel_version, 0x10002, " kernel version"); + + reset_common_data(FOR_FINALIZE); + vb2_nv_set(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0x30005); + sd->kernel_version = 0x40006; + TEST_EQ(vb2api_kernel_finalize(ctx), VB2_SUCCESS, + "Limit max roll forward"); + TEST_EQ(mock_kernel_version, 0x30005, " kernel version"); + + reset_common_data(FOR_FINALIZE); + vb2_nv_set(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0x10001); + sd->kernel_version = 0x40006; + TEST_EQ(vb2api_kernel_finalize(ctx), VB2_SUCCESS, + "Max roll forward can't rollback"); + TEST_EQ(mock_kernel_version, 0x10002, " kernel version"); + + /* NO_BOOT with EC sync support */ + reset_common_data(FOR_FINALIZE); + ctx->flags |= VB2_CONTEXT_NO_BOOT; + ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED; + TEST_EQ(vb2api_kernel_finalize(ctx), VB2_ERROR_ESCAPE_NO_BOOT, + "Recovery for NO_BOOT escape"); + TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), + VB2_RECOVERY_ESCAPE_NO_BOOT, " recovery_reason"); + + /* NO_BOOT with EC sync disabled */ + reset_common_data(FOR_FINALIZE); + ctx->flags |= VB2_CONTEXT_NO_BOOT; + ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED; + mock_gbb.h.flags |= VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC; + TEST_SUCC(vb2api_kernel_finalize(ctx), + "NO_BOOT ignored with gbb DISABLE_EC_SOFTWARE_SYNC"); + + /* Normal case with EC sync support */ + reset_common_data(FOR_FINALIZE); + ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED; + TEST_SUCC(vb2api_kernel_finalize(ctx), "Disable VB2_CONTEXT_NO_BOOT"); + + /* NO_BOOT without EC sync support */ + reset_common_data(FOR_FINALIZE); + ctx->flags |= VB2_CONTEXT_NO_BOOT; + TEST_SUCC(vb2api_kernel_finalize(ctx), + "Disable VB2_CONTEXT_EC_SYNC_SUPPORTED"); +} int main(int argc, char* argv[]) { phase1_tests(); - normal_boot_tests(); + phase2_tests(); + finalize_tests(); return gTestSuccess ? 0 : 255; }
diff --git a/tests/vb2_keyblock_fuzzer.c b/tests/vb2_keyblock_fuzzer.c index 2aa83e1..cd211c4 100644 --- a/tests/vb2_keyblock_fuzzer.c +++ b/tests/vb2_keyblock_fuzzer.c
@@ -9,7 +9,6 @@ #include "2rsa.h" #include "2rsa_private.h" #include "2secdata.h" -#include "vboot_test.h" static struct vb2_context *ctx; static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
diff --git a/tests/vboot_kernel2_tests.c b/tests/vb2_load_kernel2_tests.c similarity index 78% rename from tests/vboot_kernel2_tests.c rename to tests/vb2_load_kernel2_tests.c index 5fc66f1..dfb06fb 100644 --- a/tests/vboot_kernel2_tests.c +++ b/tests/vb2_load_kernel2_tests.c
@@ -10,8 +10,8 @@ #include "2misc.h" #include "2nvstorage.h" #include "2secdata.h" -#include "load_kernel_fw.h" -#include "test_common.h" +#include "common/boot_mode.h" +#include "common/tests.h" #include "vboot_api.h" #define MAX_MOCK_KERNELS 10 @@ -20,7 +20,7 @@ /* Internal struct to simulate a stream for sector-based disks */ struct disk_stream { /* Disk handle */ - VbExDiskHandle_t handle; + vb2ex_disk_handle_t handle; /* Next sector to read */ uint64_t sector; @@ -47,10 +47,9 @@ static struct vb2_workbuf wb; static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] __attribute__((aligned(VB2_WORKBUF_ALIGN))); -static enum vb2_boot_mode *boot_mode; -static VbSelectAndLoadKernelParams lkp; -static VbDiskInfo disk_info; +static struct vb2_kernel_params lkp; +static struct vb2_disk_info disk_info; static struct vb2_keyblock kbh; static struct vb2_kernel_preamble kph; static uint8_t kernel_buffer[80000]; @@ -59,8 +58,6 @@ static int kernel_count; static struct mock_kernel *cur_kernel; -static int mock_tpm_set_mode_calls; - static void add_mock_kernel(uint64_t sector, vb2_error_t rv) { if (kernel_count >= ARRAY_SIZE(kernels)) { @@ -83,8 +80,8 @@ vb2_secdata_kernel_init(ctx); ctx->flags = VB2_CONTEXT_RECOVERY_MODE; - boot_mode = (enum vb2_boot_mode *)&ctx->boot_mode; - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); sd = vb2_get_sd(ctx); sd->kernel_version_secdata = 0xabcdef | (1 << 24); @@ -92,12 +89,11 @@ memset(&lkp, 0, sizeof(lkp)); lkp.kernel_buffer = kernel_buffer; lkp.kernel_buffer_size = sizeof(kernel_buffer); - lkp.disk_handle = (VbExDiskHandle_t)1; memset(&disk_info, 0, sizeof(disk_info)); disk_info.bytes_per_lba = 512; disk_info.lba_count = 1024; - disk_info.handle = lkp.disk_handle; + disk_info.handle = (vb2ex_disk_handle_t)1; memset(&kbh, 0, sizeof(kbh)); kbh.data_key.key_version = 2; @@ -118,13 +114,11 @@ memset(&kernels, 0, sizeof(kernels)); kernel_count = 0; cur_kernel = NULL; - - mock_tpm_set_mode_calls = 0; } /* Mocks */ -vb2_error_t VbExStreamOpen(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExStreamOpen(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, VbExStream_t *stream) { struct disk_stream *s; @@ -248,12 +242,6 @@ return cur_kernel->rv; } -vb2_error_t vb2ex_tpm_set_mode(enum vb2_tpm_mode mode_val) -{ - mock_tpm_set_mode_calls++; - return VB2_SUCCESS; -} - /* Make sure nothing tested here ever calls this directly. */ void vb2api_fail(struct vb2_context *c, uint8_t reason, uint8_t subcode) { @@ -268,55 +256,57 @@ disk_info.bytes_per_lba = KBUF_SIZE; disk_info.lba_count = 1; add_mock_kernel(0, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "{valid kernel}"); - TEST_EQ(mock_tpm_set_mode_calls, 1, - " TPM disabled"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); disk_info.bytes_per_lba = KBUF_SIZE; disk_info.lba_count = 1; - TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), VB2_ERROR_LK_NO_KERNEL_FOUND, "{no kernel}"); - TEST_EQ(mock_tpm_set_mode_calls, 0, - " TPM not disabled"); reset_common_data(); disk_info.bytes_per_lba = KBUF_SIZE; disk_info.lba_count = 2; add_mock_kernel(1, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "{no kernel, valid kernel}"); TEST_EQ(cur_kernel->sector, 1, " select kernel"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); disk_info.bytes_per_lba = KBUF_SIZE; disk_info.lba_count = 2; add_mock_kernel(0, VB2_ERROR_MOCK); add_mock_kernel(1, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "{invalid kernel, valid kernel}"); TEST_EQ(cur_kernel->sector, 1, " select second kernel"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); disk_info.bytes_per_lba = KBUF_SIZE; disk_info.lba_count = 2; add_mock_kernel(0, VB2_ERROR_MOCK); add_mock_kernel(1, VB2_ERROR_MOCK); - TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), VB2_ERROR_LK_NO_KERNEL_FOUND, "{invalid kernel, invalid kernel}"); - TEST_EQ(mock_tpm_set_mode_calls, 0, - " TPM not disabled"); reset_common_data(); disk_info.bytes_per_lba = KBUF_SIZE; disk_info.lba_count = 2; add_mock_kernel(0, VB2_SUCCESS); add_mock_kernel(1, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "{valid kernel, valid kernel} minios_priority=0"); TEST_EQ(cur_kernel->sector, 0, " select first kernel"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); disk_info.bytes_per_lba = KBUF_SIZE; @@ -324,19 +314,23 @@ add_mock_kernel(0, VB2_SUCCESS); add_mock_kernel(1, VB2_SUCCESS); vb2_nv_set(ctx, VB2_NV_MINIOS_PRIORITY, 1); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "{valid kernel, valid kernel} minios_priority=1"); TEST_EQ(cur_kernel->sector, 1, " select second kernel"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); disk_info.bytes_per_lba = KBUF_SIZE; disk_info.lba_count = 2; add_mock_kernel(0, VB2_SUCCESS); add_mock_kernel(1, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, - VB_MINIOS_FLAG_NON_ACTIVE), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, + VB2_MINIOS_FLAG_NON_ACTIVE), "{valid kernel, valid kernel} minios_priority=0 non-active"); TEST_EQ(cur_kernel->sector, 1, " select second kernel"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); disk_info.bytes_per_lba = KBUF_SIZE; @@ -344,8 +338,8 @@ add_mock_kernel(0, VB2_ERROR_MOCK); add_mock_kernel(1, VB2_SUCCESS); vb2_nv_set(ctx, VB2_NV_MINIOS_PRIORITY, 1); - TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, - VB_MINIOS_FLAG_NON_ACTIVE), + TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, + VB2_MINIOS_FLAG_NON_ACTIVE), VB2_ERROR_LK_NO_KERNEL_FOUND, "{invalid kernel, valid kernel} minios_priority=1 non-active"); @@ -353,7 +347,7 @@ disk_info.bytes_per_lba = VB2_KEYBLOCK_MAGIC_SIZE; disk_info.lba_count = 4; add_mock_kernel(1, VB2_SUCCESS); - TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), VB2_ERROR_LK_NO_KERNEL_FOUND, "valid kernel header near start of disk (disk too small)"); @@ -361,7 +355,7 @@ disk_info.bytes_per_lba = VB2_KEYBLOCK_MAGIC_SIZE; disk_info.lba_count = 1000; add_mock_kernel(999, VB2_SUCCESS); - TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), VB2_ERROR_LK_NO_KERNEL_FOUND, "valid kernel header near end of disk"); @@ -369,36 +363,46 @@ disk_info.bytes_per_lba = 1024; disk_info.lba_count = 128; add_mock_kernel(63, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "start/end overlap assuming >128 MB search range (start)"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); disk_info.bytes_per_lba = 1024; disk_info.lba_count = 128; add_mock_kernel(64, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "start/end overlap assuming >128 MB search range (end)"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); disk_info.bytes_per_lba = 128; disk_info.lba_count = 1024; add_mock_kernel(3, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "kernel at last sector in batch assuming 512 KB batches"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); disk_info.bytes_per_lba = 256; disk_info.lba_count = 1024; add_mock_kernel(3, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "kernel at last sector in batch assuming 1 MB batches"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); disk_info.bytes_per_lba = 512; disk_info.lba_count = 1024; add_mock_kernel(3, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "kernel at last sector in batch assuming 2 MB batches"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_DEVELOPER_0 @@ -407,8 +411,10 @@ disk_info.bytes_per_lba = KBUF_SIZE; disk_info.lba_count = 2; add_mock_kernel(0, VB2_SUCCESS); - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), "kernel with minios keyblock flag"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); reset_common_data(); kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_DEVELOPER_0 @@ -417,7 +423,7 @@ disk_info.bytes_per_lba = KBUF_SIZE; disk_info.lba_count = 2; add_mock_kernel(0, VB2_SUCCESS); - TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), VB2_ERROR_LK_NO_KERNEL_FOUND, "kernel with !minios keyblock flag"); @@ -427,7 +433,7 @@ add_mock_kernel(0, VB2_SUCCESS); sd->kernel_version_secdata = 5 << 24; kph.kernel_version = 4; - TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), VB2_ERROR_LK_NO_KERNEL_FOUND, "kernel version too old"); @@ -437,7 +443,7 @@ add_mock_kernel(0, VB2_SUCCESS); sd->kernel_version_secdata = 5 << 24; kph.kernel_version = 0x100; - TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), + TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), VB2_ERROR_LK_NO_KERNEL_FOUND, "kernel version greater than 0xff"); @@ -447,8 +453,10 @@ add_mock_kernel(0, VB2_SUCCESS); sd->kernel_version_secdata = 5 << 24; kph.kernel_version = 6; - TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0), - "newer kernel version"); + TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0), + "newer kernel version"); + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); } int main(void)
diff --git a/tests/vboot_kernel_tests.c b/tests/vb2_load_kernel_tests.c similarity index 66% rename from tests/vboot_kernel_tests.c rename to tests/vb2_load_kernel_tests.c index 1f77cc5..bb6f348 100644 --- a/tests/vboot_kernel_tests.c +++ b/tests/vb2_load_kernel_tests.c
@@ -13,9 +13,9 @@ #include "2secdata_struct.h" #include "cgptlib.h" #include "cgptlib_internal.h" +#include "common/boot_mode.h" +#include "common/tests.h" #include "gpt.h" -#include "load_kernel_fw.h" -#include "test_common.h" #include "vboot_api.h" /* Mock kernel partition */ @@ -40,8 +40,8 @@ static int gpt_flag_external; static struct vb2_gbb_header gbb; -static VbSelectAndLoadKernelParams lkp; -static VbDiskInfo disk_info; +static struct vb2_kernel_params lkp; +static struct vb2_disk_info disk_info; static struct vb2_keyblock kbh; static struct vb2_kernel_preamble kph; static struct vb2_secdata_fwmp *fwmp; @@ -51,7 +51,6 @@ static struct vb2_context *ctx; static struct vb2_shared_data *sd; static struct vb2_packed_key mock_key; -static enum vb2_boot_mode *boot_mode; /** * Reset mock data (for use before each test) @@ -76,13 +75,12 @@ memset(&lkp, 0, sizeof(lkp)); lkp.kernel_buffer = kernel_buffer; lkp.kernel_buffer_size = sizeof(kernel_buffer); - lkp.disk_handle = (VbExDiskHandle_t)1; memset(&disk_info, 0, sizeof(disk_info)); disk_info.bytes_per_lba = 512; disk_info.streaming_lba_count = 1024; disk_info.lba_count = 1024; - disk_info.handle = lkp.disk_handle; + disk_info.handle = (vb2ex_disk_handle_t)1; memset(&kbh, 0, sizeof(kbh)); kbh.data_key.key_version = 2; @@ -115,8 +113,7 @@ fwmp = (struct vb2_secdata_fwmp *)ctx->secdata_fwmp; memcpy(&fwmp->dev_key_hash, mock_digest, sizeof(fwmp->dev_key_hash)); - boot_mode = (enum vb2_boot_mode *)&ctx->boot_mode; - *boot_mode = VB2_BOOT_MODE_NORMAL; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); // TODO: more workbuf fields - flags, secdata_firmware @@ -156,7 +153,7 @@ return VB2_SUCCESS; } -vb2_error_t VbExDiskRead(VbExDiskHandle_t h, uint64_t lba_start, +vb2_error_t VbExDiskRead(vb2ex_disk_handle_t h, uint64_t lba_start, uint64_t lba_count, void *buffer) { if ((int)lba_start == disk_read_to_fail) @@ -165,7 +162,7 @@ return VB2_SUCCESS; } -int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata) +int AllocAndReadGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata) { return GPT_SUCCESS; } @@ -197,7 +194,7 @@ return GPT_SUCCESS; } -int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata) +int WriteAndFreeGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata) { return GPT_SUCCESS; } @@ -279,31 +276,34 @@ TEST_TRUE(0, " called vb2api_fail()"); } -static void TestLoadKernel(int expect_retval, const char *test_name) +static void test_load_kernel(vb2_error_t expect_retval, const char *test_name) { - TEST_EQ(LoadKernel(ctx, &lkp, &disk_info), expect_retval, test_name); + TEST_EQ(vb2api_load_kernel(ctx, &lkp, &disk_info), expect_retval, + test_name); + if (expect_retval == VB2_SUCCESS) + TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, + " fill disk_handle when success"); } /** - * Trivial invalid calls to LoadKernel() + * Trivial invalid calls to vb2api_load_kernel() */ -static void InvalidParamsTest(void) +static void invalid_params_tests(void) { ResetMocks(); gpt_init_fail = 1; - TestLoadKernel(VB2_ERROR_LK_NO_KERNEL_FOUND, "Bad GPT"); + test_load_kernel(VB2_ERROR_LK_NO_KERNEL_FOUND, "Bad GPT"); /* This causes the stream open call to fail */ ResetMocks(); - lkp.disk_handle = NULL; disk_info.handle = NULL; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad disk handle"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad disk handle"); } -static void LoadKernelTest(void) +static void load_kernel_tests(void) { ResetMocks(); - TestLoadKernel(0, "First kernel good"); + test_load_kernel(VB2_SUCCESS, "First kernel good"); TEST_EQ(lkp.partition_number, 1, " part num"); TEST_EQ(lkp.bootloader_address, 0xbeadd008, " bootloader addr"); TEST_EQ(lkp.bootloader_size, 0x1234, " bootloader size"); @@ -314,312 +314,311 @@ ResetMocks(); mock_parts[1].start = 300; mock_parts[1].size = 150; - TestLoadKernel(0, "Two good kernels"); + test_load_kernel(VB2_SUCCESS, "Two good kernels"); TEST_EQ(lkp.partition_number, 1, " part num"); TEST_EQ(mock_part_next, 1, " didn't read second one"); /* Fail if no kernels found */ ResetMocks(); mock_parts[0].size = 0; - TestLoadKernel(VB2_ERROR_LK_NO_KERNEL_FOUND, "No kernels"); + test_load_kernel(VB2_ERROR_LK_NO_KERNEL_FOUND, "No kernels"); /* Skip kernels which are too small */ ResetMocks(); mock_parts[0].size = 10; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Too small"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Too small"); ResetMocks(); disk_read_to_fail = 100; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Fail reading kernel start"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Fail reading kernel start"); ResetMocks(); keyblock_verify_fail = 1; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Fail key block sig"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Fail key block sig"); /* In dev mode, fail if hash is bad too */ ResetMocks(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); keyblock_verify_fail = 2; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Fail key block dev hash"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Fail key block dev hash"); /* But just bad sig is ok */ ResetMocks(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); keyblock_verify_fail = 1; - TestLoadKernel(0, "Succeed keyblock dev sig"); + test_load_kernel(VB2_SUCCESS, "Succeed keyblock dev sig"); TEST_EQ(sd->flags & VB2_SD_FLAG_KERNEL_SIGNED, 0, " use hash"); /* In dev mode and requiring signed kernel, fail if sig is bad */ ResetMocks(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1); keyblock_verify_fail = 1; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Fail key block dev sig"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Fail key block dev sig"); ResetMocks(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY; keyblock_verify_fail = 1; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Fail key block dev sig fwmp"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Fail key block dev sig fwmp"); /* Check keyblock flags */ ResetMocks(); kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0 | VB2_KEYBLOCK_FLAG_DEVELOPER_1 | VB2_KEYBLOCK_FLAG_MINIOS_0; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock dev flag mismatch"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock dev flag mismatch"); ResetMocks(); kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | VB2_KEYBLOCK_FLAG_MINIOS_0; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock rec flag mismatch"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock rec flag mismatch"); ResetMocks(); kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0 | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | VB2_KEYBLOCK_FLAG_MINIOS_1; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock minios flag mismatch"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock minios flag mismatch"); ResetMocks(); - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_1 | VB2_KEYBLOCK_FLAG_MINIOS_0; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock recdev flag mismatch"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock recdev flag mismatch"); ResetMocks(); - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | VB2_KEYBLOCK_FLAG_MINIOS_0; - TestLoadKernel(0, "Keyblock rec flag okay"); + test_load_kernel(VB2_SUCCESS, "Keyblock rec flag okay"); ResetMocks(); - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE | VB2_CONTEXT_DEVELOPER_MODE; - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); + ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | VB2_KEYBLOCK_FLAG_MINIOS_0; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock rec!dev flag mismatch"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock rec!dev flag mismatch"); ResetMocks(); - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE | VB2_CONTEXT_DEVELOPER_MODE; - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); + ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_1 | VB2_KEYBLOCK_FLAG_MINIOS_0; - TestLoadKernel(0, "Keyblock recdev flag okay"); + test_load_kernel(VB2_SUCCESS, "Keyblock recdev flag okay"); /* Check keyblock flags (dev mode + signed kernel required) */ ResetMocks(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1); kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | VB2_KEYBLOCK_FLAG_MINIOS_0; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock dev flag mismatch (signed kernel required)"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock dev flag mismatch (signed kernel required)"); ResetMocks(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY; kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | VB2_KEYBLOCK_FLAG_MINIOS_0; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock dev flag mismatch (signed kernel required)"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock dev flag mismatch (signed kernel required)"); ResetMocks(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY; kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0 | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | VB2_KEYBLOCK_FLAG_MINIOS_1; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock dev flag mismatch (signed kernel required)"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock dev flag mismatch (signed kernel required)"); ResetMocks(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1); kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0 | VB2_KEYBLOCK_FLAG_DEVELOPER_1 | VB2_KEYBLOCK_FLAG_MINIOS_0; - TestLoadKernel(0, "Keyblock dev flag okay (signed kernel required)"); + test_load_kernel(VB2_SUCCESS, + "Keyblock dev flag okay (signed kernel required)"); /* Check kernel key version */ ResetMocks(); kbh.data_key.key_version = 1; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock kernel key rollback"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock kernel key rollback"); ResetMocks(); kbh.data_key.key_version = 0x10000; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock kernel key version too big"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock kernel key version too big"); ResetMocks(); kbh.data_key.key_version = 3; - TestLoadKernel(0, "Keyblock version roll forward"); + test_load_kernel(VB2_SUCCESS, "Keyblock version roll forward"); TEST_EQ(sd->kernel_version, 0x30001, " SD version"); ResetMocks(); kbh.data_key.key_version = 3; mock_parts[1].start = 300; mock_parts[1].size = 150; - TestLoadKernel(0, "Two kernels roll forward"); + test_load_kernel(VB2_SUCCESS, "Two kernels roll forward"); TEST_EQ(mock_part_next, 2, " read both"); TEST_EQ(sd->kernel_version, 0x30001, " SD version"); ResetMocks(); kbh.data_key.key_version = 1; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; - TestLoadKernel(0, "Key version ignored in dev mode"); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); + test_load_kernel(VB2_SUCCESS, "Key version ignored in dev mode"); ResetMocks(); kbh.data_key.key_version = 1; - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; - TestLoadKernel(0, "Key version ignored in rec mode"); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); + test_load_kernel(VB2_SUCCESS, "Key version ignored in rec mode"); ResetMocks(); unpack_key_fail = 2; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad data key"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad data key"); ResetMocks(); preamble_verify_fail = 1; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad preamble"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad preamble"); ResetMocks(); kph.kernel_version = 0; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Kernel version rollback"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Kernel version rollback"); ResetMocks(); kph.kernel_version = 0; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; - TestLoadKernel(0, "Kernel version ignored in dev mode"); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); + test_load_kernel(VB2_SUCCESS, "Kernel version ignored in dev mode"); ResetMocks(); kph.kernel_version = 0; - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; - TestLoadKernel(0, "Kernel version ignored in rec mode"); + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); + test_load_kernel(VB2_SUCCESS, "Kernel version ignored in rec mode"); /* Check kernel version (dev mode + signed kernel required) */ ResetMocks(); kbh.data_key.key_version = 0; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1); - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock key version checked in dev mode " - "(signed kernel required)"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock key version checked in dev mode " + "(signed kernel required)"); ResetMocks(); kbh.data_key.key_version = 0; - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Keyblock key version checked in dev mode " - "(signed kernel required)"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Keyblock key version checked in dev mode " + "(signed kernel required)"); /* Check developer key hash - bad */ ResetMocks(); - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH; fwmp->dev_key_hash[0]++; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Fail keyblock dev fwmp hash"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Fail keyblock dev fwmp hash"); /* Check developer key hash - bad (recovery mode) */ ResetMocks(); - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH; fwmp->dev_key_hash[0]++; - TestLoadKernel(0, "Bad keyblock dev fwmp hash ignored in rec mode"); + test_load_kernel(VB2_SUCCESS, + "Bad keyblock dev fwmp hash ignored in rec mode"); /* Check developer key hash - good */ ResetMocks(); - *boot_mode = VB2_BOOT_MODE_DEVELOPER; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH; - TestLoadKernel(0, "Good keyblock dev fwmp hash"); + test_load_kernel(VB2_SUCCESS, "Good keyblock dev fwmp hash"); ResetMocks(); kph.preamble_size |= 0x07; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Kernel body offset"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Kernel body offset"); ResetMocks(); kph.preamble_size += 65536; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Kernel body offset huge"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Kernel body offset huge"); /* Check getting kernel load address from header */ ResetMocks(); kph.body_load_address = (size_t)kernel_buffer; lkp.kernel_buffer = NULL; - TestLoadKernel(0, "Get load address from preamble"); + test_load_kernel(VB2_SUCCESS, "Get load address from preamble"); TEST_PTR_EQ(lkp.kernel_buffer, kernel_buffer, " address"); /* Size is rounded up to nearest sector */ TEST_EQ(lkp.kernel_buffer_size, 70144, " size"); ResetMocks(); lkp.kernel_buffer_size = 8192; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Kernel too big for buffer"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Kernel too big for buffer"); ResetMocks(); mock_parts[0].size = 130; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Kernel too big for partition"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Kernel too big for partition"); ResetMocks(); kph.body_signature.data_size = 8192; - TestLoadKernel(0, "Kernel tiny"); + test_load_kernel(VB2_SUCCESS, "Kernel tiny"); ResetMocks(); disk_read_to_fail = 228; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, - "Fail reading kernel data"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, + "Fail reading kernel data"); ResetMocks(); verify_data_fail = 1; - TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad data"); + test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad data"); /* Check that EXTERNAL_GPT flag makes it down */ ResetMocks(); - disk_info.flags |= VB_DISK_FLAG_EXTERNAL_GPT; - TestLoadKernel(0, "Succeed external GPT"); + disk_info.flags |= VB2_DISK_FLAG_EXTERNAL_GPT; + test_load_kernel(VB2_SUCCESS, "Succeed external GPT"); TEST_EQ(gpt_flag_external, 1, "GPT was external"); /* Check recovery from unreadble primary GPT */ ResetMocks(); disk_read_to_fail = 1; - TestLoadKernel(0, "Can't read disk"); + test_load_kernel(VB2_SUCCESS, "Can't read disk"); } int main(void) { - InvalidParamsTest(); - LoadKernelTest(); + invalid_params_tests(); + load_kernel_tests(); return gTestSuccess ? 0 : 255; }
diff --git a/tests/vb2_misc2_tests.c b/tests/vb2_misc2_tests.c new file mode 100644 index 0000000..403e2f6 --- /dev/null +++ b/tests/vb2_misc2_tests.c
@@ -0,0 +1,128 @@ +/* Copyright 2022 The ChromiumOS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Tests for vb2_set_boot_mode. + */ + +#include "2api.h" +#include "2common.h" +#include "2misc.h" +#include "2nvstorage.h" +#include "common/tests.h" + +/* Mock data */ + +static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] + __attribute__((aligned(VB2_WORKBUF_ALIGN))); +static struct vb2_context *ctx; +static struct vb2_shared_data *sd; +static struct vb2_gbb_header gbb; + +static int mock_diagnostic_ui_enabled; + +/* Mock functions */ + +struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) +{ + return &gbb; +} + +int vb2api_diagnostic_ui_enabled(struct vb2_context *c) +{ + return mock_diagnostic_ui_enabled; +} + +static void reset_common_data(void) +{ + memset(workbuf, 0xaa, sizeof(workbuf)); + + memset(&gbb, 0, sizeof(gbb)); + + TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx), + "vb2api_init failed"); + sd = vb2_get_sd(ctx); + + vb2_nv_init(ctx); + + mock_diagnostic_ui_enabled = 0; +} + +static void set_boot_mode_tests(void) +{ + /* Normal boot */ + reset_common_data(); + vb2_set_boot_mode(ctx); + TEST_EQ(ctx->boot_mode, VB2_BOOT_MODE_NORMAL, "Normal boot"); + + /* Check that NV_DIAG_REQUEST triggers diagnostic mode */ + reset_common_data(); + mock_diagnostic_ui_enabled = 1; + vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1); + vb2_set_boot_mode(ctx); + TEST_EQ(ctx->boot_mode, VB2_BOOT_MODE_DIAGNOSTICS, + "Normal boot with diag UI enabled"); + + reset_common_data(); + vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1); + vb2_set_boot_mode(ctx); + TEST_EQ(ctx->boot_mode, VB2_BOOT_MODE_NORMAL, + "Normal boot with diag UI disabled"); + + /* Developer boot */ + reset_common_data(); + ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; + sd->flags |= VB2_SD_FLAG_DEV_MODE_ENABLED; + vb2_set_boot_mode(ctx); + TEST_EQ(ctx->boot_mode, VB2_BOOT_MODE_DEVELOPER, "Dev boot"); + + /* Recovery boot */ + reset_common_data(); + sd->recovery_reason = 123; + ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; + vb2_set_boot_mode(ctx); + TEST_EQ(ctx->boot_mode, VB2_BOOT_MODE_BROKEN_SCREEN, "Broken screen"); + + reset_common_data(); + sd->recovery_reason = VB2_RECOVERY_RO_MANUAL; + ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; + gbb.flags |= VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY; + vb2_set_boot_mode(ctx); + TEST_EQ(ctx->boot_mode, VB2_BOOT_MODE_MANUAL_RECOVERY, + "Manual recovery: forced by GBB flags"); + + reset_common_data(); + sd->recovery_reason = VB2_RECOVERY_RO_MANUAL; + ctx->flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE; + ctx->flags |= VB2_CONTEXT_EC_TRUSTED; + vb2_set_boot_mode(ctx); + TEST_EQ(ctx->boot_mode, VB2_BOOT_MODE_MANUAL_RECOVERY, + "Manual recovery: physical rec switch"); + + reset_common_data(); + ctx->flags |= VB2_CONTEXT_EC_TRUSTED; + vb2_set_boot_mode(ctx); + TEST_NEQ(ctx->boot_mode, VB2_BOOT_MODE_MANUAL_RECOVERY, + "VB2_CONTEXT_FORCE_RECOVERY_MODE is not set"); + + reset_common_data(); + ctx->flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE; + ctx->flags |= VB2_CONTEXT_NO_BOOT; + ctx->flags |= VB2_CONTEXT_EC_TRUSTED; + vb2_set_boot_mode(ctx); + TEST_NEQ(ctx->boot_mode, VB2_BOOT_MODE_MANUAL_RECOVERY, + "Block manual recovery if NO_BOOT"); + + reset_common_data(); + ctx->flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE; + vb2_set_boot_mode(ctx); + TEST_NEQ(ctx->boot_mode, VB2_BOOT_MODE_MANUAL_RECOVERY, + "Block manual recovery for untrusted EC"); +} + +int main(void) +{ + set_boot_mode_tests(); + + return gTestSuccess ? 0 : 255; +}
diff --git a/tests/vb2_misc_tests.c b/tests/vb2_misc_tests.c index 99f8bae..4add8d0 100644 --- a/tests/vb2_misc_tests.c +++ b/tests/vb2_misc_tests.c
@@ -11,7 +11,8 @@ #include "2nvstorage.h" #include "2secdata.h" #include "2sysincludes.h" -#include "test_common.h" +#include "common/boot_mode.h" +#include "common/tests.h" /* Common context for tests */ static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] @@ -22,7 +23,6 @@ static struct vb2_shared_data *sd; static struct vb2_gbb_header gbb; static struct vb2_secdata_fwmp *fwmp; -static enum vb2_boot_mode *boot_mode; /* Mocked function data */ static enum vb2_resource_index mock_resource_index; @@ -54,8 +54,7 @@ mock_tpm_clear_called = 0; mock_tpm_clear_retval = VB2_SUCCESS; - boot_mode = (enum vb2_boot_mode *)&ctx->boot_mode; - *boot_mode = VB2_BOOT_MODE_NORMAL; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); }; /* Mocked functions */ @@ -655,7 +654,8 @@ " dev mode flag not set"); reset_common_data(); - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); TEST_SUCC(vb2api_enable_developer_mode(ctx), "vb2api_enable_developer_mode - success"); TEST_NEQ(vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS) & @@ -664,17 +664,16 @@ /* secdata_firmware not initialized, aborts */ reset_common_data(); - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, + VB2_RECOVERY_RO_MANUAL); sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT; sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED; - TEST_ABORT(vb2api_enable_developer_mode(ctx), - "secdata_firmware no init, enable dev mode aborted"); + TEST_SUCC(vb2api_enable_developer_mode(ctx), + "secdata_firmware no init, enable dev mode ignored"); sd->status |= VB2_SD_STATUS_SECDATA_FIRMWARE_INIT; TEST_EQ(vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS) & VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE, 0, " dev mode flag not set"); - TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_BOOT_EXTERNAL), 0, - " NV_DEV_BOOT_EXTERNAL not set"); } static void tpm_clear_tests(void) @@ -816,9 +815,7 @@ /* Manual recovery */ reset_common_data(); - *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY; - sd->recovery_reason = 4; - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, 4); vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, 5); vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, 13); vb2_clear_recovery(ctx); @@ -829,9 +826,7 @@ /* Broken screen */ reset_common_data(); - *boot_mode = VB2_BOOT_MODE_BROKEN_SCREEN; - sd->recovery_reason = 4; - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; + SET_BOOT_MODE(ctx, VB2_BOOT_MODE_BROKEN_SCREEN, 4); vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, 5); vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, 13); vb2_clear_recovery(ctx);
diff --git a/tests/vb2_nvstorage_tests.c b/tests/vb2_nvstorage_tests.c index 94bcfca..8734f72 100644 --- a/tests/vb2_nvstorage_tests.c +++ b/tests/vb2_nvstorage_tests.c
@@ -16,7 +16,7 @@ #include "2nvstorage_fields.h" #include "2nvstorage.h" #include "2sysincludes.h" -#include "test_common.h" +#include "common/tests.h" /* Single NV storage field to test */ struct nv_field {
diff --git a/tests/vb2_preamble_fuzzer.c b/tests/vb2_preamble_fuzzer.c index 186ee9f..92c240e 100644 --- a/tests/vb2_preamble_fuzzer.c +++ b/tests/vb2_preamble_fuzzer.c
@@ -9,7 +9,6 @@ #include "2rsa.h" #include "2rsa_private.h" #include "2secdata.h" -#include "vboot_test.h" static struct vb2_context *ctx; static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
diff --git a/tests/vb2_recovery_reasons_tests.c b/tests/vb2_recovery_reasons_tests.c index 5def4d2..8d05862 100644 --- a/tests/vb2_recovery_reasons_tests.c +++ b/tests/vb2_recovery_reasons_tests.c
@@ -6,7 +6,7 @@ */ #include "2recovery_reasons.h" -#include "test_common.h" +#include "common/tests.h" static void get_recovery_reason_string_tests(void) {
diff --git a/tests/vb2_rsa_tests.sh b/tests/vb2_rsa_tests.sh index 903d38d..58d99b2 100755 --- a/tests/vb2_rsa_tests.sh +++ b/tests/vb2_rsa_tests.sh
@@ -16,24 +16,24 @@ function test_signatures { algorithmcounter=0 - for keylen in ${key_lengths[@]} + for keylen in "${key_lengths[@]}" do - for hashalgo in ${hash_algos[@]} + for hashalgo in "${hash_algos[@]}" do echo -e "For ${COL_YELLOW}RSA-$keylen and $hashalgo${COL_STOP}:" - ${BIN_DIR}/verify_data $algorithmcounter \ - ${TESTKEY_DIR}/key_rsa${keylen}.keyb \ - ${TEST_FILE}.rsa${keylen}_${hashalgo}.sig \ - ${TEST_FILE} - if [ $? -ne 0 ] + if ! "${BIN_DIR}/verify_data" "$algorithmcounter" \ + "${TESTKEY_DIR}/key_rsa${keylen}.keyb" \ + "${TEST_FILE}.rsa${keylen}_${hashalgo}.sig" \ + "${TEST_FILE}" then return_code=255 fi - let algorithmcounter=algorithmcounter+1 + algorithmcounter=$((algorithmcounter + 1)) done done echo -e "Peforming ${COL_YELLOW}PKCS #1 v1.5 Padding Tests${COL_STOP}..." - ${TEST_DIR}/vb20_rsa_padding_tests ${TESTKEY_DIR}/rsa_padding_test_pubkey.keyb + "${TEST_DIR}/vb20_rsa_padding_tests" \ + "${TESTKEY_DIR}/rsa_padding_test_pubkey.keyb" } check_test_keys @@ -41,4 +41,3 @@ test_signatures exit $return_code -
diff --git a/tests/vb2_rsa_utility_tests.c b/tests/vb2_rsa_utility_tests.c index 4ad5a95..057b4b0 100644 --- a/tests/vb2_rsa_utility_tests.c +++ b/tests/vb2_rsa_utility_tests.c
@@ -10,11 +10,10 @@ #include "2rsa.h" #include "2rsa_private.h" #include "2sysincludes.h" +#include "common/tests.h" #include "file_keys.h" #include "rsa_padding_test.h" -#include "test_common.h" #include "vboot_api.h" -#include "vboot_test.h" /** * Test RSA utility funcs
diff --git a/tests/vb2_secdata_firmware_tests.c b/tests/vb2_secdata_firmware_tests.c index c1b0a73..0520cc0 100644 --- a/tests/vb2_secdata_firmware_tests.c +++ b/tests/vb2_secdata_firmware_tests.c
@@ -12,7 +12,7 @@ #include "2secdata.h" #include "2secdata_struct.h" #include "2sysincludes.h" -#include "test_common.h" +#include "common/tests.h" static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] __attribute__((aligned(VB2_WORKBUF_ALIGN)));
diff --git a/tests/vb2_secdata_fwmp_tests.c b/tests/vb2_secdata_fwmp_tests.c index 79b0f55..eabe671 100644 --- a/tests/vb2_secdata_fwmp_tests.c +++ b/tests/vb2_secdata_fwmp_tests.c
@@ -9,7 +9,7 @@ #include "2misc.h" #include "2secdata.h" #include "2secdata_struct.h" -#include "test_common.h" +#include "common/tests.h" static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] __attribute__((aligned(VB2_WORKBUF_ALIGN)));
diff --git a/tests/vb2_secdata_kernel_tests.c b/tests/vb2_secdata_kernel_tests.c index dc41f1a..a84e04e 100644 --- a/tests/vb2_secdata_kernel_tests.c +++ b/tests/vb2_secdata_kernel_tests.c
@@ -12,8 +12,7 @@ #include "2secdata.h" #include "2secdata_struct.h" #include "2sysincludes.h" -#include "test_common.h" -#include "vboot_test.h" +#include "common/tests.h" static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] __attribute__((aligned(VB2_WORKBUF_ALIGN)));
diff --git a/tests/vb2_sha256_x86_tests.c b/tests/vb2_sha256_x86_tests.c index 06ba12e..e17d395 100644 --- a/tests/vb2_sha256_x86_tests.c +++ b/tests/vb2_sha256_x86_tests.c
@@ -10,8 +10,8 @@ #include "2api.h" #include "2sha.h" +#include "common/tests.h" #include "sha_test_vectors.h" -#include "test_common.h" vb2_error_t vb2_digest_buffer(const uint8_t *buf, uint32_t size, enum vb2_hash_algorithm hash_alg, uint8_t *digest,
diff --git a/tests/vb2_sha_api_tests.c b/tests/vb2_sha_api_tests.c index cb58f7b..6ed0b74 100644 --- a/tests/vb2_sha_api_tests.c +++ b/tests/vb2_sha_api_tests.c
@@ -8,7 +8,7 @@ #include "2return_codes.h" #include "2sha.h" #include "2sysincludes.h" -#include "test_common.h" +#include "common/tests.h" uint8_t mock_sha1[] = {0x1, 0x3, 0x5, 0x2, 0x4, 0x6, 0xa, 0xb, 0xc, 0xd, 0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf, 0x0, 0xf0};
diff --git a/tests/vb2_sha_tests.c b/tests/vb2_sha_tests.c index a14af65..40cf42f 100644 --- a/tests/vb2_sha_tests.c +++ b/tests/vb2_sha_tests.c
@@ -11,8 +11,8 @@ #include "2rsa.h" #include "2sha.h" #include "2sysincludes.h" +#include "common/tests.h" #include "sha_test_vectors.h" -#include "test_common.h" static void sha1_tests(void) {
diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c deleted file mode 100644 index 60d87c6..0000000 --- a/tests/vboot_api_kernel4_tests.c +++ /dev/null
@@ -1,343 +0,0 @@ -/* Copyright (c) 2013 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. - * - * Tests for vboot_api_kernel, part 4 - select and load kernel - */ - -#include "2api.h" -#include "2common.h" -#include "2misc.h" -#include "2nvstorage.h" -#include "2secdata.h" -#include "2sysincludes.h" -#include "host_common.h" -#include "load_kernel_fw.h" -#include "test_common.h" -#include "tlcl.h" -#include "tss_constants.h" -#include "vboot_struct.h" -#include "vboot_test.h" - -/* Mock data */ - -static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] - __attribute__((aligned(VB2_WORKBUF_ALIGN))); -static struct vb2_context *ctx; -static struct vb2_shared_data *sd; -static VbSelectAndLoadKernelParams kparams; -static struct vb2_gbb_header gbb; - -static uint32_t kernel_version; -static uint32_t new_version; -static vb2_error_t vbboot_retval; -static int commit_data_called; -static vb2_error_t secdata_kernel_init_retval; -static vb2_error_t secdata_fwmp_init_retval; -static vb2_error_t kernel_phase1_retval; -static uint32_t current_recovery_reason; -static uint32_t expected_recovery_reason; - -static int mock_diagnostic_ui_enabled; - -static void reset_common_data(void) -{ - memset(&kparams, 0, sizeof(kparams)); - - memset(&gbb, 0, sizeof(gbb)); - gbb.major_version = VB2_GBB_MAJOR_VER; - gbb.minor_version = VB2_GBB_MINOR_VER; - gbb.flags = 0; - - TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx), - "vb2api_init failed"); - sd = vb2_get_sd(ctx); - sd->flags |= VB2_SD_FLAG_DISPLAY_AVAILABLE; - ctx->flags |= VB2_CONTEXT_NO_SECDATA_FWMP; - sd->preamble_size = 1; - - vb2_nv_init(ctx); - vb2_nv_set(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0xffffffff); - commit_data_called = 0; - - kernel_version = new_version = 0x10002; - vbboot_retval = VB2_SUCCESS; - secdata_kernel_init_retval = VB2_SUCCESS; - secdata_fwmp_init_retval = VB2_SUCCESS; - kernel_phase1_retval = VB2_SUCCESS; - current_recovery_reason = 0; - expected_recovery_reason = 0; - - mock_diagnostic_ui_enabled = 0; - - sd->status |= VB2_SD_STATUS_SECDATA_KERNEL_INIT; - sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT; -} - -static void test_slk(vb2_error_t retval, int recovery_reason, const char *desc) -{ - if (sd->recovery_reason) - ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; - - expected_recovery_reason = recovery_reason; - /* The VbSelectAndLoadKernel directly leverages the value at - ctx->boot_mode, so we have to call vb2_set_boot_mode first. */ - vb2_set_boot_mode(ctx); - TEST_EQ(VbSelectAndLoadKernel(ctx, &kparams), retval, desc); - TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), - recovery_reason, " recovery reason"); -} - -/* Mock functions */ - -struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) -{ - return &gbb; -} - -vb2_error_t vb2api_kernel_phase1(struct vb2_context *c) -{ - sd->kernel_version_secdata = kernel_version; - sd->kernel_version = kernel_version; - return kernel_phase1_retval; -} - -vb2_error_t vb2ex_commit_data(struct vb2_context *c) -{ - current_recovery_reason = vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST); - commit_data_called = 1; - return VB2_SUCCESS; -} - -vb2_error_t vb2_secdata_fwmp_init(struct vb2_context *c) -{ - return secdata_fwmp_init_retval; -} - -void vb2_secdata_kernel_set(struct vb2_context *c, - enum vb2_secdata_kernel_param param, - uint32_t value) -{ - kernel_version = value; -} - -vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t disk_flags) -{ - sd->kernel_version = new_version; - - if (vbboot_retval == -1) - return VB2_ERROR_MOCK; - - return vbboot_retval; -} - -static vb2_error_t boot_dev(struct vb2_context *c) -{ - if (vbboot_retval == -2) - return VB2_ERROR_MOCK; - - return vbboot_retval; -} - -vb2_error_t vb2ex_developer_ui(struct vb2_context *c) -{ - return boot_dev(c); -} - -static void rec_check(struct vb2_context *c) -{ - TEST_EQ(current_recovery_reason, expected_recovery_reason, - " recovery reason"); - TEST_TRUE(commit_data_called, " commit data"); -} - -vb2_error_t vb2ex_manual_recovery_ui(struct vb2_context *c) -{ - rec_check(c); - if (vbboot_retval == -3) - return VB2_ERROR_MOCK; - return vbboot_retval; -} - -vb2_error_t vb2ex_broken_screen_ui(struct vb2_context *c) -{ - rec_check(c); - if (vbboot_retval == -4) - return VB2_ERROR_MOCK; - return vbboot_retval; -} - -vb2_error_t vb2ex_diagnostic_ui(struct vb2_context *c) -{ - if (vbboot_retval == -5) - return VB2_ERROR_MOCK; - - return vbboot_retval; -} - -int vb2api_diagnostic_ui_enabled(struct vb2_context *c) -{ - return mock_diagnostic_ui_enabled; -} - -vb2_error_t vb2ex_tpm_set_mode(enum vb2_tpm_mode mode_val) -{ - return VB2_SUCCESS; -} - -/* Tests */ - -static void select_and_load_kernel_tests(void) -{ - /* Normal boot */ - reset_common_data(); - test_slk(0, 0, "Normal"); - TEST_EQ(kernel_version, 0x10002, " version"); - TEST_NEQ(sd->status & VB2_SD_STATUS_EC_SYNC_COMPLETE, 0, - " EC sync complete"); - TEST_FALSE(commit_data_called, " no commit data"); - - /* Check EC sync toggling */ - reset_common_data(); - ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED; - gbb.flags |= VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC; - test_slk(0, 0, "EC sync disabled by GBB"); - TEST_NEQ(sd->status & VB2_SD_STATUS_EC_SYNC_COMPLETE, 0, - " EC sync complete"); - - reset_common_data(); - ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED; - test_slk(0, 0, "Normal with EC sync"); - TEST_NEQ(sd->status & VB2_SD_STATUS_EC_SYNC_COMPLETE, 0, - " EC sync complete"); - - reset_common_data(); - new_version = 0x20003; - test_slk(0, 0, "Roll forward"); - TEST_EQ(kernel_version, 0x20003, " version"); - - reset_common_data(); - vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_TRYING); - new_version = 0x20003; - test_slk(0, 0, "Don't roll forward kernel when trying new FW"); - TEST_EQ(kernel_version, 0x10002, " version"); - - reset_common_data(); - vb2_nv_set(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0x30005); - new_version = 0x40006; - test_slk(0, 0, "Limit max roll forward"); - TEST_EQ(kernel_version, 0x30005, " version"); - - reset_common_data(); - vb2_nv_set(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0x10001); - new_version = 0x40006; - test_slk(0, 0, "Max roll forward can't rollback"); - TEST_EQ(kernel_version, 0x10002, " version"); - - /* Boot normal */ - reset_common_data(); - vbboot_retval = -1; - test_slk(VB2_ERROR_MOCK, 0, "Normal boot bad"); - - /* Check that NV_DIAG_REQUEST triggers diagnostic UI */ - reset_common_data(); - mock_diagnostic_ui_enabled = 1; - vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1); - vbboot_retval = -5; - test_slk(VB2_ERROR_MOCK, 0, - "Normal boot with diag enabled"); - TEST_EQ(vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST), 0, - " diag not requested"); - - reset_common_data(); - vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1); - test_slk(VB2_REQUEST_REBOOT, 0, - "Normal boot with diag disabled (reboot to unset)"); - - /* Boot normal - phase1 failure */ - reset_common_data(); - kernel_phase1_retval = VB2_ERROR_MOCK; - test_slk(VB2_ERROR_MOCK, 0, "Normal phase1 failure"); - - /* Recovery - VB2_ERROR_ESCAPE_NO_BOOT */ - reset_common_data(); - ctx->flags |= VB2_CONTEXT_NO_BOOT; - ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED; - test_slk(VB2_ERROR_ESCAPE_NO_BOOT, - VB2_RECOVERY_ESCAPE_NO_BOOT, "Recovery for NO_BOOT escape"); - - /* Boot normal - VB2_ERROR_ESCAPE_NO_BOOT */ - reset_common_data(); - ctx->flags |= VB2_CONTEXT_NO_BOOT; - ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED; - gbb.flags |= VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC; - test_slk(VB2_SUCCESS, 0, "DISABLE_EC_SOFTWARE_SYNC ignores NO_BOOT"); - - /* Boot dev */ - reset_common_data(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - vbboot_retval = -2; - test_slk(VB2_ERROR_MOCK, 0, "Dev boot bad"); - TEST_FALSE(commit_data_called, " no commit data"); - - reset_common_data(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - new_version = 0x20003; - test_slk(0, 0, "Dev doesn't roll forward"); - TEST_EQ(kernel_version, 0x10002, " version"); - - /* Boot dev - phase1 failure */ - reset_common_data(); - ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - kernel_phase1_retval = VB2_ERROR_MOCK; - test_slk(VB2_ERROR_MOCK, 0, "Dev phase1 failure"); - - /* Boot recovery */ - reset_common_data(); - sd->recovery_reason = 123; - vbboot_retval = -4; - test_slk(VB2_ERROR_MOCK, 0, "Recovery boot bad"); - TEST_TRUE(commit_data_called, " commit data"); - - reset_common_data(); - sd->recovery_reason = 123; - new_version = 0x20003; - test_slk(0, 0, "Recovery doesn't roll forward"); - TEST_EQ(kernel_version, 0x10002, " version"); - TEST_TRUE(commit_data_called, " commit data"); - - /* Boot recovery - phase1 failure */ - reset_common_data(); - sd->recovery_reason = 123; - kernel_phase1_retval = VB2_ERROR_MOCK; - test_slk(VB2_ERROR_MOCK, 0, "Recovery phase1 failure"); - TEST_FALSE(commit_data_called, " no commit data"); - - /* Boot recovery - memory retraining */ - reset_common_data(); - sd->recovery_reason = VB2_RECOVERY_TRAIN_AND_REBOOT; - test_slk(VB2_REQUEST_REBOOT, 0, "Recovery train and reboot"); - TEST_FALSE(commit_data_called, " no commit data"); - - /* Boot BROKEN recovery */ - reset_common_data(); - sd->recovery_reason = 123; - vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, 13); - test_slk(0, 0, "BROKEN recovery"); - TEST_TRUE(commit_data_called, " commit data"); - - /* Boot manual recovery */ - reset_common_data(); - sd->recovery_reason = VB2_RECOVERY_RO_MANUAL; - vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, 13); - ctx->flags &= VB2_CONTEXT_FORCE_RECOVERY_MODE; - test_slk(0, 0, "Manual recovery"); - TEST_TRUE(commit_data_called, " commit data"); -} - -int main(void) -{ - select_and_load_kernel_tests(); - - return gTestSuccess ? 0 : 255; -}
diff --git a/tests/vboot_api_kernel_tests.c b/tests/vboot_api_kernel_tests.c deleted file mode 100644 index b66c432..0000000 --- a/tests/vboot_api_kernel_tests.c +++ /dev/null
@@ -1,642 +0,0 @@ -/* Copyright (c) 2013 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. - * - * Tests for VbTryLoadKernel() - */ - -#include "2common.h" -#include "2misc.h" -#include "2nvstorage.h" -#include "2sysincludes.h" -#include "load_kernel_fw.h" -#include "test_common.h" -#include "vboot_api.h" -#include "vboot_test.h" - -#define MAX_TEST_DISKS 10 -#define DEFAULT_COUNT -1 - -typedef struct { - uint64_t bytes_per_lba; - uint64_t lba_count; - uint32_t flags; - const char *diskname; -} disk_desc_t; - -typedef struct { - const char *name; - - /* inputs for test case */ - uint32_t ctx_flags; - uint32_t want_flags; - vb2_error_t diskgetinfo_return_val; - disk_desc_t disks_to_provide[MAX_TEST_DISKS]; - int disk_count_to_return; - vb2_error_t loadkernel_return_val[MAX_TEST_DISKS]; - uint8_t external_expected[MAX_TEST_DISKS]; - - /* outputs from test */ - uint32_t expected_recovery_request_val; - const char *expected_to_find_disk; - const char *expected_to_load_disk; - uint32_t expected_return_val; - -} test_case_t; - -/****************************************************************************/ -/* Test cases */ - -static const char pickme[] = "correct choice"; -#define DONT_CARE ((const char *)42) - -test_case_t normal_tests[] = { - { - .name = "first drive (removable)", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_FIXED, - .disks_to_provide = { - {4096, 100, VB_DISK_FLAG_REMOVABLE, pickme}, - {4096, 100, VB_DISK_FLAG_FIXED, "holygrail"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {0}, - .external_expected = {0}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = pickme, - .expected_to_load_disk = pickme, - .expected_return_val = VB2_SUCCESS - }, - { - .name = "first drive (fixed)", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_FIXED, - .disks_to_provide = { - {4096, 100, VB_DISK_FLAG_FIXED, pickme}, - {4096, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {0}, - .external_expected = {0}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = pickme, - .expected_to_load_disk = pickme, - .expected_return_val = VB2_SUCCESS - }, - { - .name = "first removable drive", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_REMOVABLE, - .disks_to_provide = { - /* too small */ - {512, 10, VB_DISK_FLAG_REMOVABLE, 0}, - /* wrong LBA */ - {511, 100, VB_DISK_FLAG_REMOVABLE, 0}, - /* not a power of 2 */ - {2047, 100, VB_DISK_FLAG_REMOVABLE, 0}, - /* wrong type */ - {512, 100, VB_DISK_FLAG_FIXED, 0}, - /* wrong flags */ - {512, 100, 0, 0}, - /* still wrong flags */ - {512, 100, -1, 0}, - {4096, 100, VB_DISK_FLAG_REMOVABLE, pickme}, - /* already got one */ - {512, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {0}, - .external_expected = {0}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = pickme, - .expected_to_load_disk = pickme, - .expected_return_val = VB2_SUCCESS - }, - { - .name = "first removable drive (skip external GPT)", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_REMOVABLE, - .disks_to_provide = { - /* too small */ - {512, 10, VB_DISK_FLAG_REMOVABLE, 0}, - /* wrong LBA */ - {511, 100, VB_DISK_FLAG_REMOVABLE, 0}, - /* not a power of 2 */ - {2047, 100, VB_DISK_FLAG_REMOVABLE, 0}, - /* wrong type */ - {512, 100, VB_DISK_FLAG_FIXED, 0}, - /* wrong flags */ - {512, 100, 0, 0}, - /* still wrong flags */ - {512, 100, -1, 0}, - {512, 100, - VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_EXTERNAL_GPT, - pickme}, - /* already got one */ - {512, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {0, 0}, - .external_expected = {1, 0}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = pickme, - .expected_to_load_disk = pickme, - .expected_return_val = VB2_SUCCESS - }, - { - .name = "second removable drive", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_REMOVABLE, - .disks_to_provide = { - /* wrong flags */ - {512, 100, 0, 0}, - {512, 100, VB_DISK_FLAG_REMOVABLE, "not yet"}, - {512, 100, VB_DISK_FLAG_REMOVABLE, pickme}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND, 0}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = pickme, - .expected_to_load_disk = pickme, - .expected_return_val = VB2_SUCCESS - }, - { - .name = "first fixed drive", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_FIXED, - .disks_to_provide = { - /* too small */ - {512, 10, VB_DISK_FLAG_FIXED, 0}, - /* wrong LBA */ - {511, 100, VB_DISK_FLAG_FIXED, 0}, - /* not a power of 2 */ - {2047, 100, VB_DISK_FLAG_REMOVABLE, 0}, - /* wrong type */ - {512, 100, VB_DISK_FLAG_REMOVABLE, 0}, - /* wrong flags */ - {512, 100, 0, 0}, - /* still wrong flags */ - {512, 100, -1, 0}, - /* flags */ - {512, 100, VB_DISK_FLAG_REMOVABLE|VB_DISK_FLAG_FIXED, - 0}, - {512, 100, VB_DISK_FLAG_FIXED, pickme}, - /* already got one */ - {512, 100, VB_DISK_FLAG_FIXED, "holygrail"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {0}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = pickme, - .expected_to_load_disk = pickme, - .expected_return_val = VB2_SUCCESS - }, - { - .name = "no drives at all", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_FIXED, - .disks_to_provide = {}, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - - .expected_recovery_request_val = VB2_RECOVERY_RW_NO_DISK, - .expected_to_find_disk = 0, - .expected_to_load_disk = 0, - .expected_return_val = VB2_ERROR_LK_NO_DISK_FOUND - }, - { - .name = "VbExDiskGetInfo() error", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_FIXED, - .disks_to_provide = { - {512, 10, VB_DISK_FLAG_REMOVABLE, 0}, - {512, 100, VB_DISK_FLAG_FIXED, 0}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_ERROR_UNKNOWN, - - .expected_recovery_request_val = VB2_RECOVERY_RW_NO_DISK, - .expected_to_find_disk = 0, - .expected_to_load_disk = 0, - .expected_return_val = VB2_ERROR_LK_NO_DISK_FOUND, - }, - { - .name = "invalid kernel", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_FIXED, - .disks_to_provide = { - /* too small */ - {512, 10, VB_DISK_FLAG_FIXED, 0}, - /* wrong LBA */ - {511, 100, VB_DISK_FLAG_FIXED, 0}, - /* not a power of 2 */ - {2047, 100, VB_DISK_FLAG_FIXED, 0}, - /* wrong type */ - {512, 100, VB_DISK_FLAG_REMOVABLE, 0}, - /* wrong flags */ - {512, 100, 0, 0}, - /* still wrong flags */ - {512, 100, -1, 0}, - /* doesn't load */ - {512, 100, VB_DISK_FLAG_FIXED, "corrupted kernel"}, - /* doesn't load */ - {512, 100, VB_DISK_FLAG_FIXED, "stateful partition"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND, - VB2_ERROR_LK_NO_KERNEL_FOUND}, - - .expected_recovery_request_val = VB2_RECOVERY_RW_INVALID_OS, - .expected_to_find_disk = DONT_CARE, - .expected_to_load_disk = 0, - .expected_return_val = VB2_ERROR_LK_INVALID_KERNEL_FOUND, - }, - { - .name = "invalid kernel, order flipped", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_FIXED, - .disks_to_provide = { - {512, 1000, VB_DISK_FLAG_FIXED, "stateful partition"}, - {512, 1000, VB_DISK_FLAG_FIXED, "corrupted kernel"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {VB2_ERROR_LK_NO_KERNEL_FOUND, - VB2_ERROR_LK_INVALID_KERNEL_FOUND}, - - .expected_recovery_request_val = VB2_RECOVERY_RW_INVALID_OS, - .expected_to_find_disk = DONT_CARE, - .expected_to_load_disk = 0, - .expected_return_val = VB2_ERROR_LK_INVALID_KERNEL_FOUND, - }, - { - .name = "no Chrome OS partitions", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_FIXED, - .disks_to_provide = { - {512, 100, VB_DISK_FLAG_FIXED, "stateful partition"}, - {512, 1000, VB_DISK_FLAG_FIXED, "Chrubuntu"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {VB2_ERROR_LK_NO_KERNEL_FOUND, - VB2_ERROR_LK_NO_KERNEL_FOUND}, - - .expected_recovery_request_val = VB2_RECOVERY_RW_NO_KERNEL, - .expected_to_find_disk = DONT_CARE, - .expected_to_load_disk = 0, - .expected_return_val = VB2_ERROR_LK_NO_KERNEL_FOUND, - }, - { - .name = "invalid kernel (removable)", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_REMOVABLE, - .disks_to_provide = { - {512, 100, VB_DISK_FLAG_REMOVABLE, "corrupted"}, - {512, 100, VB_DISK_FLAG_REMOVABLE, "data"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND, - VB2_ERROR_LK_NO_KERNEL_FOUND}, - - .expected_recovery_request_val = VB2_RECOVERY_RW_INVALID_OS, - .expected_to_find_disk = DONT_CARE, - .expected_to_load_disk = 0, - .expected_return_val = VB2_ERROR_LK_INVALID_KERNEL_FOUND, - }, - { - .name = "invalid kernel (removable, rec mode)", - .ctx_flags = VB2_CONTEXT_RECOVERY_MODE, - .want_flags = VB_DISK_FLAG_REMOVABLE, - .disks_to_provide = { - {512, 100, VB_DISK_FLAG_REMOVABLE, "corrupted"}, - {512, 100, VB_DISK_FLAG_REMOVABLE, "data"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND, - VB2_ERROR_LK_NO_KERNEL_FOUND}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = DONT_CARE, - .expected_to_load_disk = 0, - .expected_return_val = VB2_ERROR_LK_INVALID_KERNEL_FOUND, - }, - { - .name = "invalid kernel (removable, dev mode)", - .ctx_flags = VB2_CONTEXT_DEVELOPER_MODE, - .want_flags = VB_DISK_FLAG_REMOVABLE, - .disks_to_provide = { - {512, 100, VB_DISK_FLAG_REMOVABLE, "corrupted"}, - {512, 100, VB_DISK_FLAG_REMOVABLE, "data"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND, - VB2_ERROR_LK_NO_KERNEL_FOUND}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = DONT_CARE, - .expected_to_load_disk = 0, - .expected_return_val = VB2_ERROR_LK_INVALID_KERNEL_FOUND, - }, - { - .name = "no kernel (removable)", - .ctx_flags = 0, - .want_flags = VB_DISK_FLAG_REMOVABLE, - .disks_to_provide = { - {512, 100, VB_DISK_FLAG_REMOVABLE, "data"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {VB2_ERROR_LK_NO_KERNEL_FOUND}, - - .expected_recovery_request_val = VB2_RECOVERY_RW_NO_KERNEL, - .expected_to_find_disk = DONT_CARE, - .expected_to_load_disk = 0, - .expected_return_val = VB2_ERROR_LK_NO_KERNEL_FOUND, - }, - { - .name = "no kernel (removable, rec mode)", - .ctx_flags = VB2_CONTEXT_RECOVERY_MODE, - .want_flags = VB_DISK_FLAG_REMOVABLE, - .disks_to_provide = { - {512, 100, VB_DISK_FLAG_REMOVABLE, "data"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {VB2_ERROR_LK_NO_KERNEL_FOUND}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = DONT_CARE, - .expected_to_load_disk = 0, - .expected_return_val = VB2_ERROR_LK_NO_KERNEL_FOUND, - }, -}; - -test_case_t minios_tests[] = { - { - .name = "pick first fixed drive", - .ctx_flags = 0, - .disks_to_provide = { - {4096, 100, VB_DISK_FLAG_REMOVABLE, 0}, - {4096, 100, VB_DISK_FLAG_FIXED, pickme}, - {4096, 100, VB_DISK_FLAG_FIXED, "holygrail"}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {0}, - .external_expected = {0}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = pickme, - .expected_to_load_disk = pickme, - .expected_return_val = VB2_SUCCESS - }, - { - .name = "skip failed fixed drive", - .ctx_flags = 0, - .disks_to_provide = { - {4096, 100, VB_DISK_FLAG_FIXED, "holygrail"}, - {4096, 100, VB_DISK_FLAG_FIXED, pickme}, - }, - .disk_count_to_return = DEFAULT_COUNT, - .diskgetinfo_return_val = VB2_SUCCESS, - .loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND, 0}, - .external_expected = {0}, - - .expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED, - .expected_to_find_disk = pickme, - .expected_to_load_disk = pickme, - .expected_return_val = VB2_SUCCESS - }, -}; - -/****************************************************************************/ - -/* Mock data */ -static VbDiskInfo mock_disks[MAX_TEST_DISKS]; -static test_case_t *t; -static int load_kernel_calls; -static int lk_normal_calls; -static int lk_minios_calls; -static uint32_t got_recovery_request_val; -static const char *got_find_disk; -static const char *got_load_disk; -static uint32_t got_return_val; -static uint32_t got_external_mismatch; -static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] - __attribute__((aligned(VB2_WORKBUF_ALIGN))); -static struct vb2_context *ctx; -static struct VbSelectAndLoadKernelParams kparams; - -/** - * Reset mock data (for use before each test) - */ -static void ResetMocks(test_case_t *test_case) -{ - TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx), - "vb2api_init failed"); - - memset(&kparams, 0, sizeof(VbSelectAndLoadKernelParams)); - *VbApiKernelGetParamsPtr() = &kparams; - - - memset(&mock_disks, 0, sizeof(mock_disks)); - load_kernel_calls = 0; - lk_normal_calls = 0; - lk_minios_calls = 0; - - got_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED; - got_find_disk = 0; - got_load_disk = 0; - got_return_val = 0xdeadbeef; - - t = test_case; -} - -static int is_nonzero(const void *vptr, size_t count) -{ - const char *p = (const char *)vptr; - while (count--) - if (*p++) - return 1; - - return 0; -} - -/****************************************************************************/ -/* Mocked verification functions */ - -vb2_error_t VbExDiskGetInfo(VbDiskInfo **infos_ptr, uint32_t *count, - uint32_t disk_flags) -{ - int i; - int num_disks = 0; - - VB2_DEBUG("My %s\n", __FUNCTION__); - - *infos_ptr = mock_disks; - - for(i = 0; i < MAX_TEST_DISKS; i++) { - if (is_nonzero(&t->disks_to_provide[i], - sizeof(t->disks_to_provide[i]))) { - mock_disks[num_disks].bytes_per_lba = - t->disks_to_provide[i].bytes_per_lba; - mock_disks[num_disks].lba_count = - mock_disks[num_disks].streaming_lba_count = - t->disks_to_provide[i].lba_count; - mock_disks[num_disks].flags = - t->disks_to_provide[i].flags; - mock_disks[num_disks].handle = (VbExDiskHandle_t) - t->disks_to_provide[i].diskname; - VB2_DEBUG(" mock_disk[%d] %" PRIu64 " %" PRIu64 - " %#x %s\n", i, - mock_disks[num_disks].bytes_per_lba, - mock_disks[num_disks].lba_count, - mock_disks[num_disks].flags, - (mock_disks[num_disks].handle - ? (char *)mock_disks[num_disks].handle - : "0")); - num_disks++; - } else { - mock_disks[num_disks].handle = - (VbExDiskHandle_t)"INVALID"; - } - } - - if (t->disk_count_to_return >= 0) - *count = t->disk_count_to_return; - else - *count = num_disks; - - VB2_DEBUG(" *count=%" PRIu32 "\n", *count); - VB2_DEBUG(" return %#x\n", t->diskgetinfo_return_val); - - return t->diskgetinfo_return_val; -} - -vb2_error_t VbExDiskFreeInfo(VbDiskInfo *infos, - VbExDiskHandle_t preserve_handle) -{ - got_load_disk = (const char *)preserve_handle; - VB2_DEBUG("%s(): got_load_disk = %s\n", __FUNCTION__, - got_load_disk ? got_load_disk : "0"); - return VB2_SUCCESS; -} - -static vb2_error_t LoadKernelImpl(struct vb2_context *c, - VbSelectAndLoadKernelParams *params, - VbDiskInfo *disk_info) -{ - got_find_disk = (const char *)params->disk_handle; - VB2_DEBUG("%s(%d): got_find_disk = %s\n", __FUNCTION__, - load_kernel_calls, - got_find_disk ? got_find_disk : "0"); - if (t->external_expected[load_kernel_calls] != - !!(disk_info->flags & VB_DISK_FLAG_EXTERNAL_GPT)) - got_external_mismatch++; - return t->loadkernel_return_val[load_kernel_calls++]; -} - -vb2_error_t LoadKernel(struct vb2_context *c, - VbSelectAndLoadKernelParams *params, - VbDiskInfo *disk_info) -{ - lk_normal_calls++; - return LoadKernelImpl(c, params, disk_info); -} - -vb2_error_t LoadMiniOsKernel(struct vb2_context *c, - VbSelectAndLoadKernelParams *params, - VbDiskInfo *disk_info, uint32_t minios_flags) -{ - lk_minios_calls++; - return LoadKernelImpl(c, params, disk_info); -} - -void vb2_nv_set(struct vb2_context *c, - enum vb2_nv_param param, - uint32_t value) -{ - if (param != VB2_NV_RECOVERY_REQUEST) - return; - VB2_DEBUG("%s(): got_recovery_request_val = %d (%#x)\n", __FUNCTION__, - value, value); - got_recovery_request_val = value; -} - -/****************************************************************************/ - -static void VbTryLoadKernelTest(void) -{ - int i; - int num_tests = ARRAY_SIZE(normal_tests); - - for (i = 0; i < num_tests; i++) { - printf("Test case: %s ...\n", normal_tests[i].name); - ResetMocks(&normal_tests[i]); - ctx->flags = t->ctx_flags; - TEST_EQ(VbTryLoadKernel(ctx, t->want_flags), - t->expected_return_val, " return value"); - TEST_EQ(got_recovery_request_val, - t->expected_recovery_request_val, " recovery_request"); - if (t->expected_to_find_disk != DONT_CARE) { - TEST_PTR_EQ(got_find_disk, t->expected_to_find_disk, - " find disk"); - TEST_PTR_EQ(got_load_disk, t->expected_to_load_disk, - " load disk"); - } - TEST_EQ(got_external_mismatch, 0, " external GPT errors"); - } - TEST_EQ(lk_normal_calls, load_kernel_calls, " LoadKernel called"); - TEST_EQ(lk_minios_calls, 0, " LoadMiniOsKernel not called"); -} - -static void VbTryLoadMiniOsKernelTest(void) -{ - int i; - int num_tests = ARRAY_SIZE(minios_tests); - - for (i = 0; i < num_tests; i++) { - printf("Test case: %s ...\n", minios_tests[i].name); - ResetMocks(&minios_tests[i]); - ctx->flags = t->ctx_flags; - TEST_EQ(VbTryLoadMiniOsKernel(ctx, 0), - t->expected_return_val, " return value"); - TEST_EQ(got_recovery_request_val, - t->expected_recovery_request_val, " recovery_request"); - if (t->expected_to_find_disk != DONT_CARE) { - TEST_PTR_EQ(got_find_disk, t->expected_to_find_disk, - " find disk"); - TEST_PTR_EQ(got_load_disk, t->expected_to_load_disk, - " load disk"); - } - TEST_EQ(got_external_mismatch, 0, " external GPT errors"); - } - TEST_EQ(lk_normal_calls, 0, " LoadKernel not called"); - TEST_EQ(lk_minios_calls, load_kernel_calls, - " LoadMiniOsKernel called"); -} - -int main(void) -{ - VbTryLoadKernelTest(); - VbTryLoadMiniOsKernelTest(); - - return gTestSuccess ? 0 : 255; -}
diff --git a/tests/verify_kernel.c b/tests/verify_kernel.c index a79f33a..8af4791 100644 --- a/tests/verify_kernel.c +++ b/tests/verify_kernel.c
@@ -14,7 +14,6 @@ #include "host_common.h" #include "util_misc.h" #include "vboot_api.h" -#include "load_kernel_fw.h" static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] __attribute__((aligned(VB2_WORKBUF_ALIGN))); @@ -23,13 +22,13 @@ static uint8_t *diskbuf; -static VbSelectAndLoadKernelParams params; -static VbDiskInfo disk_info; +static struct vb2_kernel_params params; +static struct vb2_disk_info disk_info; -vb2_error_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExDiskRead(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, void *buffer) { - if (handle != (VbExDiskHandle_t)1) + if (handle != (vb2ex_disk_handle_t)1) return VB2_ERROR_UNKNOWN; if (lba_start >= disk_info.streaming_lba_count) return VB2_ERROR_UNKNOWN; @@ -40,10 +39,10 @@ return VB2_SUCCESS; } -vb2_error_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExDiskWrite(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, const void *buffer) { - if (handle != (VbExDiskHandle_t)1) + if (handle != (vb2ex_disk_handle_t)1) return VB2_ERROR_UNKNOWN; if (lba_start >= disk_info.streaming_lba_count) return VB2_ERROR_UNKNOWN; @@ -87,8 +86,7 @@ } /* Set up params */ - params.disk_handle = (VbExDiskHandle_t)1; - disk_info.handle = (VbExDiskHandle_t)1; + disk_info.handle = (vb2ex_disk_handle_t)1; disk_info.bytes_per_lba = 512; disk_info.streaming_lba_count = disk_bytes / 512; disk_info.lba_count = disk_info.streaming_lba_count; @@ -123,8 +121,8 @@ } /* - * LoadKernel() cares only about VBNV_DEV_BOOT_SIGNED_ONLY, and only in - * dev mode. So just use defaults for nv storage. + * vb2api_load_kernel() cares only about VBNV_DEV_BOOT_SIGNED_ONLY, and + * only in dev mode. So just use defaults for nv storage. */ vb2_nv_init(ctx); /* We need to init kernel secdata for @@ -134,9 +132,10 @@ vb2_secdata_kernel_init(ctx); /* Try loading kernel */ - rv = LoadKernel(ctx, ¶ms, &disk_info); + rv = vb2api_load_kernel(ctx, ¶ms, &disk_info); if (rv != VB2_SUCCESS) { - fprintf(stderr, "LoadKernel() failed with code %d\n", rv); + fprintf(stderr, "vb2api_load_kernel() failed with code %d\n", + rv); return 1; }
diff --git a/utility/load_kernel_test.c b/utility/load_kernel_test.c index 405fced..565161e 100644 --- a/utility/load_kernel_test.c +++ b/utility/load_kernel_test.c
@@ -15,7 +15,6 @@ #include "2misc.h" #include "2sysincludes.h" #include "host_common.h" -#include "load_kernel_fw.h" #define LBA_BYTES 512 #define KERNEL_BUFFER_SIZE 0xA00000 @@ -25,13 +24,13 @@ static struct vb2_shared_data *sd; /* Global variables for stub functions */ -static VbSelectAndLoadKernelParams lkp; -static VbDiskInfo disk_info; +static struct vb2_kernel_params lkp; +static struct vb2_disk_info disk_info; static FILE *image_file = NULL; /* Boot device stub implementations to read from the image file */ -vb2_error_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExDiskRead(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, void *buffer) { printf("Read(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count); @@ -56,7 +55,7 @@ } -vb2_error_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start, +vb2_error_t VbExDiskWrite(vb2ex_disk_handle_t handle, uint64_t lba_start, uint64_t lba_count, const void *buffer) { printf("Write(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count); @@ -99,7 +98,7 @@ int errorcnt = 0; char *e = 0; - memset(&lkp, 0, sizeof(VbSelectAndLoadKernelParams)); + memset(&lkp, 0, sizeof(lkp)); disk_info.bytes_per_lba = LBA_BYTES; int boot_flags = BOOT_FLAG_RECOVERY; @@ -243,9 +242,9 @@ if (boot_flags & BOOT_FLAG_DEVELOPER) ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - /* Call LoadKernel() */ - rv = LoadKernel(ctx, &lkp, &disk_info); - printf("LoadKernel() returned %d\n", rv); + /* Call vb2api_load_kernel() */ + rv = vb2api_load_kernel(ctx, &lkp, &disk_info); + printf("vb2api_load_kernel() returned %d\n", rv); if (VB2_SUCCESS == rv) { printf("Partition number: %u\n", lkp.partition_number);