diff options
author | Bill Richardson <wfrichar@chromium.org> | 2013-03-04 13:21:16 -0800 |
---|---|---|
committer | Bill Richardson <wfrichar@chromium.org> | 2013-03-04 14:22:48 -0800 |
commit | a4c40a0f7bb0a7e099052c1699fdad92fe4d9efb (patch) | |
tree | f7c1ad247c852ab8f8ab6fa7e406275299f3d65e | |
parent | 7f73c9c38468faf03464ac0d22d5bf1f999b2ffe (diff) | |
parent | 81a0b3de707b4e00958faf36f41b8f3d7bac6808 (diff) | |
download | vboot-a4c40a0f7bb0a7e099052c1699fdad92fe4d9efb.tar.gz |
Merge remote-tracking branch 'm/master' into futility
BUG=none
BRANCH=none
TEST=none
Change-Id: I817f78c5844a3e8e3ef7fdca339b716b09b2e3d2
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r-- | Makefile | 269 | ||||
-rw-r--r-- | cgpt/CgptManager.cc | 429 | ||||
-rw-r--r-- | cgpt/CgptManager.h | 172 | ||||
-rw-r--r-- | firmware/lib/include/vboot_display.h | 4 | ||||
-rw-r--r-- | firmware/lib/include/vboot_kernel.h | 1 | ||||
-rw-r--r-- | firmware/lib/rollback_index.c | 17 | ||||
-rw-r--r-- | firmware/lib/tpm_bootmode.c | 3 | ||||
-rw-r--r-- | firmware/lib/vboot_api_kernel.c | 1 | ||||
-rw-r--r-- | firmware/lib/vboot_common.c | 34 | ||||
-rw-r--r-- | firmware/lib/vboot_common_init.c | 43 | ||||
-rw-r--r-- | firmware/lib/vboot_display.c | 6 | ||||
-rw-r--r-- | firmware/linktest/main_vbinit.c | 13 | ||||
-rw-r--r-- | firmware/linktest/main_vbsf.c | 14 | ||||
-rw-r--r-- | firmware/stub/utility_stub.c | 19 | ||||
-rw-r--r-- | firmware/stub/vboot_api_stub.c | 76 | ||||
-rw-r--r-- | firmware/stub/vboot_api_stub_init.c | 73 | ||||
-rw-r--r-- | firmware/stub/vboot_api_stub_sf.c | 40 | ||||
-rw-r--r-- | tests/CgptManagerTests.cc | 403 | ||||
-rw-r--r-- | utility/mount-encrypted.c | 1349 | ||||
-rw-r--r-- | utility/mount-encrypted.h | 144 | ||||
-rw-r--r-- | utility/mount-helpers.c | 803 | ||||
-rw-r--r-- | utility/mount-helpers.h | 42 |
22 files changed, 313 insertions, 3642 deletions
@@ -192,30 +192,9 @@ endif export BUILD_RUN -# Some things only compile inside the Chromium OS chroot. -# TODO: Those things should be in their own repo, not part of vboot_reference -# TODO: Is there a better way to detect this? -ifneq (${CROS_WORKON_SRCROOT},) -IN_CHROOT := yes -endif - -# TODO: Move to separate repo. -ifneq (${IN_CHROOT},) -PC_BASE_VER ?= 125070 -PC_DEPS := libchrome-${PC_BASE_VER} -PC_CFLAGS := $(shell ${PKG_CONFIG} --cflags ${PC_DEPS}) -PC_LDLIBS := $(shell ${PKG_CONFIG} --libs ${PC_DEPS}) -endif - - ############################################################################## # Now we need to describe everything we might want or need to build -# TODO: This should go in its own repo. -AU_CGPTLIB = ${BUILD}/cgpt/libcgpt-cc.a -# This is just ... Gah. There's no good place for it. -DUMPKERNELCONFIGLIB = ${BUILD}/libdump_kernel_config.a - # Everything wants these headers. INCLUDES += \ -Ifirmware/include \ @@ -235,12 +214,16 @@ endif # Firmware library. TODO: Do we still need to export this? FWLIB = ${BUILD}/vboot_fw.a -# find lib -iname '*.c' | sort -FWLIB_SRCS = \ - firmware/lib/cgptlib/cgptlib.c \ - firmware/lib/cgptlib/cgptlib_internal.c \ - firmware/lib/cgptlib/crc32.c \ +# Firmware library sources needed by VbInit() call +VBINIT_SRCS = \ firmware/lib/crc8.c \ + firmware/lib/utility.c \ + firmware/lib/vboot_api_init.c \ + firmware/lib/vboot_common_init.c \ + firmware/lib/vboot_nvstorage.c \ + +# Additional firmware library sources needed by VbSelectFirmware() call +VBSF_SRCS = \ firmware/lib/cryptolib/padding.c \ firmware/lib/cryptolib/rsa.c \ firmware/lib/cryptolib/rsa_utility.c \ @@ -249,48 +232,75 @@ FWLIB_SRCS = \ firmware/lib/cryptolib/sha512.c \ firmware/lib/cryptolib/sha_utility.c \ firmware/lib/stateful_util.c \ - firmware/lib/utility.c \ - firmware/lib/utility_string.c \ - firmware/lib/vboot_api_init.c \ firmware/lib/vboot_api_firmware.c \ + firmware/lib/vboot_common.c \ + firmware/lib/vboot_firmware.c + +# Additional firmware library sources needed by VbSelectAndLoadKernel() call +VBSLK_SRCS = \ + firmware/lib/cgptlib/cgptlib.c \ + firmware/lib/cgptlib/cgptlib_internal.c \ + firmware/lib/cgptlib/crc32.c \ + firmware/lib/utility_string.c \ firmware/lib/vboot_api_kernel.c \ firmware/lib/vboot_audio.c \ - firmware/lib/vboot_common.c \ firmware/lib/vboot_display.c \ - firmware/lib/vboot_firmware.c \ - firmware/lib/vboot_kernel.c \ - firmware/lib/vboot_nvstorage.c + firmware/lib/vboot_kernel.c # Support real TPM unless BIOS sets MOCK_TPM ifeq (${MOCK_TPM},) -FWLIB_SRCS += \ +VBINIT_SRCS += \ firmware/lib/rollback_index.c \ - firmware/lib/tpm_bootmode.c \ firmware/lib/tpm_lite/tlcl.c + +VBSF_SRCS += \ + firmware/lib/tpm_bootmode.c else -FWLIB_SRCS += \ +VBINIT_SRCS += \ firmware/lib/mocked_rollback_index.c \ - firmware/lib/mocked_tpm_bootmode.c \ firmware/lib/tpm_lite/mocked_tlcl.c + +VBSF_SRCS += \ + firmware/lib/mocked_tpm_bootmode.c endif ifeq (${FIRMWARE_ARCH},) # Include BIOS stubs in the firmware library when compiling for host -FWLIB_SRCS += \ +# TODO: split out other stub funcs too +VBINIT_SRCS += \ firmware/stub/tpm_lite_stub.c \ firmware/stub/utility_stub.c \ + firmware/stub/vboot_api_stub_init.c + +VBSF_SRCS += \ + firmware/stub/vboot_api_stub_sf.c + +VBSLK_SRCS += \ firmware/stub/vboot_api_stub.c \ firmware/stub/vboot_api_stub_disk.c endif +VBSF_SRCS += ${VBINIT_SRCS} +FWLIB_SRCS += ${VBSF_SRCS} ${VBSLK_SRCS} + +VBINIT_OBJS = ${VBINIT_SRCS:%.c=${BUILD}/%.o} +VBSF_OBJS = ${VBSF_SRCS:%.c=${BUILD}/%.o} + FWLIB_OBJS = ${FWLIB_SRCS:%.c=${BUILD}/%.o} ALL_OBJS += ${FWLIB_OBJS} # Library to build the utilities. "HOST" mostly means "userspace". -HOSTLIB = ${BUILD}/vboot_host.a +HOSTLIB = ${BUILD}/libvboot_host.a HOSTLIB_SRCS = \ + cgpt/cgpt_create.c \ + cgpt/cgpt_add.c \ + cgpt/cgpt_boot.c \ + cgpt/cgpt_show.c \ + cgpt/cgpt_repair.c \ + cgpt/cgpt_prioritize.c \ + cgpt/cgpt_common.c \ host/arch/${ARCH}/lib/crossystem_arch.c \ host/lib/crossystem.c \ host/lib/file_keys.c \ @@ -300,18 +310,37 @@ HOSTLIB_SRCS = \ host/lib/host_keyblock.c \ host/lib/host_misc.c \ host/lib/host_signature.c \ - host/lib/signature_digest.c + host/lib/signature_digest.c \ + utility/dump_kernel_config_lib.c HOSTLIB_OBJS = ${HOSTLIB_SRCS:%.c=${BUILD}/%.o} ALL_OBJS += ${HOSTLIB_OBJS} - # Link with hostlib by default LIBS = $(HOSTLIB) # Might need this too. CRYPTO_LIBS := $(shell ${PKG_CONFIG} --libs libcrypto) +# Sigh. For historical reasons, the autoupdate installer must sometimes be a +# 32-bit executable, even when everything else is 64-bit. But it only needs a +# few functions, so let's just build those. +TINYHOSTLIB = ${BUILD}/libtinyvboot_host.a + +TINYHOSTLIB_SRCS = \ + cgpt/cgpt_create.c \ + cgpt/cgpt_add.c \ + cgpt/cgpt_boot.c \ + cgpt/cgpt_show.c \ + cgpt/cgpt_repair.c \ + cgpt/cgpt_prioritize.c \ + cgpt/cgpt_common.c \ + utility/dump_kernel_config_lib.c \ + firmware/lib/cgptlib/crc32.c \ + firmware/lib/cgptlib/cgptlib_internal.c \ + firmware/stub/utility_stub.c + +TINYHOSTLIB_OBJS = ${TINYHOSTLIB_SRCS:%.c=${BUILD}/%.o} # ---------------------------------------------------------------------------- # Now for the userspace binaries @@ -384,10 +413,6 @@ endif UTIL_BINS_STATIC := $(addprefix ${BUILD}/utility/,${UTIL_NAMES_STATIC}) UTIL_BINS = $(addprefix ${BUILD}/utility/,${UTIL_NAMES}) -ifneq (${IN_CHROOT},) -UTIL_SBINS = $(addprefix ${BUILD}/utility/,mount-encrypted) -endif - ALL_DEPS += $(addsuffix .d,${UTIL_BINS}) @@ -411,7 +436,7 @@ SIGNING_COMMON = scripts/image_signing/common_minimal.sh FUTIL_BIN = ${BUILD}/futility/futility # These are the others it will replace. -FUTIL_OLD = $(notdir ${CGPT} ${UTIL_BINS} ${UTIL_SCRIPTS} ${UTIL_SBINS} \ +FUTIL_OLD = $(notdir ${CGPT} ${UTIL_BINS} ${UTIL_SCRIPTS} \ ${SIGNING_SCRIPTS} ${SIGNING_SCRIPTS_DEV}) FUTIL_SRCS = \ @@ -469,11 +494,6 @@ TEST_NAMES = \ vboot_kernel_tests \ vboot_nvstorage_test -# Grrr -ifneq (${IN_CHROOT},) -TEST_NAMES += CgptManagerTests -endif - # TODO: port these tests to new API, if not already eqivalent # functionality in other tests. These don't even compile at present. # @@ -516,29 +536,6 @@ ALL_DEPS += $(addsuffix .d,${TEST_BINS}) # Directory containing test keys TEST_KEYS = ${SRC_RUN}/tests/testkeys -# ---------------------------------------------------------------------------- -# TODO: why not make this include *all* the cgpt files, and simply have -# cgpt link against it? -# TODO: CgptManager.cc should move to the installer project. Shouldn't be -# in libcgpt-cc.a. -AU_CGPTLIB_SRCS = \ - cgpt/CgptManager.cc \ - cgpt/cgpt_create.c \ - cgpt/cgpt_add.c \ - cgpt/cgpt_boot.c \ - cgpt/cgpt_show.c \ - cgpt/cgpt_repair.c \ - cgpt/cgpt_prioritize.c \ - cgpt/cgpt_common.c \ - firmware/lib/cgptlib/crc32.c \ - firmware/lib/cgptlib/cgptlib_internal.c \ - firmware/stub/utility_stub.c - -AU_CGPTLIB_OBJS = $(filter %.o, \ - ${AU_CGPTLIB_SRCS:%.c=${BUILD}/%.o} \ - ${AU_CGPTLIB_SRCS:%.cc=${BUILD}/%.o}) -ALL_OBJS += ${AU_CGPTLIB_OBJS} - ############################################################################## # Finally, some targets. High-level ones first. @@ -559,10 +556,6 @@ all: fwlib $(if ${FIRMWARE_ARCH},,host_stuff) $(if ${COV},coverage) .PHONY: host_stuff host_stuff: hostlib cgpt utils futil tests -# AU targets -.PHONY: au_stuff -au_stuff: libcgpt_cc libdump_kernel_config cgptmanager_tests - .PHONY: clean clean: ${Q}/bin/rm -rf ${BUILD} @@ -622,8 +615,20 @@ ifeq (${FIRMWARE_ARCH},) ${FWLIB_OBJS}: CFLAGS += -DDISABLE_ROLLBACK_TPM endif +# Link tests +${BUILD}/firmware/linktest/main_vbinit: LIBS = +${BUILD}/firmware/linktest/main_vbinit: OBJS = ${VBINIT_OBJS} +${BUILD}/firmware/linktest/main_vbsf: LIBS = +${BUILD}/firmware/linktest/main_vbsf: OBJS = ${VBSF_OBJS} + +.phony: fwlinktest +fwlinktest: ${FWLIB} \ + ${BUILD}/firmware/linktest/main_vbinit \ + ${BUILD}/firmware/linktest/main_vbsf \ + ${BUILD}/firmware/linktest/main + .PHONY: fwlib -fwlib: ${FWLIB} $(if ${FIRMWARE_ARCH},,${BUILD}/firmware/linktest/main) +fwlib: ${FWLIB} $(if ${FIRMWARE_ARCH},,fwlinktest) ${FWLIB}: ${FWLIB_OBJS} @printf " RM $(subst ${BUILD}/,,$@)\n" @@ -648,6 +653,18 @@ ${HOSTLIB}: ${HOSTLIB_OBJS} ${FWLIB_OBJS} @printf " AR $(subst ${BUILD}/,,$@)\n" ${Q}ar qc $@ $^ + +# Ugh. This is a very cut-down version of HOSTLIB just for the installer. +.PHONY: tinyhostlib +tinyhostlib: ${TINYHOSTLIB} + ${Q}cp -f ${TINYHOSTLIB} ${HOSTLIB} + +${TINYHOSTLIB}: ${TINYHOSTLIB_OBJS} + @printf " RM $(subst ${BUILD}/,,$@)\n" + ${Q}rm -f $@ + @printf " AR $(subst ${BUILD}/,,$@)\n" + ${Q}ar qc $@ $^ + # ---------------------------------------------------------------------------- # CGPT library and utility @@ -677,24 +694,15 @@ ${BUILD}/utility/%: INCLUDES += -Ihost/include -Iutility/include ${UTIL_BINS_STATIC}: LDFLAGS += -static .PHONY: utils -utils: ${UTIL_BINS} ${UTIL_SCRIPTS} ${UTIL_SBINS} +utils: ${UTIL_BINS} ${UTIL_SCRIPTS} ${Q}cp -f ${UTIL_SCRIPTS} ${BUILD}/utility ${Q}chmod a+rx $(patsubst %,${BUILD}/%,${UTIL_SCRIPTS}) .PHONY: utils_install -utils_install: ${UTIL_BINS} ${UTIL_SCRIPTS} ${UTIL_SBINS} +utils_install: ${UTIL_BINS} ${UTIL_SCRIPTS} @printf " INSTALL UTILS\n" ${Q}mkdir -p ${UB_DIR} ${Q}${INSTALL} -t ${UB_DIR} ${UTIL_BINS} ${UTIL_SCRIPTS} -ifneq (${UTIL_SBINS},) - ${Q}${INSTALL} -t ${UB_DIR} ${UTIL_SBINS} -ifneq (${SB_DIR},) - ${Q}mkdir -p ${SB_DIR} - ${Q}for prog in $(notdir ${UTIL_SBINS}); do \ - ln -sf "${FT_DIR}/futility" "${SB_DIR}/$$prog"; done -endif -endif - # And some signing stuff for the target .PHONY: signing_install @@ -729,44 +737,6 @@ futil_install: ${FUTIL_BIN} ln -sf futility "${F_DIR}/$$prog"; done # ---------------------------------------------------------------------------- -# Mount-encrypted utility for cryptohome - -# TODO: mount-encrypted should move to cryptohome and just link against -# vboot-host.a for tlcl and crossystem. - -# The embedded libcrypto conflicts with the shipped openssl, -# so mount-* builds without the common CFLAGS (and those includes). - -${BUILD}/utility/mount-helpers.o: \ - utility/mount-helpers.c \ - utility/mount-helpers.h \ - utility/mount-encrypted.h - @printf " CCm-e $(subst ${BUILD}/,,$@)\n" - ${Q}${CC} -Wall -Werror -O2 -D_FORTIFY_SOURCE=2 -fstack-protector \ - ${COV_FLAGS} \ - $(shell ${PKG_CONFIG} --cflags glib-2.0 openssl) \ - -c $< -o $@ - -${BUILD}/utility/mount-encrypted: \ - utility/mount-encrypted.c \ - utility/mount-encrypted.h \ - ${BUILD}/utility/mount-helpers.o ${LIBS} - @printf " CCm-exe $(subst ${BUILD}/,,$@)\n" - ${Q}${CC} -Wall -Werror -O2 -D_FORTIFY_SOURCE=2 -fstack-protector \ - $(shell ${PKG_CONFIG} --cflags glib-2.0 openssl) \ - -Ifirmware/include \ - -Ihost/include \ - ${COV_FLAGS} \ - ${LDFLAGS} \ - $< -o $@ \ - ${BUILD}/utility/mount-helpers.o ${LIBS} \ - $(shell ${PKG_CONFIG} --libs glib-2.0 openssl) \ - -lm -ifneq (${COV},) - ${Q}mv -f mount-encrypted.gcno ${BUILD}/utility -endif - -# ---------------------------------------------------------------------------- # Utility to generate TLCL structure definition header file. ${BUILD}/utility/tlcl_generator: CFLAGS += -fpack-struct @@ -783,32 +753,6 @@ update_tlcl_structures: ${BUILD}/utility/tlcl_generator cp ${STRUCTURES_TMP} ${STRUCTURES_SRC} ) # ---------------------------------------------------------------------------- -# Library to dump kernel config -# Used by platform/installer, as well as standalone utility. - -.PHONY: libdump_kernel_config -libdump_kernel_config: ${DUMPKERNELCONFIGLIB} - -${DUMPKERNELCONFIGLIB}: ${BUILD}/utility/dump_kernel_config_lib.o - @printf " RM $(subst ${BUILD}/,,$@)\n" - ${Q}rm -f $@ - @printf " AR $(subst ${BUILD}/,,$@)\n" - ${Q}ar qc $@ $^ - -# ---------------------------------------------------------------------------- -# And this thing. - -.PHONY: libcgpt_cc -libcgpt_cc: ${AU_CGPTLIB} - -${AU_CGPTLIB}: INCLUDES += -Ifirmware/lib/cgptlib/include -${AU_CGPTLIB}: ${AU_CGPTLIB_OBJS} - @printf " RM $(subst ${BUILD}/,,$@)\n" - ${Q}rm -f $@ - @printf " AR $(subst ${BUILD}/,,$@)\n" - ${Q}ar qc $@ $^ - -# ---------------------------------------------------------------------------- # Tests .PHONY: tests @@ -858,10 +802,6 @@ ${BUILD}/%.o: %.cc # Linktest ensures firmware lib doesn't rely on outside libraries ${BUILD}/firmware/linktest/main: LIBS = ${FWLIB} -# Specific dependency here. -${BUILD}/utility/dump_kernel_config: LIBS += ${DUMPKERNELCONFIGLIB} -${BUILD}/utility/dump_kernel_config: ${DUMPKERNELCONFIGLIB} - # GBB utility needs C++ linker. TODO: It shouldn't. ${BUILD}/utility/gbb_utility: LD = ${CXX} @@ -918,15 +858,6 @@ ${BUILD}/tests/vboot_audio_tests: OBJS += \ ${BUILD}/tests/vboot_audio_tests: \ ${BUILD}/firmware/lib/vboot_audio_for_test.o -.PHONY: cgptmanager_tests -cgptmanager_tests: ${BUILD}/tests/CgptManagerTests - -${BUILD}/tests/CgptManagerTests: CFLAGS += ${PC_CFLAGS} -${BUILD}/tests/CgptManagerTests: LD = ${CXX} -${BUILD}/tests/CgptManagerTests: LDLIBS += -lgtest -lgflags ${PC_LDLIBS} -${BUILD}/tests/CgptManagerTests: LIBS = ${AU_CGPTLIB} -${BUILD}/tests/CgptManagerTests: ${AU_CGPTLIB} - ${BUILD}/tests/rollback_index_test: INCLUDES += -I/usr/include ${BUILD}/tests/rollback_index_test: LIBS += -ltlcl @@ -988,10 +919,6 @@ runbmptests: test_setup .PHONY: runcgpttests runcgpttests: test_setup ${RUNTEST} ${BUILD_RUN}/tests/cgptlib_test -# HEY - elsewhere -ifneq (${IN_CHROOT},) - ${RUNTEST} ${BUILD_RUN}/tests/CgptManagerTests --v=1 -endif .PHONY: runtestscripts runtestscripts: test_setup genfuzztestcases diff --git a/cgpt/CgptManager.cc b/cgpt/CgptManager.cc deleted file mode 100644 index a1a018a3..00000000 --- a/cgpt/CgptManager.cc +++ /dev/null @@ -1,429 +0,0 @@ -// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <string.h> - -#include "CgptManager.h" - -extern "C" { -#include "cgpt_params.h" -} - -using std::string; - -// We don't use these variables for the libcgpt version. -const char* progname = ""; -const char* command = ""; -void (*uuid_generator)(uint8_t* buffer) = NULL; - - -// This file implements the C++ wrapper methods over the C cgpt methods. - -CgptManager::CgptManager(): - is_initialized_(false) { -} - -CgptManager::~CgptManager() { -} - -CgptErrorCode CgptManager::Initialize(const string& device_name) { - device_name_ = device_name; - is_initialized_ = true; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::ClearAll() { - if (!is_initialized_) - return kCgptNotInitialized; - - CgptCreateParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.zap = 0; - - int retval = cgpt_create(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - return kCgptSuccess; -} - -CgptErrorCode CgptManager::AddPartition(const string& label, - const Guid& partition_type_guid, - const Guid& unique_id, - uint64_t beginning_offset, - uint64_t num_sectors) { - if (!is_initialized_) - return kCgptNotInitialized; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.label = const_cast<char *>(label.c_str()); - - params.type_guid = partition_type_guid; - params.set_type = 1; - - params.begin = beginning_offset; - params.set_begin = 1; - - params.size = num_sectors; - params.set_size = 1; - - if (!IsZero(&unique_id)) { - params.unique_guid = unique_id; - params.set_unique = 1; - } - - int retval = cgpt_add(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - return kCgptSuccess; -} - -CgptErrorCode CgptManager::GetNumNonEmptyPartitions(uint8_t* num_partitions) const { - if (!is_initialized_) - return kCgptNotInitialized; - - if (!num_partitions) - return kCgptInvalidArgument; - - CgptShowParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - int retval = cgpt_get_num_non_empty_partitions(¶ms); - - if (retval != CGPT_OK) - return kCgptUnknownError; - - *num_partitions = params.num_partitions; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::SetPmbr(uint32_t boot_partition_number, - const string& boot_file_name, - bool should_create_legacy_partition) { - if (!is_initialized_) - return kCgptNotInitialized; - - CgptBootParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - if (!boot_file_name.empty()) - params.bootfile = const_cast<char *>(boot_file_name.c_str()); - - params.partition = boot_partition_number; - params.create_pmbr = should_create_legacy_partition; - - int retval = cgpt_boot(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - return kCgptSuccess; -} - -CgptErrorCode CgptManager::GetPmbrBootPartitionNumber( - uint32_t* boot_partition) const { - if (!is_initialized_) - return kCgptNotInitialized; - - if (!boot_partition) - return kCgptInvalidArgument; - - CgptBootParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - - int retval = cgpt_get_boot_partition_number(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - *boot_partition = params.partition; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::SetSuccessful( - uint32_t partition_number, - bool is_successful) { - if (!is_initialized_) - return kCgptNotInitialized; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.partition = partition_number; - - params.successful = is_successful; - params.set_successful = true; - - int retval = cgpt_set_attributes(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - return kCgptSuccess; -} - -CgptErrorCode CgptManager::GetSuccessful(uint32_t partition_number, - bool* is_successful) const { - if (!is_initialized_) - return kCgptNotInitialized; - - if (!is_successful) - return kCgptInvalidArgument; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.partition = partition_number; - - int retval = cgpt_get_partition_details(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - *is_successful = params.successful; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::SetNumTriesLeft(uint32_t partition_number, - int numTries) { - if (!is_initialized_) - return kCgptNotInitialized; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.partition = partition_number; - - params.tries = numTries; - params.set_tries = true; - - int retval = cgpt_set_attributes(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - return kCgptSuccess; -} - -CgptErrorCode CgptManager::GetNumTriesLeft(uint32_t partition_number, - int* numTries) const { - if (!is_initialized_) - return kCgptNotInitialized; - - if (!numTries) - return kCgptInvalidArgument; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.partition = partition_number; - - int retval = cgpt_get_partition_details(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - *numTries = params.tries; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::SetPriority(uint32_t partition_number, - uint8_t priority) { - if (!is_initialized_) - return kCgptNotInitialized; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.partition = partition_number; - - params.priority = priority; - params.set_priority = true; - - int retval = cgpt_set_attributes(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - return kCgptSuccess; -} - -CgptErrorCode CgptManager::GetPriority(uint32_t partition_number, - uint8_t* priority) const { - if (!is_initialized_) - return kCgptNotInitialized; - - if (!priority) - return kCgptInvalidArgument; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.partition = partition_number; - - int retval = cgpt_get_partition_details(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - *priority = params.priority; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::GetBeginningOffset(uint32_t partition_number, - uint64_t* offset) const { - if (!is_initialized_) - return kCgptNotInitialized; - - if (!offset) - return kCgptInvalidArgument; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.partition = partition_number; - - int retval = cgpt_get_partition_details(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - *offset = params.begin; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::GetNumSectors(uint32_t partition_number, - uint64_t* num_sectors) const { - if (!is_initialized_) - return kCgptNotInitialized; - - if (!num_sectors) - return kCgptInvalidArgument; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.partition = partition_number; - - int retval = cgpt_get_partition_details(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - *num_sectors = params.size; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::GetPartitionTypeId(uint32_t partition_number, - Guid* type_id) const { - if (!is_initialized_) - return kCgptNotInitialized; - - if (!type_id) - return kCgptInvalidArgument; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.partition = partition_number; - - int retval = cgpt_get_partition_details(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - *type_id = params.type_guid; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::GetPartitionUniqueId(uint32_t partition_number, - Guid* unique_id) const { - if (!is_initialized_) - return kCgptNotInitialized; - - if (!unique_id) - return kCgptInvalidArgument; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.partition = partition_number; - - int retval = cgpt_get_partition_details(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - *unique_id = params.unique_guid; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::GetPartitionNumberByUniqueId( - const Guid& unique_id, - uint32_t* partition_number) const { - if (!is_initialized_) - return kCgptNotInitialized; - - if (!partition_number) - return kCgptInvalidArgument; - - CgptAddParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.unique_guid = unique_id; - params.set_unique = 1; - - int retval = cgpt_get_partition_details(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - *partition_number = params.partition; - return kCgptSuccess; -} - -CgptErrorCode CgptManager::SetHighestPriority(uint32_t partition_number, - uint8_t highest_priority) { - if (!is_initialized_) - return kCgptNotInitialized; - - CgptPrioritizeParams params; - memset(¶ms, 0, sizeof(params)); - - params.drive_name = const_cast<char *>(device_name_.c_str()); - params.set_partition = partition_number; - params.max_priority = highest_priority; - - int retval = cgpt_prioritize(¶ms); - if (retval != CGPT_OK) - return kCgptUnknownError; - - return kCgptSuccess; -} - -CgptErrorCode CgptManager::SetHighestPriority(uint32_t partition_number) { - // The internal implementation in cgpt_prioritize automatically computes the - // right priority number if we supply 0 for the highest_priority argument. - return SetHighestPriority(partition_number, 0); -} - -CgptErrorCode CgptManager::Validate() { - if (!is_initialized_) - return kCgptNotInitialized; - - uint8_t num_partitions; - - // GetNumNonEmptyPartitions does the check for GptSanityCheck. - // so call it (ignore the num_partitions result) and just return - // its success/failure result. - return GetNumNonEmptyPartitions(&num_partitions); -} diff --git a/cgpt/CgptManager.h b/cgpt/CgptManager.h deleted file mode 100644 index 2dbca6f2..00000000 --- a/cgpt/CgptManager.h +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef VBOOT_REFERENCE_CGPT_CGPTMANAGER_H_ -#define VBOOT_REFERENCE_CGPT_CGPTMANAGER_H_ - -#include <string> -#include "gpt.h" - -// This file defines a simple C++ wrapper class interface for the cgpt methods. - -// These are the possible error codes that can be returned by the CgptManager. -typedef enum CgptErrorCode -{ - kCgptSuccess = 0, - kCgptNotInitialized = 1, - kCgptUnknownError = 2, - kCgptInvalidArgument = 3, -} CgptErrorCode; - - -// CgptManager exposes methods to manipulate the Guid Partition Table as needed -// for ChromeOS scenarios. -class CgptManager { - public: - // Default constructor. The Initialize method must be called before - // any other method can be called on this class. - CgptManager(); - - // Destructor. Automatically closes any opened device. - ~CgptManager(); - - // Opens the given device_name (e.g. "/dev/sdc") and initializes - // with the Guid Partition Table of that device. This is the first method - // that should be called on this class. Otherwise those methods will - // return kCgptNotInitialized. - // Returns kCgptSuccess or an appropriate error code. - // This device is automatically closed when this object is destructed. - CgptErrorCode Initialize(const std::string& device_name); - - // Clears all the existing contents of the GPT and PMBR on the current - // device. - CgptErrorCode ClearAll(); - - // Adds a new partition at the end of the existing partitions - // with the new label, type, unique Id, offset and size. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode AddPartition(const std::string& label, - const Guid& partition_type_guid, - const Guid& unique_id, - uint64_t beginning_offset, - uint64_t num_sectors); - - // Populates num_partitions parameter with the number of partitions - // that are currently on this device and not empty. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode GetNumNonEmptyPartitions(uint8_t* num_partitions) const; - - // Sets the Protective Master Boot Record on this device with the given - // boot_partition number after populating the MBR with the contents of the - // given boot_file_name. It also creates a legacy partition if - // should_create_legacy_partition is true. - // Note: Strictly speaking, the PMBR is not part of the GPT, but it is - // included here for ease of use. - CgptErrorCode SetPmbr(uint32_t boot_partition_number, - const std::string& boot_file_name, - bool should_create_legacy_partition); - - // Populates boot_partition with the partition number that's set to - // boot in the PMBR. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode GetPmbrBootPartitionNumber(uint32_t* boot_partition) const; - - // Sets the "successful" attribute of the given kernelPartition to 0 or 1 - // based on the value of is_successful being true (1) or false(0) - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode SetSuccessful(uint32_t partition_number, bool is_successful); - - // Populates is_successful to true if the successful attribute in the - // given kernelPartition is non-zero, or to false if it's zero. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode GetSuccessful(uint32_t partition_number, - bool* is_successful) const; - - // Sets the "NumTriesLeft" attribute of the given kernelPartition to - // the given num_tries_left value. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode SetNumTriesLeft(uint32_t partition_number, - int num_tries_left); - - // Populates the num_tries_left parameter with the value of the - // NumTriesLeft attribute of the given kernelPartition. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode GetNumTriesLeft(uint32_t partition_number, - int* num_tries_left) const; - - // Sets the "Priority" attribute of the given kernelPartition to - // the given priority value. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode SetPriority(uint32_t partition_number, - uint8_t priority); - - // Populates the priority parameter with the value of the Priority - // attribute of the given kernelPartition. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode GetPriority(uint32_t partition_number, - uint8_t* priority) const; - - // Populates the offset parameter with the beginning offset of the - // given partition. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode GetBeginningOffset(uint32_t partition_number, - uint64_t* offset) const; - - // Populates the number of sectors in the given partition. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode GetNumSectors(uint32_t partition_number, - uint64_t* num_sectors) const; - - // Populates the type_id parameter with the partition type id - // (these are the standard ids for kernel, rootfs, etc.) - // of the partition corresponding to the given partition_number. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode GetPartitionTypeId(uint32_t partition_number, - Guid* type_id) const; - - // Populates the unique_id parameter with the Guid that uniquely identifies - // the given partition_number. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode GetPartitionUniqueId(uint32_t partition_number, - Guid* unique_id) const; - - // Populates the partition_number parameter with the partition number of - // the partition which is uniquely identified by the given unique_id. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode GetPartitionNumberByUniqueId( - const Guid& unique_id, - uint32_t* partition_number) const; - - // Sets the "Priority" attribute of given kernelPartition to the value - // specified in higestPriority parameter. In addition, also reduces the - // priorities of all the other kernel partitions, if necessary, to ensure - // no other partition has a higher priority. It does preserve the relative - // ordering among the remaining partitions and doesn't touch the partitions - // whose priorities are zero. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode SetHighestPriority(uint32_t partition_number, - uint8_t highest_priority); - - // Same as SetHighestPriority above but works without having to explicitly - // give a value for highest_priority. The internal implementation figures - // out the best highest number that needs to be given depending on the - // existing priorities. - // Returns kCgptSuccess or an appropriate error code. - CgptErrorCode SetHighestPriority(uint32_t partition_number); - - // Runs the sanity checks on the CGPT and MBR and - // Returns kCgptSuccess if everything is valid or an appropriate error code - // if there's anything invalid or if there's any error encountered during - // the validation. - CgptErrorCode Validate(); - - private: - std::string device_name_; - bool is_initialized_; - - CgptManager(const CgptManager &); - void operator=(const CgptManager &); -}; - -#endif // VBOOT_REFERENCE_CGPT_CGPTMANAGER_H_ diff --git a/firmware/lib/include/vboot_display.h b/firmware/lib/include/vboot_display.h index 52730b9e..17ce48b8 100644 --- a/firmware/lib/include/vboot_display.h +++ b/firmware/lib/include/vboot_display.h @@ -34,7 +34,7 @@ ImageInfo *VbFindFontGlyph(VbFont_t *font, uint32_t ascii, /** * Try to display the specified text at a particular position. */ -void VbRenderTextAtPos(char *text, int right_to_left, +void VbRenderTextAtPos(const char *text, int right_to_left, uint32_t x, uint32_t y, VbFont_t *font); /** @@ -45,7 +45,7 @@ const char *RecoveryReasonString(uint8_t code); /** * Return a fixed string representing the HWID. */ -char *VbHWID(VbCommonParams *cparams); +const char *VbHWID(VbCommonParams *cparams); /** * Get the number of localizations in the GBB bitmap data. diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h index e3a44190..1243cb84 100644 --- a/firmware/lib/include/vboot_kernel.h +++ b/firmware/lib/include/vboot_kernel.h @@ -12,7 +12,6 @@ #include "cgptlib.h" #include "load_firmware_fw.h" #include "vboot_api.h" -#include "vboot_kernel.h" /** * Allocate and read GPT data from the drive. The sector_bytes and diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c index a7b65510..0c6e02ac 100644 --- a/firmware/lib/rollback_index.c +++ b/firmware/lib/rollback_index.c @@ -17,6 +17,15 @@ #define offsetof(A,B) __builtin_offsetof(A,B) #endif +/* + * Provide protoypes for functions not in the header file. These prototypes + * fix -Wmissing-prototypes warnings. + */ +uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf); +uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf); +uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk); +uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk); + #ifdef FOR_TEST /* * Compiling for unit test, so we need the real implementations of @@ -33,11 +42,11 @@ static int g_rollback_recovery_mode = 0; __pragma(warning (disable: 4127)) #define RETURN_ON_FAILURE(tpm_command) do { \ - uint32_t result; \ - if ((result = (tpm_command)) != TPM_SUCCESS) { \ + uint32_t result_; \ + if ((result_ = (tpm_command)) != TPM_SUCCESS) { \ VBDEBUG(("Rollback: %08x returned by " #tpm_command \ - "\n", (int)result)); \ - return result; \ + "\n", (int)result_)); \ + return result_; \ } \ } while (0) diff --git a/firmware/lib/tpm_bootmode.c b/firmware/lib/tpm_bootmode.c index ec8fac7e..218db207 100644 --- a/firmware/lib/tpm_bootmode.c +++ b/firmware/lib/tpm_bootmode.c @@ -96,7 +96,8 @@ const uint8_t kBootInvalidSHA1Digest[] = { * Given the boot state, return the correct SHA1 digest index for TPMExtend * in kBootStateSHA1Digests[]. */ -int GetBootStateIndex(int dev_mode, int rec_mode, uint64_t keyblock_flags) +static int GetBootStateIndex(int dev_mode, int rec_mode, + uint64_t keyblock_flags) { int index = 0; diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index a55d8064..483d47ed 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -13,6 +13,7 @@ #include "vboot_audio.h" #include "vboot_common.h" #include "vboot_display.h" +#include "vboot_kernel.h" #include "vboot_nvstorage.h" /* Global variables */ diff --git a/firmware/lib/vboot_common.c b/firmware/lib/vboot_common.c index 50a4cff8..3e3375f1 100644 --- a/firmware/lib/vboot_common.c +++ b/firmware/lib/vboot_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +/* 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. * @@ -430,38 +430,6 @@ int VerifyKernelPreamble(const VbKernelPreambleHeader *preamble, return VBOOT_SUCCESS; } -int VbSharedDataInit(VbSharedDataHeader *header, uint64_t size) -{ - VBDEBUG(("VbSharedDataInit, %d bytes, header %d bytes\n", (int)size, - sizeof(VbSharedDataHeader))); - - if (size < sizeof(VbSharedDataHeader)) { - VBDEBUG(("Not enough data for header.\n")); - return VBOOT_SHARED_DATA_INVALID; - } - if (size < VB_SHARED_DATA_MIN_SIZE) { - VBDEBUG(("Shared data buffer too small.\n")); - return VBOOT_SHARED_DATA_INVALID; - } - - if (!header) - return VBOOT_SHARED_DATA_INVALID; - - /* Zero the header */ - Memset(header, 0, sizeof(VbSharedDataHeader)); - - /* Initialize fields */ - header->magic = VB_SHARED_DATA_MAGIC; - header->struct_version = VB_SHARED_DATA_VERSION; - header->struct_size = sizeof(VbSharedDataHeader); - header->data_size = size; - header->data_used = sizeof(VbSharedDataHeader); - header->firmware_index = 0xFF; - - /* Success */ - return VBOOT_SUCCESS; -} - uint64_t VbSharedDataReserve(VbSharedDataHeader *header, uint64_t size) { uint64_t offs = header->data_used; diff --git a/firmware/lib/vboot_common_init.c b/firmware/lib/vboot_common_init.c new file mode 100644 index 00000000..9d6670ea --- /dev/null +++ b/firmware/lib/vboot_common_init.c @@ -0,0 +1,43 @@ +/* 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. + * + * Common functions between firmware and kernel verified boot. + * (Firmware portion) + */ + +#include "vboot_api.h" +#include "vboot_common.h" +#include "utility.h" + +int VbSharedDataInit(VbSharedDataHeader *header, uint64_t size) +{ + VBDEBUG(("VbSharedDataInit, %d bytes, header %d bytes\n", (int)size, + sizeof(VbSharedDataHeader))); + + if (size < sizeof(VbSharedDataHeader)) { + VBDEBUG(("Not enough data for header.\n")); + return VBOOT_SHARED_DATA_INVALID; + } + if (size < VB_SHARED_DATA_MIN_SIZE) { + VBDEBUG(("Shared data buffer too small.\n")); + return VBOOT_SHARED_DATA_INVALID; + } + + if (!header) + return VBOOT_SHARED_DATA_INVALID; + + /* Zero the header */ + Memset(header, 0, sizeof(VbSharedDataHeader)); + + /* Initialize fields */ + header->magic = VB_SHARED_DATA_MAGIC; + header->struct_version = VB_SHARED_DATA_VERSION; + header->struct_size = sizeof(VbSharedDataHeader); + header->data_size = size; + header->data_used = sizeof(VbSharedDataHeader); + header->firmware_index = 0xFF; + + /* Success */ + return VBOOT_SUCCESS; +} diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c index 7c916d01..9abc51d9 100644 --- a/firmware/lib/vboot_display.c +++ b/firmware/lib/vboot_display.c @@ -46,7 +46,7 @@ VbError_t VbGetLocalizationCount(VbCommonParams *cparams, uint32_t *count) return VBERROR_SUCCESS; } -char *VbHWID(VbCommonParams *cparams) +const char *VbHWID(VbCommonParams *cparams) { GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader *)cparams->gbb_data; @@ -120,7 +120,7 @@ ImageInfo *VbFindFontGlyph(VbFont_t *font, uint32_t ascii, return &(entry->info); } -void VbRenderTextAtPos(char *text, int right_to_left, +void VbRenderTextAtPos(const char *text, int right_to_left, uint32_t x, uint32_t y, VbFont_t *font) { int i; @@ -182,7 +182,7 @@ VbError_t VbDisplayScreenFromGBB(VbCommonParams *cparams, uint32_t screen, uint32_t offset; uint32_t i; VbFont_t *font; - char *text_to_show; + const char *text_to_show; int rtol = 0; char outbuf[OUTBUF_LEN] = ""; uint32_t used = 0; diff --git a/firmware/linktest/main_vbinit.c b/firmware/linktest/main_vbinit.c new file mode 100644 index 00000000..a3d50196 --- /dev/null +++ b/firmware/linktest/main_vbinit.c @@ -0,0 +1,13 @@ +/* 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. + */ + +#include "vboot_api.h" + +int main(void) +{ + /* vboot_api.h - entry points INTO vboot_reference */ + VbInit(0, 0); + return 0; +} diff --git a/firmware/linktest/main_vbsf.c b/firmware/linktest/main_vbsf.c new file mode 100644 index 00000000..1a3825a8 --- /dev/null +++ b/firmware/linktest/main_vbsf.c @@ -0,0 +1,14 @@ +/* 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. + */ + +#include "vboot_api.h" + +int main(void) +{ + /* vboot_api.h - entry points INTO vboot_reference */ + VbSelectFirmware(0, 0); + VbUpdateFirmwareBodyHash(0, 0, 0); + return 0; +} diff --git a/firmware/stub/utility_stub.c b/firmware/stub/utility_stub.c index e3ec19be..549ee851 100644 --- a/firmware/stub/utility_stub.c +++ b/firmware/stub/utility_stub.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* 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. * @@ -15,18 +15,19 @@ #include <string.h> #include <sys/time.h> - -int Memcmp(const void* src1, const void* src2, size_t n) { - return memcmp(src1, src2, n); +int Memcmp(const void *src1, const void *src2, size_t n) +{ + return memcmp(src1, src2, n); } - -void* Memcpy(void* dest, const void* src, uint64_t n) { - return memcpy(dest, src, (size_t)n); +void *Memcpy(void *dest, const void *src, uint64_t n) +{ + return memcpy(dest, src, (size_t)n); } -void* Memset(void* d, const uint8_t c, uint64_t n) { - return memset(d, c, n); +void *Memset(void *d, const uint8_t c, uint64_t n) +{ + return memset(d, c, n); } diff --git a/firmware/stub/vboot_api_stub.c b/firmware/stub/vboot_api_stub.c index c71c38ac..1829764f 100644 --- a/firmware/stub/vboot_api_stub.c +++ b/firmware/stub/vboot_api_stub.c @@ -18,66 +18,6 @@ /* disable MSVC warnings on unused arguments */ __pragma(warning (disable: 4100)) - -/* U-Boot's printf uses '%L' for uint64_t. gcc uses '%l'. */ -#define MAX_FMT 255 -static char fmtbuf[MAX_FMT+1]; - -static const char *fixfmt(const char *format) -{ - int i; - for(i=0; i<MAX_FMT && format[i]; i++) { - fmtbuf[i] = format[i]; - if(format[i] == '%' && format[i+1] == 'L') { - fmtbuf[i+1] = 'l'; - i++; - } - } - fmtbuf[i] = '\0'; - return fmtbuf; -} - -void VbExError(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - fprintf(stderr, "ERROR: "); - vfprintf(stderr, fixfmt(format), ap); - va_end(ap); - exit(1); -} - -void VbExDebug(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - fprintf(stderr, "DEBUG: "); - vfprintf(stderr, fixfmt(format), ap); - va_end(ap); -} - -void *VbExMalloc(size_t size) -{ - void *p = malloc(size); - if (!p) { - /* Fatal Error. We must abort. */ - abort(); - } - return p; -} - -void VbExFree(void *ptr) -{ - free(ptr); -} - -uint64_t VbExGetTimer(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec; -} - void VbExSleepMs(uint32_t msec) { } @@ -87,22 +27,6 @@ VbError_t VbExBeep(uint32_t msec, uint32_t frequency) return VBERROR_SUCCESS; } -VbError_t VbExNvStorageRead(uint8_t *buf) -{ - return VBERROR_SUCCESS; -} - -VbError_t VbExNvStorageWrite(const uint8_t *buf) -{ - return VBERROR_SUCCESS; -} - -VbError_t VbExHashFirmwareBody(VbCommonParams *cparams, - uint32_t firmware_index) -{ - return VBERROR_SUCCESS; -} - VbError_t VbExDisplayInit(uint32_t *width, uint32_t *height) { return VBERROR_SUCCESS; diff --git a/firmware/stub/vboot_api_stub_init.c b/firmware/stub/vboot_api_stub_init.c new file mode 100644 index 00000000..76a29175 --- /dev/null +++ b/firmware/stub/vboot_api_stub_init.c @@ -0,0 +1,73 @@ +/* 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. + */ + +#define _STUB_IMPLEMENTATION_ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include "vboot_api.h" + +/* disable MSVC warnings on unused arguments */ +__pragma(warning (disable: 4100)) + +/* U-Boot's printf uses '%L' for uint64_t. gcc uses '%l'. */ +#define MAX_FMT 255 +static char fmtbuf[MAX_FMT+1]; + +static const char *fixfmt(const char *format) +{ + int i; + for(i=0; i<MAX_FMT && format[i]; i++) { + fmtbuf[i] = format[i]; + if(format[i] == '%' && format[i+1] == 'L') { + fmtbuf[i+1] = 'l'; + i++; + } + } + fmtbuf[i] = '\0'; + return fmtbuf; +} + +void VbExError(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + fprintf(stderr, "ERROR: "); + vfprintf(stderr, fixfmt(format), ap); + va_end(ap); + exit(1); +} + +void VbExDebug(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + fprintf(stderr, "DEBUG: "); + vfprintf(stderr, fixfmt(format), ap); + va_end(ap); +} + +uint64_t VbExGetTimer(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec; +} + +VbError_t VbExNvStorageRead(uint8_t *buf) +{ + return VBERROR_SUCCESS; +} + +VbError_t VbExNvStorageWrite(const uint8_t *buf) +{ + return VBERROR_SUCCESS; +} diff --git a/firmware/stub/vboot_api_stub_sf.c b/firmware/stub/vboot_api_stub_sf.c new file mode 100644 index 00000000..41a16467 --- /dev/null +++ b/firmware/stub/vboot_api_stub_sf.c @@ -0,0 +1,40 @@ +/* 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. + */ + +#define _STUB_IMPLEMENTATION_ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include "vboot_api.h" + +/* disable MSVC warnings on unused arguments */ +__pragma(warning (disable: 4100)) + +void *VbExMalloc(size_t size) +{ + void *p = malloc(size); + if (!p) { + /* Fatal Error. We must abort. */ + abort(); + } + return p; +} + +void VbExFree(void *ptr) +{ + free(ptr); +} + +VbError_t VbExHashFirmwareBody(VbCommonParams *cparams, + uint32_t firmware_index) +{ + return VBERROR_SUCCESS; +} diff --git a/tests/CgptManagerTests.cc b/tests/CgptManagerTests.cc deleted file mode 100644 index 35da0d09..00000000 --- a/tests/CgptManagerTests.cc +++ /dev/null @@ -1,403 +0,0 @@ -// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Unit tests for CgptManager class. -#include <string> - -#include "../cgpt/CgptManager.h" - -// We use some specific GUID constants for some of the tests, -// so pulling in cgpt.h. Make sure this is included after -// CgptManager.h so that we can test the actual usage of -// CgptManager.h as the post-install package would use. -// Example: this would catch an incorrect usage of a GUID -// that's defined only in cgpt.h and being accidentally -// used in CgptManager.h (which should not have any cgpt.h -// dependencies). -extern "C" { -#include "../cgpt/cgpt.h" -} - -#include <base/logging.h> -#include <gflags/gflags.h> -#include <gtest/gtest.h> -#include <uuid/uuid.h> - -using std::string; - -static const Guid p2guid = {{{0, 1, 2, 3, 4, {2, 2, 2, 2, 2, 2}}}}; -static const Guid p3guid = {{{0, 6, 5, 4, 2, {3, 3, 3, 3, 3, 3}}}}; - -#define EXPECT_SUCCESS(c) EXPECT_EQ(kCgptSuccess, c) - -// The --v flag controls the log verbosity level. -DEFINE_int32(v, 0, 0); - -// This class unit tests the CgptManager class. -class CgptManagerUnitTest : public ::testing::Test { -public: - CgptManagerUnitTest() { - // Even though the post-installer doesn't use any methods that require - // uuid_generate, for the unit test we use those methods, so we need to - // set the uuid_generator. - uuid_generator = uuid_generate; - } - - void SetUp() { - const string device_name = "/tmp/DummyFileForCgptManagerTests.bin"; - - CreateDummyDevice(device_name); - - LOG(INFO) << "Initializing cgpt with " << device_name; - EXPECT_SUCCESS(cgpt_manager.Initialize(device_name)); - EXPECT_SUCCESS(cgpt_manager.ClearAll()); - - CheckPartitionCount(0); - } - - virtual ~CgptManagerUnitTest() { } - -protected: - CgptManager cgpt_manager; - - void CreateDummyDevice(const string& dummy_device) { - FILE* fp = fopen(dummy_device.c_str(), "w"); - - ASSERT_TRUE(fp != NULL); - - const int kNumSectors = 1000; - const int kSectorSize = 512; - const char kFillChar = '7'; // Some character, value doesn't matter. - - for(int i = 0; i < kNumSectors * kSectorSize; i++) { - EXPECT_EQ(kFillChar, fputc(kFillChar, fp)); - } - - fclose(fp); - } - - void CheckEquality(string field, - uint64_t expected, - uint64_t actual) { - - - VLOG(1) << field << ":" - << "Expected = " << expected - << ";Actual = " << actual; - - EXPECT_EQ(expected, actual); - } - - - void CheckGuidEquality(string field, - const Guid& expected_id, - const Guid& actual_id) { - char expected_id_str[GUID_STRLEN]; - GuidToStr(&expected_id, expected_id_str, sizeof(expected_id_str)); - - char actual_id_str[GUID_STRLEN]; - GuidToStr(&actual_id, actual_id_str, sizeof(actual_id_str)); - - VLOG(1) << field << ":" - << "Expected = " << expected_id_str - << ";Actual = " << actual_id_str; - - EXPECT_TRUE(GuidEqual(&expected_id, &actual_id)); - } - - // Checks if the current number of partitions in the device matches - // the value of expected_num_partitions. - void CheckPartitionCount(uint8 expected_num_partitions) { - uint8_t actual_num_partitions; - EXPECT_SUCCESS(cgpt_manager.GetNumNonEmptyPartitions( - &actual_num_partitions)); - - CheckEquality("NumPartitions", - expected_num_partitions, - actual_num_partitions); - } - - void SetAndCheckSuccessfulBit(uint32_t partition_number, - bool expected_is_successful) { - EXPECT_SUCCESS(cgpt_manager.SetSuccessful(partition_number, - expected_is_successful)); - - bool actual_is_successful; - EXPECT_SUCCESS(cgpt_manager.GetSuccessful(partition_number, - &actual_is_successful)); - EXPECT_EQ(expected_is_successful, actual_is_successful); - } - - - void SetAndCheckNumTriesLeft(uint32_t partition_number, - int expected_num_tries) { - EXPECT_SUCCESS(cgpt_manager.SetNumTriesLeft(partition_number, - expected_num_tries)); - - int actual_num_tries; - EXPECT_SUCCESS(cgpt_manager.GetNumTriesLeft(partition_number, - &actual_num_tries)); - CheckEquality("NumTries", expected_num_tries, actual_num_tries); - } - - void SetAndCheckPriority(uint32_t partition_number, - uint8_t expected_priority) { - EXPECT_SUCCESS(cgpt_manager.SetPriority(partition_number, - expected_priority)); - - uint8_t actual_priority; - EXPECT_SUCCESS(cgpt_manager.GetPriority(partition_number, - &actual_priority)); - CheckEquality("Priority", expected_priority, actual_priority); - } - - void CheckPriority(uint32_t partition_number, - uint8_t expected_priority) { - uint8_t actual_priority; - EXPECT_SUCCESS(cgpt_manager.GetPriority(partition_number, - &actual_priority)); - CheckEquality("Priority", expected_priority, actual_priority); - } - - - void CheckBeginningOffset(uint32_t partition_number, - uint64_t expected_offset) { - uint64_t actual_offset; - EXPECT_SUCCESS(cgpt_manager.GetBeginningOffset(partition_number, - &actual_offset)); - CheckEquality("Beginning Offset", expected_offset, actual_offset); - } - - - void CheckNumSectors(uint32_t partition_number, - uint64_t expected_num_sectors) { - uint64_t actual_num_sectors; - EXPECT_SUCCESS(cgpt_manager.GetNumSectors(partition_number, - &actual_num_sectors)); - CheckEquality("Num Sectors", expected_num_sectors, actual_num_sectors); - } - - - void CheckPartitionTypeId(int partition_number, - const Guid& expected_partition_type_id) { - // Get the partition type id and check if it matches the expected value. - Guid actual_partition_type_id; - EXPECT_SUCCESS(cgpt_manager.GetPartitionTypeId(partition_number, - &actual_partition_type_id)); - - CheckGuidEquality("PartitionTypeId", - expected_partition_type_id, - actual_partition_type_id); - } - - void CheckPartitionUniqueId(int partition_number, - const Guid& expected_partition_unique_id) { - // Get the partition unique id and check if it matches the expected value. - Guid actual_partition_unique_id; - EXPECT_SUCCESS(cgpt_manager.GetPartitionUniqueId( - partition_number, - &actual_partition_unique_id)); - - CheckGuidEquality("PartitionUniqueId", - expected_partition_unique_id, - actual_partition_unique_id); - } - - void CheckPartitionNumberByUniqueId(const Guid& unique_id, - uint32_t expected_partition_number) { - // Get the partition number for the unique id and check - // if it matches the expected value. - uint32_t actual_partition_number; - EXPECT_SUCCESS(cgpt_manager.GetPartitionNumberByUniqueId( - unique_id, - &actual_partition_number)); - - CheckEquality("PartitionNumberForUniqueId", - expected_partition_number, - actual_partition_number); - } - - - void CreateBootFile(const string& boot_file_name) { - FILE* fp = fopen(boot_file_name.c_str(), "w"); - - ASSERT_TRUE(fp != NULL); - - const int kNumSectors = 1; - const int kSectorSize = 512; - const char kFillChar = '8'; // Some character, value doesn't matter. - - for(int i = 0; i < kNumSectors * kSectorSize; i++) { - EXPECT_EQ(kFillChar, fputc(kFillChar, fp)); - } - - fclose(fp); - } - -private: - DISALLOW_COPY_AND_ASSIGN(CgptManagerUnitTest); -}; - -TEST_F(CgptManagerUnitTest, AutoPrioritizationTest) { - EXPECT_SUCCESS(cgpt_manager.AddPartition("k1", - guid_chromeos_kernel, - guid_unused, - 100, - 10)); - CheckPartitionCount(1); - - EXPECT_SUCCESS(cgpt_manager.AddPartition("k2", - guid_chromeos_kernel, - p2guid, - 200, - 20)); - CheckPartitionCount(2); - - EXPECT_SUCCESS(cgpt_manager.AddPartition("k3", - guid_chromeos_kernel, - p3guid, - 300, - 30)); - CheckPartitionCount(3); - - uint8_t expectedk1Priority = 1; - uint8_t expectedk2Priority = 2; - uint8_t expectedk3Priority = 0; - - // Calling SetAndCheckPriority will do a set and get of the above priorities. - SetAndCheckPriority(1, expectedk1Priority); - SetAndCheckPriority(2, expectedk2Priority); - SetAndCheckPriority(3, expectedk3Priority); - - EXPECT_SUCCESS(cgpt_manager.SetHighestPriority(1)); - - expectedk1Priority = 2; - expectedk2Priority = 1; - - CheckPriority(1, expectedk1Priority); - CheckPriority(2, expectedk2Priority); - CheckPriority(3, expectedk3Priority); -} - - -TEST_F(CgptManagerUnitTest, AddPartitionTest) { - int p2_offset = 200; - int p2_size = 20; - int p3_offset = 300; - int p3_size = 30; - - VLOG(1) << "Adding various types of partitions ... "; - EXPECT_SUCCESS(cgpt_manager.AddPartition("data stuff", - guid_linux_data, - guid_unused, - 100, - 10)); - CheckPartitionCount(1); - - EXPECT_SUCCESS(cgpt_manager.AddPartition("kernel stuff", - guid_chromeos_kernel, - p2guid, - p2_offset, - p2_size)); - CheckPartitionCount(2); - - EXPECT_SUCCESS(cgpt_manager.AddPartition("rootfs stuff", - guid_chromeos_rootfs, - p3guid, - p3_offset, - p3_size)); - CheckPartitionCount(3); - - uint32_t pmbr_boot_partition_number = 4; - EXPECT_SUCCESS(cgpt_manager.AddPartition("ESP stuff", - guid_efi, - guid_unused, - 400, - 40)); - CheckPartitionCount(4); - - EXPECT_SUCCESS(cgpt_manager.AddPartition("fture stuff", - guid_chromeos_reserved, - guid_unused, - 500, - 50)); - CheckPartitionCount(5); - - Guid guid_random = {{{0x2364a860, 0xbf63, 0x42fb, 0xa8, 0x3d, - {0x9a, 0xd3, 0xe0, 0x57, 0xfc, 0xf5}}}}; - - EXPECT_SUCCESS(cgpt_manager.AddPartition("random stuff", - guid_random, - guid_unused, - 600, - 60)); - - CheckPartitionCount(6); - - string boot_file_name = "/tmp/BootFileForCgptManagerTests.bin"; - LOG(INFO) << "Adding EFI partition to PMBR with bootfile: " - << boot_file_name; - - CreateBootFile(boot_file_name); - EXPECT_SUCCESS(cgpt_manager.SetPmbr(pmbr_boot_partition_number, - boot_file_name, - true)); - - VLOG(1) << "Checking if contents of GPT match values set in AddPartition."; - - uint32_t actual_boot_partition_number; - EXPECT_SUCCESS(cgpt_manager.GetPmbrBootPartitionNumber( - &actual_boot_partition_number)); - EXPECT_EQ(pmbr_boot_partition_number, actual_boot_partition_number); - - // Set the successful attribute for some partition to various Values - // and check if the settings are preserved. - SetAndCheckSuccessfulBit(2, true); - SetAndCheckSuccessfulBit(2, false); - - // Set the number of tries for some partition to various Values - // and check if the settings are preserved. - SetAndCheckNumTriesLeft(2, 6); - SetAndCheckNumTriesLeft(2, 5); - - // Set the priority for some partition to various Values - // and check if the settings are preserved. - SetAndCheckPriority(2, 2); - SetAndCheckPriority(2, 0); - - // Check if the beginning offset for some of the partitions - // are the same as what was set in AddPartition. - CheckBeginningOffset(2, p2_offset); - CheckBeginningOffset(3, p3_offset); - - // Check if the number of sectors for some of the partitions - // are same as what was set in AddPartition. - CheckNumSectors(2, p2_size); - CheckNumSectors(3, p3_size); - - // Check if the partition type IDs for some of the partitions - // are same as what was set in AddPartition. - CheckPartitionTypeId(2, guid_chromeos_kernel); - CheckPartitionTypeId(4, guid_efi); - - // Check if the partition unique IDs for some of the partitions - // same as what was set in AddPartition. - CheckPartitionUniqueId(2, p2guid); - CheckPartitionUniqueId(3, p3guid); - - // Check if the partition numbers for some of the partitions are - // retrievable by their unique IDs set in AddPartition. - CheckPartitionNumberByUniqueId(p2guid, 2); - CheckPartitionNumberByUniqueId(p3guid, 3); -} - -int main(int argc, char **argv) { - google::ParseCommandLineFlags(&argc, &argv, true); - ::testing::InitGoogleTest(&argc, argv); - - // VLOG(2) logs at level -2. So if user gives --v=2, we should - // set MinLogLevel to -2, so VLOG(2) and VLOG(1) will show up. - logging::SetMinLogLevel(-FLAGS_v); - return RUN_ALL_TESTS(); -} diff --git a/utility/mount-encrypted.c b/utility/mount-encrypted.c deleted file mode 100644 index 9dbedc2a..00000000 --- a/utility/mount-encrypted.c +++ /dev/null @@ -1,1349 +0,0 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * This tool will attempt to mount or create the encrypted stateful partition, - * and the various bind mountable subdirectories. - * - */ -#define _GNU_SOURCE -#define _FILE_OFFSET_BITS 64 -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <grp.h> -#include <pwd.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/statvfs.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/mount.h> -#include <linux/fs.h> - -#include <glib.h> - -#include <openssl/rand.h> - -#define CHROMEOS_ENVIRONMENT -#include "tlcl.h" -#include "crossystem.h" - -#include "mount-encrypted.h" -#include "mount-helpers.h" - -#define STATEFUL_MNT "mnt/stateful_partition" -#define ENCRYPTED_MNT STATEFUL_MNT "/encrypted" -#define BUF_SIZE 1024 -#define PROP_SIZE 64 -#define LOCKBOX_SIZE_MAX 0x45 - -static const gchar * const kKernelCmdline = "/proc/cmdline"; -static const gchar * const kKernelCmdlineOption = " encrypted-stateful-key="; -static const gchar * const kEncryptedFSType = "ext4"; -static const gchar * const kCryptDevName = "encstateful"; -static const gchar * const kTpmDev = "/dev/tpm0"; -static const gchar * const kNullDev = "/dev/null"; -static const gchar * const kNvramExport = "/tmp/lockbox.nvram"; -static const float kSizePercent = 0.3; -static const float kMigrationSizeMultiplier = 1.1; -static const uint32_t kLockboxIndex = 0x20000004; -static const uint32_t kLockboxSizeV1 = 0x2c; -static const uint32_t kLockboxSizeV2 = LOCKBOX_SIZE_MAX; -static const uint32_t kLockboxSaltOffset = 0x5; -static const uint64_t kSectorSize = 512; -static const uint64_t kExt4BlockSize = 4096; -static const uint64_t kExt4MinBytes = 16 * 1024 * 1024; -static const char * const kStaticKeyDefault = "default unsafe static key"; -static const char * const kStaticKeyFactory = "factory unsafe static key"; -static const char * const kStaticKeyFinalizationNeeded = "needs finalization"; -static const int kModeProduction = 0; -static const int kModeFactory = 1; -static const int kCryptAllowDiscard = 1; - -enum migration_method { - MIGRATE_TEST_ONLY, - MIGRATE_FOR_REAL, -}; - -enum bind_dir { - BIND_SOURCE, - BIND_DEST, -}; - -static struct bind_mount { - char * src; /* Location of bind source. */ - char * dst; /* Destination of bind. */ - char * previous; /* Migratable prior bind source. */ - char * pending; /* Location for pending deletion. */ - char * owner; - char * group; - mode_t mode; - int submount; /* Submount is bound already. */ -} bind_mounts_default[] = { - { ENCRYPTED_MNT "/var", "var", - STATEFUL_MNT "/var", STATEFUL_MNT "/.var", - "root", "root", - S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, 0 }, - { ENCRYPTED_MNT "/chronos", "home/chronos", - STATEFUL_MNT "/home/chronos", STATEFUL_MNT "/home/.chronos", - "chronos", "chronos", - S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, 1 }, - { }, -}; - -#if DEBUG_ENABLED -struct timeval tick = { }; -struct timeval tick_start = { }; -#endif - -static struct bind_mount *bind_mounts = NULL; -static gchar *rootdir = NULL; -static gchar *stateful_mount = NULL; -static gchar *key_path = NULL; -static gchar *needs_finalization_path = NULL; -static gchar *block_path = NULL; -static gchar *encrypted_mount = NULL; -static gchar *dmcrypt_name = NULL; -static gchar *dmcrypt_dev = NULL; -static int has_tpm = 0; -static int tpm_init_called = 0; -static uint8_t nvram_data[LOCKBOX_SIZE_MAX]; -static uint32_t nvram_size = 0; - -static void tpm_init(void) -{ - uint32_t result; - - if (tpm_init_called) - return; - - DEBUG("Opening TPM"); - - setenv("TPM_NO_EXIT", "1", 1); - result = TlclLibInit(); - - tpm_init_called = 1; - has_tpm = (result == TPM_SUCCESS); - INFO("TPM %s", has_tpm ? "ready" : "not available"); -} - -/* Returns TPM result status code, and on TPM_SUCCESS, stores ownership - * flag to "owned". - */ -static uint32_t tpm_owned(uint8_t *owned) -{ - uint32_t result; - - tpm_init(); - DEBUG("Reading TPM Ownership Flag"); - if (!has_tpm) - result = TPM_E_NO_DEVICE; - else - result = TlclGetOwnership(owned); - DEBUG("TPM Ownership Flag returned: %s", result ? "FAIL" : "ok"); - - return result; -} - -static void tpm_close(void) -{ - if (!has_tpm || !tpm_init_called) - return; - TlclLibClose(); - tpm_init_called = 0; -} - -static void sha256(char *string, uint8_t *digest) -{ - SHA256((unsigned char *)string, strlen(string), digest); -} - -/* Extract the desired system key from the kernel's boot command line. */ -static int get_key_from_cmdline(uint8_t *digest) -{ - int result = 0; - gchar *buffer; - gsize length; - char *cmdline, *option_end; - /* Option name without the leading space. */ - const gchar *option = kKernelCmdlineOption + 1; - - if (!g_file_get_contents(kKernelCmdline, &buffer, &length, NULL)) { - PERROR(kKernelCmdline); - return 0; - } - - /* Find a string match either at start of string or following - * a space. - */ - cmdline = buffer; - if (strncmp(cmdline, option, strlen(option)) == 0 || - (cmdline = strstr(cmdline, kKernelCmdlineOption))) { - /* The "=" exists because it is in kKernelCmdlineOption. */ - cmdline = strstr(cmdline, "="); - /* strchrnul() cannot return NULL. */ - option_end = strchrnul(cmdline, ' '); - *option_end = '\0'; - sha256(cmdline, digest); - debug_dump_hex("system key", digest, DIGEST_LENGTH); - result = 1; - } - - g_free(buffer); - return result; -} - -static int get_system_property(const char *prop, char *buf, size_t length) -{ - const char *rc; - - DEBUG("Fetching System Property '%s'", prop); - rc = VbGetSystemPropertyString(prop, buf, length); - DEBUG("Got System Property 'mainfw_type': %s", rc ? buf : "FAIL"); - - return rc != NULL; -} - -static int has_chromefw(void) -{ - static int state = -1; - char fw[PROP_SIZE]; - - /* Cache the state so we don't have to perform the query again. */ - if (state != -1) - return state; - - if (!get_system_property("mainfw_type", fw, sizeof(fw))) - state = 0; - else - state = strcmp(fw, "nonchrome") != 0; - return state; -} - -static int is_cr48(void) -{ - static int state = -1; - char hwid[PROP_SIZE]; - - /* Cache the state so we don't have to perform the query again. */ - if (state != -1) - return state; - - if (!get_system_property("hwid", hwid, sizeof(hwid))) - state = 0; - else - state = strstr(hwid, "MARIO") != NULL; - return state; -} - -static uint32_t -_read_nvram(uint8_t *buffer, size_t len, uint32_t index, uint32_t size) -{ - uint32_t result; - - if (size > len) { - ERROR("NVRAM size (0x%x > 0x%zx) is too big", size, len); - return 0; - } - - tpm_init(); - DEBUG("Reading NVRAM area 0x%x (size %u)", index, size); - if (!has_tpm) - result = TPM_E_NO_DEVICE; - else - result = TlclRead(index, buffer, size); - DEBUG("NVRAM read returned: %s", result == TPM_SUCCESS ? "ok" - : "FAIL"); - - return result; -} - -/* - * TPM cases: - * - does not exist at all (disabled in test firmware or non-chrome device). - * - exists (below). - * - * TPM ownership cases: - * - unowned (OOBE): - * - expect modern lockbox (no migration allowed). - * - owned: depends on NVRAM area (below). - * - * NVRAM area cases: - * - no NVRAM area at all: - * - interrupted install (cryptohome has the TPM password) - * - ancient device (cr48, cryptohome has thrown away TPM password) - * - broken device (cryptohome has thrown away/never had TPM password) - * - must expect worst-case: no lockbox ever, and migration allowed. - * - defined NVRAM area, but not written to ("Finalized"); interrupted OOBE: - * - if legacy size, allow migration. - * - if not, disallow migration. - * - written ("Finalized") NVRAM area: - * - if legacy size, allow migration. - * - if not, disallow migration. - * - * When returning 1: (NVRAM area found and used) - * - *digest populated with NVRAM area entropy. - * - *migrate is 1 for NVRAM v1, 0 for NVRAM v2. - * When returning 0: (NVRAM missing or error) - * - *digest untouched. - * - *migrate always 1 - */ -static int get_nvram_key(uint8_t *digest, int *migrate) -{ - uint8_t owned = 0; - uint8_t value[kLockboxSizeV2], bytes_anded, bytes_ored; - uint32_t size, result, i; - uint8_t *rand_bytes; - uint32_t rand_size; - - /* Default to allowing migration (disallow when owned with NVRAMv2). */ - *migrate = 1; - - /* Ignore unowned TPM's NVRAM area. */ - result = tpm_owned(&owned); - if (result != TPM_SUCCESS) { - INFO("Could not read TPM Permanent Flags: error 0x%02x.", - result); - return 0; - } - if (!owned) { - INFO("TPM not Owned, ignoring NVRAM area."); - return 0; - } - - /* Reading the NVRAM takes 40ms. Instead of querying the NVRAM area - * for its size (which takes time), just read the expected size. If - * it fails, then fall back to the older size. This means cleared - * devices take 80ms (2 failed reads), legacy devices take 80ms - * (1 failed read, 1 good read), and populated devices take 40ms, - * which is the minimum possible time (instead of 40ms + time to - * query NVRAM size). - */ - size = kLockboxSizeV2; - result = _read_nvram(value, sizeof(value), kLockboxIndex, size); - if (result != TPM_SUCCESS) { - size = kLockboxSizeV1; - result = _read_nvram(value, sizeof(value), kLockboxIndex, size); - if (result != TPM_SUCCESS) { - /* No NVRAM area at all. */ - INFO("No NVRAM area defined: error 0x%02x", result); - return 0; - } - /* Legacy NVRAM area. */ - INFO("Version 1 NVRAM area found."); - } else { - *migrate = 0; - INFO("Version 2 NVRAM area found."); - } - - debug_dump_hex("nvram", value, size); - - /* Ignore defined but unwritten NVRAM area. */ - bytes_ored = 0x0; - bytes_anded = 0xff; - for (i = 0; i < size; ++i) { - bytes_ored |= value[i]; - bytes_anded &= value[i]; - } - if (bytes_ored == 0x0 || bytes_anded == 0xff) { - INFO("NVRAM area has been defined but not written."); - return 0; - } - - /* "Export" nvram data for use after the helper. */ - if (size <= sizeof(nvram_data)) { - nvram_size = size; - memcpy(nvram_data, value, size); - } - - /* Choose random bytes to use based on NVRAM version. */ - if (*migrate) { - rand_bytes = value; - rand_size = size; - } else { - rand_bytes = value + kLockboxSaltOffset; - if (kLockboxSaltOffset + DIGEST_LENGTH > size) { - INFO("Impossibly small NVRAM area size (%d).", size); - return 0; - } - rand_size = DIGEST_LENGTH; - } - if (rand_size < DIGEST_LENGTH) { - INFO("Impossibly small rand_size (%d).", rand_size); - return 0; - } - debug_dump_hex("rand_bytes", rand_bytes, rand_size); - - SHA256(rand_bytes, rand_size, digest); - debug_dump_hex("system key", digest, DIGEST_LENGTH); - - return 1; -} - -/* Find the system key used for decrypting the stored encryption key. - * ChromeOS devices are required to use the NVRAM area, all the rest will - * fallback through various places (kernel command line, BIOS UUID, and - * finally a static value) for a system key. - */ -static int find_system_key(int mode, uint8_t *digest, int *migration_allowed) -{ - gchar *key; - gsize length; - - /* By default, do not allow migration. */ - *migration_allowed = 0; - - /* Factory mode uses a static system key. */ - if (mode == kModeFactory) { - INFO("Using factory insecure system key."); - sha256((char *)kStaticKeyFactory, digest); - debug_dump_hex("system key", digest, DIGEST_LENGTH); - return 1; - } - - /* Force ChromeOS devices into requiring the system key come from - * NVRAM. - */ - if (has_chromefw()) { - int rc; - rc = get_nvram_key(digest, migration_allowed); - - if (rc) { - INFO("Using NVRAM as system key; already populated%s.", - *migration_allowed ? " (legacy)" : ""); - } else { - INFO("Using NVRAM as system key; finalization needed."); - } - return rc; - } - - if (get_key_from_cmdline(digest)) { - INFO("Using kernel command line argument as system key."); - return 1; - } - if (g_file_get_contents("/sys/class/dmi/id/product_uuid", - &key, &length, NULL)) { - sha256(key, digest); - debug_dump_hex("system key", digest, DIGEST_LENGTH); - g_free(key); - INFO("Using UUID as system key."); - return 1; - } - - INFO("Using default insecure system key."); - sha256((char *)kStaticKeyDefault, digest); - debug_dump_hex("system key", digest, DIGEST_LENGTH); - return 1; -} - -/* Returns 1 on success, 0 on failure. */ -static int get_random_bytes_tpm(unsigned char *buffer, int wanted) -{ - uint32_t remaining = wanted; - - tpm_init(); - /* Read random bytes from TPM, which can return short reads. */ - while (remaining) { - uint32_t result, size; - - result = TlclGetRandom(buffer + (wanted - remaining), - remaining, &size); - if (result != TPM_SUCCESS || size > remaining) { - ERROR("TPM GetRandom failed: error 0x%02x.", result); - return 0; - } - remaining -= size; - } - - return 1; -} - -/* Returns 1 on success, 0 on failure. */ -static int get_random_bytes(unsigned char *buffer, int wanted) -{ - if (has_tpm && get_random_bytes_tpm(buffer, wanted)) - return 1; - - if (RAND_bytes(buffer, wanted)) - return 1; - SSL_ERROR("RAND_bytes"); - - return 0; -} - -static char *choose_encryption_key(void) -{ - unsigned char rand_bytes[DIGEST_LENGTH]; - unsigned char digest[DIGEST_LENGTH]; - - if (!get_random_bytes(rand_bytes, sizeof(rand_bytes))) - ERROR("No entropy source found -- using uninitialized stack"); - - SHA256(rand_bytes, DIGEST_LENGTH, digest); - debug_dump_hex("encryption key", digest, DIGEST_LENGTH); - - return stringify_hex(digest, DIGEST_LENGTH); -} - -static int check_bind(struct bind_mount *bind, enum bind_dir dir) -{ - struct passwd *user; - struct group *group; - const gchar *target; - - if (dir == BIND_SOURCE) - target = bind->src; - else - target = bind->dst; - - if (access(target, R_OK) && mkdir(target, bind->mode)) { - PERROR("mkdir(%s)", target); - return -1; - } - - /* Destination may be on read-only filesystem, so skip tweaks. */ - if (dir == BIND_DEST) - return 0; - - if (!(user = getpwnam(bind->owner))) { - PERROR("getpwnam(%s)", bind->owner); - return -1; - } - if (!(group = getgrnam(bind->group))) { - PERROR("getgrnam(%s)", bind->group); - return -1; - } - - /* Must do explicit chmod since mkdir()'s mode respects umask. */ - if (chmod(target, bind->mode)) { - PERROR("chmod(%s)", target); - return -1; - } - if (chown(target, user->pw_uid, group->gr_gid)) { - PERROR("chown(%s)", target); - return -1; - } - - return 0; -} - -static int migrate_contents(struct bind_mount *bind, - enum migration_method method) -{ - const gchar *previous = NULL; - const gchar *pending = NULL; - gchar *dotdir; - - /* Skip migration if the previous bind sources are missing. */ - if (bind->pending && access(bind->pending, R_OK) == 0) - pending = bind->pending; - if (bind->previous && access(bind->previous, R_OK) == 0) - previous = bind->previous; - if (!pending && !previous) - return 0; - - /* Pretend migration happened. */ - if (method == MIGRATE_TEST_ONLY) - return 1; - - check_bind(bind, BIND_SOURCE); - - /* Prefer the pending-delete location when doing migration. */ - if (!(dotdir = g_strdup_printf("%s/.", pending ? pending : previous))) { - PERROR("g_strdup_printf"); - goto mark_for_removal; - } - - INFO("Migrating bind mount contents %s to %s.", dotdir, bind->src); - const gchar *cp[] = { - "/bin/cp", "-a", - dotdir, - bind->src, - NULL - }; - - if (runcmd(cp, NULL) != 0) { - /* If the copy failed, it may have partially populated the - * new source, so we need to remove the new source and - * rebuild it. Regardless, the previous source must be removed - * as well. - */ - INFO("Failed to migrate %s to %s!", dotdir, bind->src); - remove_tree(bind->src); - check_bind(bind, BIND_SOURCE); - } - -mark_for_removal: - g_free(dotdir); - - /* The removal of the previous directory needs to happen at finalize - * time, otherwise /var state gets lost on a migration if the - * system is powered off before the encryption key is saved. Instead, - * relocate the directory so it can be removed (or re-migrated). - */ - - if (previous) { - /* If both pending and previous directory exists, we must - * remove previous entirely now so it stops taking up disk - * space. The pending area will stay pending to be deleted - * later. - */ - if (pending) - remove_tree(pending); - if (rename(previous, bind->pending)) { - PERROR("rename(%s,%s)", previous, bind->pending); - } - } - - /* As noted above, failures are unrecoverable, so getting here means - * "we're done" more than "it worked". - */ - return 1; -} - -static void finalized(void) -{ - /* TODO(keescook): once ext4 supports secure delete, just unlink. */ - if (access(needs_finalization_path, R_OK) == 0) { - /* This is nearly useless on SSDs. */ - shred(needs_finalization_path); - unlink(needs_finalization_path); - } -} - -static void finalize(uint8_t *system_key, char *encryption_key) -{ - struct bind_mount *bind; - - INFO("Writing keyfile %s.", key_path); - if (!keyfile_write(key_path, system_key, encryption_key)) { - ERROR("Failed to write %s -- aborting.", key_path); - return; - } - - finalized(); - - for (bind = bind_mounts; bind->src; ++ bind) { - if (!bind->pending || access(bind->pending, R_OK)) - continue; - INFO("Removing %s.", bind->pending); -#if DEBUG_ENABLED - continue; -#endif - remove_tree(bind->pending); - } -} - -static void needs_finalization(char *encryption_key) -{ - uint8_t useless_key[DIGEST_LENGTH]; - sha256((char *)kStaticKeyFinalizationNeeded, useless_key); - - INFO("Writing finalization intent %s.", needs_finalization_path); - if (!keyfile_write(needs_finalization_path, useless_key, - encryption_key)) { - ERROR("Failed to write %s -- aborting.", - needs_finalization_path); - return; - } -} - -/* This triggers the live encryption key to be written to disk, encrypted - * by the system key. It is intended to be called by Cryptohome once the - * TPM is done being set up. If the system key is passed as an argument, - * use it, otherwise attempt to query the TPM again. - */ -static int finalize_from_cmdline(char *key) -{ - uint8_t system_key[DIGEST_LENGTH]; - char *encryption_key; - int migrate; - - /* Early sanity-check to see if the encrypted device exists, - * instead of failing at the end of this function. - */ - if (access(dmcrypt_dev, R_OK)) { - ERROR("'%s' does not exist, giving up.", dmcrypt_dev); - return EXIT_FAILURE; - } - - if (key) { - if (strlen(key) != 2 * DIGEST_LENGTH) { - ERROR("Invalid key length."); - return EXIT_FAILURE; - } - - if (!hexify_string(key, system_key, DIGEST_LENGTH)) { - ERROR("Failed to convert hex string to byte array"); - return EXIT_FAILURE; - } - } else { - /* Factory mode will never call finalize from the command - * line, so force Production mode here. - */ - if (!find_system_key(kModeProduction, system_key, &migrate)) { - ERROR("Could not locate system key."); - return EXIT_FAILURE; - } - } - - encryption_key = dm_get_key(dmcrypt_dev); - if (!encryption_key) { - ERROR("Could not locate encryption key for %s.", dmcrypt_dev); - return EXIT_FAILURE; - } - - finalize(system_key, encryption_key); - - return EXIT_SUCCESS; -} - -static void spawn_resizer(const char *device, uint64_t blocks, - uint64_t blocks_max) -{ - pid_t pid; - - /* Skip resize before forking, if it's not going to happen. */ - if (blocks >= blocks_max) { - INFO("Resizing skipped. blocks:%" PRIu64 " >= blocks_max:%" PRIu64, - blocks, blocks_max); - return; - } - - fflush(NULL); - pid = fork(); - if (pid < 0) { - PERROR("fork"); - return; - } - if (pid != 0) { - INFO("Started filesystem resizing process %d.", pid); - return; - } - - /* Child */ - tpm_close(); - INFO_INIT("Resizer spawned."); - - if (daemon(0, 1)) { - PERROR("daemon"); - goto out; - } - - filesystem_resize(device, blocks, blocks_max); - -out: - INFO_DONE("Done."); - exit(0); -} - -/* Do all the work needed to actually set up the encrypted partition. - * Takes "mode" argument to help determine where the system key should - * come from. - */ -static int setup_encrypted(int mode) -{ - int has_system_key; - uint8_t system_key[DIGEST_LENGTH]; - char *encryption_key = NULL; - int migrate_allowed = 0, migrate_needed = 0, rebuild = 0; - gchar *lodev = NULL; - uint64_t sectors; - struct bind_mount *bind; - int sparsefd; - struct statvfs stateful_statbuf; - uint64_t blocks_min, blocks_max; - int valid_keyfile = 0; - - /* Use the "system key" to decrypt the "encryption key" stored in - * the stateful partition. - */ - has_system_key = find_system_key(mode, system_key, &migrate_allowed); - if (has_system_key) { - encryption_key = keyfile_read(key_path, system_key); - } else { - INFO("No usable system key found."); - } - - if (encryption_key) { - /* If we found a stored encryption key, we've already - * finished a complete login and Cryptohome Finalize - * so migration is finished. - */ - migrate_allowed = 0; - valid_keyfile = 1; - } else { - uint8_t useless_key[DIGEST_LENGTH]; - sha256((char *)kStaticKeyFinalizationNeeded, useless_key); - encryption_key = keyfile_read(needs_finalization_path, - useless_key); - if (!encryption_key) { - /* This is a brand new system with no keys. */ - INFO("Generating new encryption key."); - encryption_key = choose_encryption_key(); - if (!encryption_key) - return 0; - rebuild = 1; - } else { - ERROR("Finalization unfinished! " \ - "Encryption key still on disk!"); - } - } - - if (rebuild) { - uint64_t fs_bytes_max; - - /* Wipe out the old files, and ignore errors. */ - unlink(key_path); - unlink(block_path); - - /* Calculate the desired size of the new partition. */ - if (statvfs(stateful_mount, &stateful_statbuf)) { - PERROR(stateful_mount); - return 0; - } - fs_bytes_max = stateful_statbuf.f_blocks; - fs_bytes_max *= kSizePercent; - fs_bytes_max *= stateful_statbuf.f_frsize; - - INFO("Creating sparse backing file with size %" PRIu64 ".", - fs_bytes_max); - - /* Create the sparse file. */ - sparsefd = sparse_create(block_path, fs_bytes_max); - if (sparsefd < 0) { - PERROR(block_path); - return 0; - } - } else { - sparsefd = open(block_path, O_RDWR | O_NOFOLLOW); - if (sparsefd < 0) { - PERROR(block_path); - return 0; - } - } - - /* Set up loopback device. */ - INFO("Loopback attaching %s (named %s).", block_path, dmcrypt_name); - lodev = loop_attach(sparsefd, dmcrypt_name); - if (!lodev || strlen(lodev) == 0) { - ERROR("loop_attach failed"); - goto failed; - } - - /* Get size as seen by block device. */ - sectors = blk_size(lodev) / kSectorSize; - if (!sectors) { - ERROR("Failed to read device size"); - goto lo_cleanup; - } - - /* Mount loopback device with dm-crypt using the encryption key. */ - INFO("Setting up dm-crypt %s as %s.", lodev, dmcrypt_dev); - if (!dm_setup(sectors, encryption_key, dmcrypt_name, lodev, - dmcrypt_dev, kCryptAllowDiscard)) { - /* If dm_setup() fails, it could be due to lacking - * "allow_discard" support, so try again with discard - * disabled. There doesn't seem to be a way to query - * the kernel for this feature short of a fallible - * version test or just trying to set up the dm table - * again, so do the latter. - */ - if (!dm_setup(sectors, encryption_key, dmcrypt_name, lodev, - dmcrypt_dev, !kCryptAllowDiscard)) { - ERROR("dm_setup failed"); - goto lo_cleanup; - } - INFO("%s: dm-crypt does not support discard; disabling.", - dmcrypt_dev); - } - - /* Decide now if any migration will happen. If so, we will not - * grow the new filesystem in the background, since we need to - * copy the contents over before /var is valid again. - */ - if (!rebuild) - migrate_allowed = 0; - if (migrate_allowed) { - for (bind = bind_mounts; bind->src; ++ bind) { - if (migrate_contents(bind, MIGRATE_TEST_ONLY)) - migrate_needed = 1; - } - } - - /* Calculate filesystem min/max size. */ - blocks_max = sectors / (kExt4BlockSize / kSectorSize); - blocks_min = kExt4MinBytes / kExt4BlockSize; - if (migrate_needed && migrate_allowed) { - uint64_t fs_bytes_min; - uint64_t calc_blocks_min; - /* When doing a migration, the new filesystem must be - * large enough to hold what we're going to migrate. - * Instead of walking the bind mount sources, which would - * be IO and time expensive, just read the bytes-used - * value from statvfs (plus 10% for overhead). It will - * be too large, since it includes the eCryptFS data, so - * we must cap at the max filesystem size just in case. - */ - - /* Bytes used in stateful partition plus 10%. */ - fs_bytes_min = stateful_statbuf.f_blocks - - stateful_statbuf.f_bfree; - fs_bytes_min *= stateful_statbuf.f_frsize; - DEBUG("Stateful bytes used: %" PRIu64 "", fs_bytes_min); - fs_bytes_min *= kMigrationSizeMultiplier; - - /* Minimum blocks needed for that many bytes. */ - calc_blocks_min = fs_bytes_min / kExt4BlockSize; - /* Do not use more than blocks_max. */ - if (calc_blocks_min > blocks_max) - calc_blocks_min = blocks_max; - /* Do not use less than blocks_min. */ - else if (calc_blocks_min < blocks_min) - calc_blocks_min = blocks_min; - - DEBUG("Maximum fs blocks: %" PRIu64 "", blocks_max); - DEBUG("Minimum fs blocks: %" PRIu64 "", blocks_min); - DEBUG("Migration blocks chosen: %" PRIu64 "", calc_blocks_min); - blocks_min = calc_blocks_min; - } - - if (rebuild) { - INFO("Building filesystem on %s " - "(blocksize:%" PRIu64 ", min:%" PRIu64 ", max:%" PRIu64 ").", - dmcrypt_dev, kExt4BlockSize, blocks_min, blocks_max); - if (!filesystem_build(dmcrypt_dev, kExt4BlockSize, - blocks_min, blocks_max)) - goto dm_cleanup; - } - - /* Mount the dm-crypt partition finally. */ - INFO("Mounting %s onto %s.", dmcrypt_dev, encrypted_mount); - if (access(encrypted_mount, R_OK) && - mkdir(encrypted_mount, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) { - PERROR(dmcrypt_dev); - goto dm_cleanup; - } - if (mount(dmcrypt_dev, encrypted_mount, kEncryptedFSType, - MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, - "discard,commit=600")) { - PERROR("mount(%s,%s)", dmcrypt_dev, encrypted_mount); - goto dm_cleanup; - } - - /* Always spawn filesystem resizer, in case growth was interrupted. */ - /* TODO(keescook): if already full size, don't resize. */ - spawn_resizer(dmcrypt_dev, blocks_min, blocks_max); - - /* If the legacy lockbox NVRAM area exists, we've rebuilt the - * filesystem, and there are old bind sources on disk, attempt - * migration. - */ - if (migrate_needed && migrate_allowed) { - /* Migration needs to happen before bind mounting because - * some partitions were not already on the stateful partition, - * and would be over-mounted by the new bind mount. - */ - for (bind = bind_mounts; bind->src; ++ bind) - migrate_contents(bind, MIGRATE_FOR_REAL); - } - - /* Perform bind mounts. */ - for (bind = bind_mounts; bind->src; ++ bind) { - INFO("Bind mounting %s onto %s.", bind->src, bind->dst); - if (check_bind(bind, BIND_SOURCE) || - check_bind(bind, BIND_DEST)) - goto unbind; - if (mount(bind->src, bind->dst, "none", MS_BIND, NULL)) { - PERROR("mount(%s,%s)", bind->src, bind->dst); - goto unbind; - } - } - - /* When we are creating the encrypted mount for the first time, - * either finalize immediately, or write the encryption key to - * disk (*sigh*) to handle the seemingly endless broken or - * wedged TPM states. - */ - if (rebuild) { - /* Devices that already have the NVRAM area populated and - * are being rebuilt don't need to wait for Cryptohome - * because the NVRAM area isn't going to change. - * - * Devices that do not have the NVRAM area populated - * may potentially never have the NVRAM area populated, - * which means we have to write the encryption key to - * disk until we finalize. Once secure deletion is - * supported on ext4, this won't be as horrible. - */ - if (has_system_key) - finalize(system_key, encryption_key); - else - needs_finalization(encryption_key); - } else { - /* If we're not rebuilding and we have a sane system - * key, then we must either need finalization (if we - * failed to finalize in Cryptohome), or we have already - * finalized, but maybe failed to clean up. - */ - if (has_system_key) { - if (!valid_keyfile) - finalize(system_key, encryption_key); - else - finalized(); - } - } - - free(lodev); - return 1; - -unbind: - for (bind = bind_mounts; bind->src; ++ bind) { - INFO("Unmounting %s.", bind->dst); - umount(bind->dst); - } - - INFO("Unmounting %s.", encrypted_mount); - umount(encrypted_mount); - -dm_cleanup: - INFO("Removing %s.", dmcrypt_dev); - /* TODO(keescook): something holds this open briefly on mkfs failure - * and I haven't been able to catch it yet. Adding an "fuser" call - * here is sufficient to lose the race. Instead, just sleep during - * the error path. - */ - sleep(1); - dm_teardown(dmcrypt_dev); - -lo_cleanup: - INFO("Unlooping %s.", lodev); - loop_detach(lodev); - -failed: - free(lodev); - - return 0; -} - -/* Clean up all bind mounts, mounts, attaches, etc. Only the final - * action informs the return value. This makes it so that failures - * can be cleaned up from, and continue the shutdown process on a - * second call. If the loopback cannot be found, claim success. - */ -static int shutdown(void) -{ - struct bind_mount *bind; - - for (bind = bind_mounts; bind->src; ++ bind) { - INFO("Unmounting %s.", bind->dst); - errno = 0; - /* Allow either success or a "not mounted" failure. */ - if (umount(bind->dst)) { - if (errno != EINVAL) { - PERROR("umount(%s)", bind->dst); - return EXIT_FAILURE; - } - } - } - - INFO("Unmounting %s.", encrypted_mount); - errno = 0; - /* Allow either success or a "not mounted" failure. */ - if (umount(encrypted_mount)) { - if (errno != EINVAL) { - PERROR("umount(%s)", encrypted_mount); - return EXIT_FAILURE; - } - } - - /* - * Force syncs to make sure we don't tickle racey/buggy kernel - * routines that might be causing crosbug.com/p/17610. - */ - sync(); - - /* Optionally run fsck on the device after umount. */ - if (getenv("MOUNT_ENCRYPTED_FSCK")) { - char *cmd; - - if (asprintf(&cmd, "fsck -a %s", dmcrypt_dev) == -1) - PERROR("asprintf"); - else { - int rc; - - rc = system(cmd); - if (rc != 0) - ERROR("'%s' failed: %d", cmd, rc); - } - } - - INFO("Removing %s.", dmcrypt_dev); - if (!dm_teardown(dmcrypt_dev)) - ERROR("dm_teardown(%s)", dmcrypt_dev); - sync(); - - INFO("Unlooping %s (named %s).", block_path, dmcrypt_name); - if (!loop_detach_name(dmcrypt_name)) { - ERROR("loop_detach_name(%s)", dmcrypt_name); - return EXIT_FAILURE; - } - sync(); - - return EXIT_SUCCESS; -} - -static void check_mount_states(void) -{ - struct bind_mount *bind; - - /* Verify stateful partition exists. */ - if (access(stateful_mount, R_OK)) { - INFO("%s does not exist.", stateful_mount); - exit(1); - } - /* Verify stateful is either a separate mount, or that the - * root directory is writable (i.e. a factory install, dev mode - * where root remounted rw, etc). - */ - if (same_vfs(stateful_mount, rootdir) && access(rootdir, W_OK)) { - INFO("%s is not mounted.", stateful_mount); - exit(1); - } - - /* Verify encrypted partition is missing or not already mounted. */ - if (access(encrypted_mount, R_OK) == 0 && - !same_vfs(encrypted_mount, stateful_mount)) { - INFO("%s already appears to be mounted.", encrypted_mount); - exit(0); - } - - /* Verify that bind mount targets exist. */ - for (bind = bind_mounts; bind->src; ++ bind) { - if (access(bind->dst, R_OK)) { - PERROR("%s mount point is missing.", bind->dst); - exit(1); - } - } - - /* Verify that old bind mounts on stateful haven't happened yet. */ - for (bind = bind_mounts; bind->src; ++ bind) { - if (bind->submount) - continue; - - if (same_vfs(bind->dst, stateful_mount)) { - INFO("%s already bind mounted.", bind->dst); - exit(1); - } - } - - INFO("VFS mount state sanity check ok."); -} - -static int report_info(void) -{ - uint8_t system_key[DIGEST_LENGTH]; - uint8_t owned = 0; - struct bind_mount *mnt; - int migrate = -1; - - printf("TPM: %s\n", has_tpm ? "yes" : "no"); - if (has_tpm) { - printf("TPM Owned: %s\n", tpm_owned(&owned) != TPM_SUCCESS ? - "fail" : (owned ? "yes" : "no")); - } - printf("ChromeOS: %s\n", has_chromefw() ? "yes" : "no"); - printf("CR48: %s\n", is_cr48() ? "yes" : "no"); - if (has_chromefw()) { - int rc; - rc = get_nvram_key(system_key, &migrate); - if (!rc) - printf("NVRAM: missing.\n"); - else { - printf("NVRAM: %s, %s.\n", - migrate ? "legacy" : "modern", - rc ? "available" : "ignored"); - } - } - else { - printf("NVRAM: not present\n"); - } - - printf("rootdir: %s\n", rootdir); - printf("stateful_mount: %s\n", stateful_mount); - printf("key_path: %s\n", key_path); - printf("block_path: %s\n", block_path); - printf("encrypted_mount: %s\n", encrypted_mount); - printf("dmcrypt_name: %s\n", dmcrypt_name); - printf("dmcrypt_dev: %s\n", dmcrypt_dev); - printf("bind mounts:\n"); - for (mnt = bind_mounts; mnt->src; ++mnt) { - printf("\tsrc:%s\n", mnt->src); - printf("\tdst:%s\n", mnt->dst); - printf("\tprevious:%s\n", mnt->previous); - printf("\tpending:%s\n", mnt->pending); - printf("\towner:%s\n", mnt->owner); - printf("\tmode:%o\n", mnt->mode); - printf("\tsubmount:%d\n", mnt->submount); - printf("\n"); - } - - return EXIT_SUCCESS; -} - -/* This expects "mnt" to be allocated and initialized to NULL bytes. */ -static int dup_bind_mount(struct bind_mount *mnt, struct bind_mount *old, - char *dir) -{ - if (old->src && asprintf(&mnt->src, "%s%s", dir, old->src) == -1) - goto fail; - if (old->dst && asprintf(&mnt->dst, "%s%s", dir, old->dst) == -1) - goto fail; - if (old->previous && asprintf(&mnt->previous, "%s%s", dir, - old->previous) == -1) - goto fail; - if (old->pending && asprintf(&mnt->pending, "%s%s", dir, - old->pending) == -1) - goto fail; - if (!(mnt->owner = strdup(old->owner))) - goto fail; - if (!(mnt->group = strdup(old->group))) - goto fail; - mnt->mode = old->mode; - mnt->submount = old->submount; - - return 0; - -fail: - perror(__FUNCTION__); - return 1; -} - -static void prepare_paths(void) -{ - char *dir = NULL; - struct bind_mount *old; - struct bind_mount *mnt; - - mnt = bind_mounts = calloc(sizeof(bind_mounts_default) / - sizeof(*bind_mounts_default), - sizeof(*bind_mounts_default)); - if (!mnt) { - perror("calloc"); - exit(1); - } - - if ((dir = getenv("MOUNT_ENCRYPTED_ROOT")) != NULL) { - unsigned char digest[DIGEST_LENGTH]; - gchar *hex; - - if (asprintf(&rootdir, "%s/", dir) == -1) - goto fail; - - /* Generate a shortened hash for non-default cryptnames, - * which will get re-used in the loopback name, which - * must be less than 64 (LO_NAME_SIZE) bytes. */ - sha256(dir, digest); - hex = stringify_hex(digest, sizeof(digest)); - hex[17] = '\0'; - if (asprintf(&dmcrypt_name, "%s_%s", kCryptDevName, - hex) == -1) - goto fail; - g_free(hex); - } else { - rootdir = "/"; - if (!(dmcrypt_name = strdup(kCryptDevName))) - goto fail; - } - - if (asprintf(&stateful_mount, "%s%s", rootdir, STATEFUL_MNT) == -1) - goto fail; - if (asprintf(&key_path, "%s%s", rootdir, - STATEFUL_MNT "/encrypted.key") == -1) - goto fail; - if (asprintf(&needs_finalization_path, "%s%s", rootdir, - STATEFUL_MNT "/encrypted.needs-finalization") == -1) - goto fail; - if (asprintf(&block_path, "%s%s", rootdir, - STATEFUL_MNT "/encrypted.block") == -1) - goto fail; - if (asprintf(&encrypted_mount, "%s%s", rootdir, ENCRYPTED_MNT) == -1) - goto fail; - if (asprintf(&dmcrypt_dev, "/dev/mapper/%s", dmcrypt_name) == -1) - goto fail; - - for (old = bind_mounts_default; old->src; ++old) { - if (dup_bind_mount(mnt++, old, rootdir)) - exit(1); - } - - return; - -fail: - perror("asprintf"); - exit(1); -} - -/* Exports NVRAM contents to tmpfs for use by install attributes */ -void nvram_export(uint8_t *data, uint32_t size) -{ - int fd; - DEBUG("Export NVRAM contents"); - if (!size || !data) - return; - fd = open(kNvramExport, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR); - if (fd < 0) { - perror("open(nvram_export)"); - return; - } - if (write(fd, data, size) != size) { - /* Don't leave broken files around */ - unlink(kNvramExport); - } - close(fd); -} - -int main(int argc, char *argv[]) -{ - int okay; - int mode = kModeProduction; - - INFO_INIT("Starting."); - prepare_paths(); - - if (argc > 1) { - if (!strcmp(argv[1], "umount")) - return shutdown(); - else if (!strcmp(argv[1], "info")) - return report_info(); - else if (!strcmp(argv[1], "finalize")) - return finalize_from_cmdline(argc > 2 ? argv[2] : NULL); - else if (!strcmp(argv[1], "factory")) - mode = kModeFactory; - else { - fprintf(stderr, - "Usage: %s [info|finalize|umount|factory]\n", - argv[0]); - return 1; - } - } - - check_mount_states(); - - okay = setup_encrypted(mode); - /* If we fail, let chromeos_startup handle the stateful wipe. */ - - if (okay) - nvram_export(nvram_data, nvram_size); - - INFO_DONE("Done."); - - /* Continue boot. */ - return okay ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/utility/mount-encrypted.h b/utility/mount-encrypted.h deleted file mode 100644 index e48617d9..00000000 --- a/utility/mount-encrypted.h +++ /dev/null @@ -1,144 +0,0 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * Private header file for mount-encrypted helper tool. - */ -#ifndef _MOUNT_ENCRYPTED_H_ -#define _MOUNT_ENCRYPTED_H_ - -/* #define DEBUG_ENABLED 1 */ -#define DEBUG_TIME_DELTA 1 - -#include <openssl/err.h> -#include <openssl/sha.h> - -#define DIGEST_LENGTH SHA256_DIGEST_LENGTH - -#define _ERROR(f, a...) do { \ - fprintf(stderr, "ERROR[pid:%d] %s (%s, %d): ", \ - getpid(), __func__, __FILE__, __LINE__); \ - fprintf(stderr, f, ## a); \ -} while (0) -#define ERROR(f, a...) do { \ - _ERROR(f, ## a); \ - fprintf(stderr, "\n"); \ - fflush(stderr); \ -} while (0) -#define PERROR(f, a...) do { \ - _ERROR(f, ## a); \ - fprintf(stderr, ": %s\n", strerror(errno)); \ - fflush(stderr); \ -} while (0) - -#define SSL_ERROR(f, a...) do { \ - ERR_load_crypto_strings(); \ - _ERROR(f, ## a); \ - fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL)); \ - fflush(stderr); \ -} while (0) - -#if DEBUG_ENABLED -extern struct timeval tick; -extern struct timeval tick_start; -# define TICK_INIT() do { \ - gettimeofday(&tick, NULL); \ - tick_start = tick; \ -} while (0) -# ifdef DEBUG_TIME_DELTA -/* This timeval helper copied from glibc manual. */ -static inline int timeval_subtract(struct timeval *result, - struct timeval *x, - struct timeval *y) -{ - /* Perform the carry for the later subtraction by updating y. */ - if (x->tv_usec < y->tv_usec) { - int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; - y->tv_usec -= 1000000 * nsec; - y->tv_sec += nsec; - } - if (x->tv_usec - y->tv_usec > 1000000) { - int nsec = (x->tv_usec - y->tv_usec) / 1000000; - y->tv_usec += 1000000 * nsec; - y->tv_sec -= nsec; - } - - /* Compute the time remaining to wait. - * tv_usec is certainly positive. - */ - result->tv_sec = x->tv_sec - y->tv_sec; - result->tv_usec = x->tv_usec - y->tv_usec; - - /* Return 1 if result is negative. */ - return x->tv_sec < y->tv_sec; -} -# define TICK_REPORT() do { \ - struct timeval now, diff; \ - gettimeofday(&now, NULL); \ - timeval_subtract(&diff, &now, &tick); \ - printf("\tTook: [pid:%d, %2lu.%06lus]\n", getpid(), \ - (unsigned long)diff.tv_sec, (unsigned long)diff.tv_usec); \ - tick = now; \ -} while (0) -# else -# define TICK_REPORT() do { \ - gettimeofday(&tick, NULL); \ - printf("[%2d.%06d] ", (int)tick.tv_sec, (int)tick.tv_usec); \ -} while (0) -# endif -# define TICK_DONE() do { \ - struct timeval tick_done; \ - TICK_REPORT(); \ - timeval_subtract(&tick_done, &tick, &tick_start); \ - printf("Process Lifetime: [pid:%d, %2d.%06ds]\n", getpid(), \ - (int)tick_done.tv_sec, (int)tick_done.tv_usec); \ -} while (0) -#else -# define TICK_INIT() do { } while (0) -# define TICK_REPORT() do { } while (0) -# define TICK_DONE() do { } while (0) -#endif - -#define _INFO(f, a...) do { \ - printf("[pid:%d] ", getpid()); \ - printf(f, ## a); \ - printf("\n"); \ - fflush(stdout); \ -} while (0) -#define INFO(f, a...) do { \ - TICK_REPORT(); \ - _INFO(f, ## a); \ -} while (0) -#define INFO_INIT(f, a...) do { \ - TICK_INIT(); \ - INFO(f, ## a); \ -} while (0) -#define INFO_DONE(f, a...) do { \ - TICK_DONE(); \ - INFO(f, ## a); \ -} while (0) -#if DEBUG_ENABLED -# define DEBUG(f, a...) do { \ - TICK_REPORT(); \ - _INFO(f, ## a); \ -} while (0) -#else -# define DEBUG(f, a...) do { } while (0) -#endif - -#if DEBUG_ENABLED -static inline void debug_dump_hex(const char *name, uint8_t *data, - uint32_t size) -{ - int i; - printf("%s: ", name); - for (i = 0; i < size; i++) { - printf("%02x ", data[i]); - } - printf("\n"); -} -#else -# define debug_dump_hex(n, d, s) do { } while (0) -#endif - -#endif /* _MOUNT_ENCRYPTED_H_ */ diff --git a/utility/mount-helpers.c b/utility/mount-helpers.c deleted file mode 100644 index aed5ef06..00000000 --- a/utility/mount-helpers.c +++ /dev/null @@ -1,803 +0,0 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * This is a collection of helper utilities for use with the "mount-encrypted" - * utility. - * - */ -#define _GNU_SOURCE -#define _FILE_OFFSET_BITS 64 -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <math.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/mount.h> -#include <linux/fs.h> -#include <linux/loop.h> - -#include <glib.h> -#include <glib/gstdio.h> - -#include <openssl/evp.h> - -#include "mount-encrypted.h" -#include "mount-helpers.h" - -static const gchar * const kRootDir = "/"; -static const gchar * const kLoopTemplate = "/dev/loop%d"; -static const int kLoopMajor = 7; -static const int kLoopMax = 8; -static const unsigned int kResizeStepSeconds = 2; -static const uint64_t kResizeBlocks = 32768 * 10; -static const uint64_t kBlocksPerGroup = 32768; -static const uint64_t kInodeRatioDefault = 16384; -static const uint64_t kInodeRatioMinimum = 2048; -static const gchar * const kExt4ExtendedOptions = "discard,lazy_itable_init"; - -int remove_tree(const char *tree) -{ - const gchar *rm[] = { - "/bin/rm", "-rf", tree, - NULL - }; - - return runcmd(rm, NULL); -} - -uint64_t blk_size(const char *device) -{ - uint64_t bytes; - int fd; - if ((fd = open(device, O_RDONLY | O_NOFOLLOW)) < 0) { - PERROR("open(%s)", device); - return 0; - } - if (ioctl(fd, BLKGETSIZE64, &bytes)) { - PERROR("ioctl(%s, BLKGETSIZE64)", device); - return 0; - } - close(fd); - return bytes; -} - -int runcmd(const gchar *argv[], gchar **output) -{ - gint rc; - gchar *out = NULL, *errout = NULL; - GError *err = NULL; - - g_spawn_sync(kRootDir, (gchar **)argv, NULL, 0, NULL, NULL, - &out, &errout, &rc, &err); - if (err) { - ERROR("%s: %s", argv[0], err->message); - g_error_free(err); - return -1; - } - - if (rc) - ERROR("%s failed (%d)\n%s\n%s", argv[0], rc, out, errout); - - if (output) - *output = out; - else - g_free(out); - g_free(errout); - - return rc; -} - -int same_vfs(const char *mnt_a, const char *mnt_b) -{ - struct stat stat_a, stat_b; - - if (lstat(mnt_a, &stat_a)) { - PERROR("lstat(%s)", mnt_a); - exit(1); - } - if (lstat(mnt_b, &stat_b)) { - PERROR("lstat(%s)", mnt_b); - exit(1); - } - return (stat_a.st_dev == stat_b.st_dev); -} - -/* Returns allocated string that holds [length]*2 + 1 characters. */ -char *stringify_hex(uint8_t *binary, size_t length) -{ - char *string; - size_t i; - - string = malloc(length * 2 + 1); - if (!string) { - PERROR("malloc"); - return NULL; - } - for (i = 0; i < length; ++i) - sprintf(string + (i * 2), "%02x", binary[i]); - string[length * 2] = '\0'; - - return string; -} - -/* Returns allocated byte array that holds strlen([string])/2 bytes. */ -uint8_t *hexify_string(char *string, uint8_t *binary, size_t length) -{ - size_t bytes, i; - - bytes = strlen(string) / 2; - if (bytes > length) { - ERROR("Hex string too long (%zu) for byte array (%zu)", - bytes, length); - return NULL; - } - - for (i = 0; i < bytes; ++i) { - if (sscanf(&string[i * 2], "%2hhx", &binary[i]) != 1) { - ERROR("Invalid hex code at byte %zu.", i); - return NULL; - } - } - - return binary; -} - -/* Overwrite file contents. Useless on SSD. :( */ -void shred(const char *pathname) -{ - uint8_t patterns[] = { 0xA5, 0x5A, 0xFF, 0x00 }; - FILE *target; - struct stat info; - uint8_t *pattern; - int fd, i; - - /* Give up if we can't safely open or stat the target. */ - if ((fd = open(pathname, O_WRONLY | O_NOFOLLOW)) < 0) { - PERROR(pathname); - return; - } - if (fstat(fd, &info)) { - close(fd); - PERROR(pathname); - return; - } - if (!(target = fdopen(fd, "w"))) { - close(fd); - PERROR(pathname); - return; - } - /* Ignore errors here, since there's nothing we can really do. */ - pattern = malloc(info.st_size); - for (i = 0; i < sizeof(patterns); ++i) { - memset(pattern, patterns[i], info.st_size); - if (fseek(target, 0, SEEK_SET)) - PERROR(pathname); - if (fwrite(pattern, info.st_size, 1, target) != 1) - PERROR(pathname); - if (fflush(target)) - PERROR(pathname); - if (fdatasync(fd)) - PERROR(pathname); - } - free(pattern); - /* fclose() closes the fd too. */ - fclose(target); -} - -static int is_loop_device(int fd) -{ - struct stat info; - - return (fstat(fd, &info) == 0 && S_ISBLK(info.st_mode) && - major(info.st_rdev) == kLoopMajor); -} - -static int loop_is_attached(int fd, struct loop_info64 *info) -{ - struct loop_info64 local_info; - - return ioctl(fd, LOOP_GET_STATUS64, info ? info : &local_info) == 0; -} - -/* Returns either the matching loopback name, or next available, if NULL. */ -static int loop_locate(gchar **loopback, const char *name) -{ - int i, fd, namelen = 0; - - if (name) { - namelen = strlen(name); - if (namelen >= LO_NAME_SIZE) { - ERROR("'%s' too long (>= %d)", name, LO_NAME_SIZE); - return -1; - } - } - - *loopback = NULL; - for (i = 0; i < kLoopMax; ++i) { - struct loop_info64 info; - int attached; - - g_free(*loopback); - *loopback = g_strdup_printf(kLoopTemplate, i); - if (!*loopback) { - PERROR("g_strdup_printf"); - return -1; - } - - fd = open(*loopback, O_RDONLY | O_NOFOLLOW); - if (fd < 0) { - PERROR("open(%s)", *loopback); - goto failed; - } - if (!is_loop_device(fd)) { - close(fd); - continue; - } - - memset(&info, 0, sizeof(info)); - attached = loop_is_attached(fd, &info); - close(fd); - - if (attached) - DEBUG("Saw %s on %s", info.lo_file_name, *loopback); - - if ((attached && name && - strncmp((char *)info.lo_file_name, name, namelen) == 0) || - (!attached && !name)) { - DEBUG("Using %s", *loopback); - /* Reopen for working on it. */ - fd = open(*loopback, O_RDWR | O_NOFOLLOW); - if (is_loop_device(fd) && - loop_is_attached(fd, NULL) == attached) - return fd; - } - } - ERROR("Ran out of loopback devices"); - -failed: - g_free(*loopback); - *loopback = NULL; - return -1; -} - -static int loop_detach_fd(int fd) -{ - if (ioctl(fd, LOOP_CLR_FD, 0)) { - PERROR("LOOP_CLR_FD"); - return 0; - } - return 1; -} - -int loop_detach(const gchar *loopback) -{ - int fd, rc = 1; - - fd = open(loopback, O_RDONLY | O_NOFOLLOW); - if (fd < 0) { - PERROR("open(%s)", loopback); - return 0; - } - if (!is_loop_device(fd) || !loop_is_attached(fd, NULL) || - !loop_detach_fd(fd)) - rc = 0; - - close (fd); - return rc; -} - -int loop_detach_name(const char *name) -{ - gchar *loopback = NULL; - int loopfd, rc; - - loopfd = loop_locate(&loopback, name); - if (loopfd < 0) - return 0; - rc = loop_detach_fd(loopfd); - - close(loopfd); - g_free(loopback); - return rc; -} - -/* Closes fd, returns name of loopback device pathname. */ -gchar *loop_attach(int fd, const char *name) -{ - gchar *loopback = NULL; - int loopfd; - struct loop_info64 info; - - loopfd = loop_locate(&loopback, NULL); - if (loopfd < 0) - return NULL; - if (ioctl(loopfd, LOOP_SET_FD, fd) < 0) { - PERROR("LOOP_SET_FD"); - goto failed; - } - - memset(&info, 0, sizeof(info)); - strncpy((char*)info.lo_file_name, name, LO_NAME_SIZE); - if (ioctl(loopfd, LOOP_SET_STATUS64, &info)) { - PERROR("LOOP_SET_STATUS64"); - goto failed; - } - - close(loopfd); - close(fd); - return loopback; -failed: - close(loopfd); - close(fd); - g_free(loopback); - return 0; -} - -int dm_setup(uint64_t sectors, const gchar *encryption_key, const char *name, - const gchar *device, const char *path, int discard) -{ - /* Mount loopback device with dm-crypt using the encryption key. */ - gchar *table = g_strdup_printf("0 %" PRIu64 " crypt " \ - "aes-cbc-essiv:sha256 %s " \ - "0 %s 0%s", - sectors, - encryption_key, - device, - discard ? " 1 allow_discards" : ""); - if (!table) { - PERROR("g_strdup_printf"); - return 0; - } - - const gchar *argv[] = { - "/sbin/dmsetup", - "create", name, - "--noudevrules", "--noudevsync", - "--table", table, - NULL - }; - - /* TODO(keescook): replace with call to libdevmapper. */ - if (runcmd(argv, NULL) != 0) { - g_free(table); - return 0; - } - g_free(table); - - /* Make sure the dm-crypt device showed up. */ - if (access(path, R_OK)) { - ERROR("%s does not exist", path); - return 0; - } - - return 1; -} - -int dm_teardown(const gchar *device) -{ - const char *argv[] = { - "/sbin/dmsetup", - "remove", device, - "--noudevrules", "--noudevsync", - NULL - }; - /* TODO(keescook): replace with call to libdevmapper. */ - if (runcmd(argv, NULL) != 0) - return 0; - return 1; -} - -char *dm_get_key(const gchar *device) -{ - gchar *output = NULL; - char *key; - int i; - const char *argv[] = { - "/sbin/dmsetup", - "table", "--showkeys", - device, - NULL - }; - /* TODO(keescook): replace with call to libdevmapper. */ - if (runcmd(argv, &output) != 0) - return NULL; - - /* Key is 4th field in the output. */ - for (i = 0, key = strtok(output, " "); - i < 4 && key; - ++i, key = strtok(NULL, " ")) { } - - /* Create a copy of the key and free the output buffer. */ - if (key) { - key = strdup(key); - g_free(output); - } - - return key; -} - -int sparse_create(const char *path, uint64_t bytes) -{ - int sparsefd; - - sparsefd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, - S_IRUSR | S_IWUSR); - if (sparsefd < 0) - goto out; - - if (ftruncate(sparsefd, bytes)) { - int saved_errno = errno; - - close(sparsefd); - unlink(path); - errno = saved_errno; - - sparsefd = -1; - } - -out: - return sparsefd; -} - -/* When creating a filesystem that will grow, the inode ratio is calculated - * using the starting size not the hinted "resize" size, which means the - * number of inodes can be highly constrained on tiny starting filesystems. - * Instead, calculate what the correct inode ratio should be for a given - * filesystem based on its expected starting and ending sizes. - * - * inode-ratio_mkfs = - * - * ceil(blocks_max / group-ratio) * size_mkfs - * ------------------------------------------------------------------ - * ceil(size_max / inode-ratio_max) * ceil(blocks_mkfs / group-ratio) - */ -static uint64_t get_inode_ratio(uint64_t block_bytes_in, - uint64_t blocks_mkfs_in, - uint64_t blocks_max_in) -{ - double block_bytes = (double)block_bytes_in; - double blocks_mkfs = (double)blocks_mkfs_in; - double blocks_max = (double)blocks_max_in; - - double size_max, size_mkfs, groups_max, groups_mkfs, inodes_max; - double denom, inode_ratio_mkfs; - - size_max = block_bytes * blocks_max; - size_mkfs = block_bytes * blocks_mkfs; - - groups_max = ceil(blocks_max / kBlocksPerGroup); - groups_mkfs = ceil(blocks_mkfs / kBlocksPerGroup); - - inodes_max = ceil(size_max / kInodeRatioDefault); - - denom = inodes_max * groups_mkfs; - /* Make sure we never trigger divide-by-zero. */ - if (denom == 0.0) - goto failure; - inode_ratio_mkfs = (groups_max * size_mkfs) / denom; - - /* Make sure we never calculate anything totally huge. */ - if (inode_ratio_mkfs > blocks_mkfs) - goto failure; - /* Make sure we never calculate anything totally tiny. */ - if (inode_ratio_mkfs < kInodeRatioMinimum) - goto failure; - - return (uint64_t)inode_ratio_mkfs; - -failure: - return kInodeRatioDefault; -} - -/* Creates an ext4 filesystem. - * device: path to block device to create filesystem on. - * block_bytes: bytes per block to use for filesystem. - * blocks_min: starting number of blocks on filesystem. - * blocks_max: largest expected size in blocks of filesystem, for growth hints. - * - * Returns 1 on success, 0 on failure. - */ -int filesystem_build(const char *device, uint64_t block_bytes, - uint64_t blocks_min, uint64_t blocks_max) -{ - int rc = 0; - uint64_t inode_ratio; - - gchar *blocksize = g_strdup_printf("%" PRIu64, block_bytes); - if (!blocksize) { - PERROR("g_strdup_printf"); - goto out; - } - - gchar *blocks_str; - blocks_str = g_strdup_printf("%" PRIu64, blocks_min); - if (!blocks_str) { - PERROR("g_strdup_printf"); - goto free_blocksize; - } - - gchar *extended; - if (blocks_min < blocks_max) { - extended = g_strdup_printf("%s,resize=%" PRIu64, - kExt4ExtendedOptions, blocks_max); - } else { - extended = g_strdup_printf("%s", kExt4ExtendedOptions); - } - if (!extended) { - PERROR("g_strdup_printf"); - goto free_blocks_str; - } - - inode_ratio = get_inode_ratio(block_bytes, blocks_min, blocks_max); - gchar *inode_ratio_str = g_strdup_printf("%" PRIu64, inode_ratio); - if (!inode_ratio_str) { - PERROR("g_strdup_printf"); - goto free_extended; - } - - const gchar *mkfs[] = { - "/sbin/mkfs.ext4", - "-T", "default", - "-b", blocksize, - "-m", "0", - "-O", "^huge_file,^flex_bg", - "-i", inode_ratio_str, - "-E", extended, - device, - blocks_str, - NULL - }; - - rc = (runcmd(mkfs, NULL) == 0); - if (!rc) - goto free_inode_ratio_str; - - const gchar *tune2fs[] = { - "/sbin/tune2fs", - "-c", "0", - "-i", "0", - device, - NULL - }; - rc = (runcmd(tune2fs, NULL) == 0); - -free_inode_ratio_str: - g_free(inode_ratio_str); -free_extended: - g_free(extended); -free_blocks_str: - g_free(blocks_str); -free_blocksize: - g_free(blocksize); -out: - return rc; -} - -/* Spawns a filesystem resizing process. */ -int filesystem_resize(const char *device, uint64_t blocks, uint64_t blocks_max) -{ - /* Ignore resizing if we know the filesystem was built to max size. */ - if (blocks >= blocks_max) { - INFO("Resizing aborted. blocks:%" PRIu64 " >= blocks_max:%" PRIu64, - blocks, blocks_max); - return 1; - } - - /* TODO(keescook): Read superblock to find out the current size of - * the filesystem (since statvfs does not report the correct value). - * For now, instead of doing multi-step resizing, just resize to the - * full size of the block device in one step. - */ - blocks = blocks_max; - - INFO("Resizing started in %d second steps.", kResizeStepSeconds); - - do { - gchar *blocks_str; - - sleep(kResizeStepSeconds); - - blocks += kResizeBlocks; - if (blocks > blocks_max) - blocks = blocks_max; - - blocks_str = g_strdup_printf("%" PRIu64, blocks); - if (!blocks_str) { - PERROR("g_strdup_printf"); - return 0; - } - - const gchar *resize[] = { - "/sbin/resize2fs", - "-f", - device, - blocks_str, - NULL - }; - - INFO("Resizing filesystem on %s to %" PRIu64 ".", device, blocks); - if (runcmd(resize, NULL)) { - ERROR("resize2fs failed"); - return 0; - } - g_free(blocks_str); - } while (blocks < blocks_max); - - INFO("Resizing finished."); - return 1; -} - -char *keyfile_read(const char *keyfile, uint8_t *system_key) -{ - char *key = NULL; - unsigned char *cipher = NULL; - gsize length; - uint8_t *plain = NULL; - int plain_length, final_len; - GError *error = NULL; - EVP_CIPHER_CTX ctx; - const EVP_CIPHER *algo = EVP_aes_256_cbc(); - - DEBUG("Reading keyfile %s", keyfile); - if (EVP_CIPHER_key_length(algo) != DIGEST_LENGTH) { - ERROR("cipher key size mismatch (got %d, want %d)", - EVP_CIPHER_key_length(algo), DIGEST_LENGTH); - goto out; - } - - if (access(keyfile, R_OK)) { - /* This file being missing is handled in caller, so - * do not emit error message. - */ - INFO("%s does not exist.", keyfile); - goto out; - } - - if (!g_file_get_contents(keyfile, (gchar **)&cipher, &length, - &error)) { - ERROR("Unable to read %s: %s", keyfile, error->message); - g_error_free(error); - goto out; - } - plain = malloc(length + EVP_CIPHER_block_size(algo)); - if (!plain) { - PERROR("malloc"); - goto free_cipher; - } - - DEBUG("Decrypting keyfile %s", keyfile); - /* Use the default IV. */ - if (!EVP_DecryptInit(&ctx, algo, system_key, NULL)) { - SSL_ERROR("EVP_DecryptInit"); - goto free_plain; - } - if (!EVP_DecryptUpdate(&ctx, plain, &plain_length, cipher, length)) { - SSL_ERROR("EVP_DecryptUpdate"); - goto free_ctx; - } - if (!EVP_DecryptFinal(&ctx, plain+plain_length, &final_len)) { - SSL_ERROR("EVP_DecryptFinal"); - goto free_ctx; - } - plain_length += final_len; - - if (plain_length != DIGEST_LENGTH) { - ERROR("Decrypted encryption key length (%d) is not %d.", - plain_length, DIGEST_LENGTH); - goto free_ctx; - } - - debug_dump_hex("encryption key", plain, DIGEST_LENGTH); - - key = stringify_hex(plain, DIGEST_LENGTH); - -free_ctx: - EVP_CIPHER_CTX_cleanup(&ctx); -free_plain: - free(plain); -free_cipher: - g_free(cipher); -out: - DEBUG("key:%p", key); - return key; -} - -int keyfile_write(const char *keyfile, uint8_t *system_key, char *string) -{ - int rc = 0; - size_t length; - uint8_t plain[DIGEST_LENGTH]; - uint8_t *cipher = NULL; - int cipher_length, final_len; - GError *error = NULL; - EVP_CIPHER_CTX ctx; - const EVP_CIPHER *algo = EVP_aes_256_cbc(); - mode_t mask; - - DEBUG("Staring to process keyfile %s", keyfile); - /* Have key file be read/write only by root user. */ - mask = umask(0077); - - if (EVP_CIPHER_key_length(algo) != DIGEST_LENGTH) { - ERROR("cipher key size mismatch (got %d, want %d)", - EVP_CIPHER_key_length(algo), DIGEST_LENGTH); - goto out; - } - - if (access(keyfile, R_OK) == 0) { - ERROR("%s already exists.", keyfile); - goto out; - } - - length = strlen(string); - if (length != sizeof(plain) * 2) { - ERROR("Encryption key string length (%zu) is not %zu.", - length, sizeof(plain) * 2); - goto out; - } - - length = sizeof(plain); - if (!hexify_string(string, plain, length)) { - ERROR("Failed to convert encryption key to byte array"); - goto out; - } - - debug_dump_hex("encryption key", plain, DIGEST_LENGTH); - - cipher = malloc(length + EVP_CIPHER_block_size(algo)); - if (!cipher) { - PERROR("malloc"); - goto out; - } - - DEBUG("Encrypting keyfile %s", keyfile); - /* Use the default IV. */ - if (!EVP_EncryptInit(&ctx, algo, system_key, NULL)) { - SSL_ERROR("EVP_EncryptInit"); - goto free_cipher; - } - if (!EVP_EncryptUpdate(&ctx, cipher, &cipher_length, - (unsigned char *)plain, length)) { - SSL_ERROR("EVP_EncryptUpdate"); - goto free_ctx; - } - if (!EVP_EncryptFinal(&ctx, cipher+cipher_length, &final_len)) { - SSL_ERROR("EVP_EncryptFinal"); - goto free_ctx; - } - length = cipher_length + final_len; - - DEBUG("Writing %zu bytes to %s", length, keyfile); - /* TODO(keescook): use fd here, and set secure delete. Unsupported - * by ext4 currently. :( - * int f; - * ioctl(fd, EXT2_IOC_GETFLAGS, &f); - * f |= EXT2_SECRM_FL; - * ioctl(fd, EXT2_IOC_SETFLAGS, &f); - */ - if (!g_file_set_contents(keyfile, (gchar *)cipher, length, &error)) { - ERROR("Unable to write %s: %s", keyfile, error->message); - g_error_free(error); - goto free_ctx; - } - - rc = 1; - -free_ctx: - EVP_CIPHER_CTX_cleanup(&ctx); -free_cipher: - free(cipher); -out: - umask(mask); - DEBUG("keyfile write rc:%d", rc); - return rc; -} diff --git a/utility/mount-helpers.h b/utility/mount-helpers.h deleted file mode 100644 index d2aa1795..00000000 --- a/utility/mount-helpers.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * Header file for mount helpers. - */ -#ifndef _MOUNT_HELPERS_H_ -#define _MOUNT_HELPERS_H_ - -/* General utility functions. */ -uint64_t blk_size(const char *device); -int remove_tree(const char *tree); -int runcmd(const gchar *argv[], gchar **output); -int same_vfs(const char *mnt_a, const char *mnt_b); -char *stringify_hex(uint8_t *binary, size_t length); -uint8_t *hexify_string(char *string, uint8_t *binary, size_t length); -void shred(const char *keyfile); - -/* Loopback device attach/detach helpers. */ -gchar *loop_attach(int fd, const char *name); -int loop_detach(const gchar *loopback); -int loop_detach_name(const char *name); - -/* Encrypted device mapper setup/teardown. */ -int dm_setup(uint64_t bytes, const gchar *encryption_key, const char *name, - const gchar *device, const char *path, int discard); -int dm_teardown(const gchar *device); -char *dm_get_key(const gchar *device); - -/* Sparse file creation. */ -int sparse_create(const char *path, uint64_t bytes); - -/* Filesystem creation. */ -int filesystem_build(const char *device, uint64_t block_bytes, - uint64_t blocks_min, uint64_t blocks_max); -int filesystem_resize(const char *device, uint64_t blocks, uint64_t blocks_max); - -/* Encrypted keyfile handling. */ -char *keyfile_read(const char *keyfile, uint8_t *system_key); -int keyfile_write(const char *keyfile, uint8_t *system_key, char *plain); - -#endif /* _MOUNT_HELPERS_H_ */ |