blob: 80c707b3e3810d0553b74e0c7f076f9af96e6e08 [file] [log] [blame]
// 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 "installer/chromeos_setimage.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <vector>
#include <base/logging.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include "installer/chromeos_install_config.h"
#include "installer/chromeos_verity.h"
#include "installer/inst_util.h"
using std::string;
//
// There is nothing in our codebase that calls chromeos-setimage,
// except for post install, so only it's use case is required
// here. I think.
//
// New dm argument syntax:
// TODO(taysom:defect 32847)
// In the future, the <num> field will be mandatory.
//
// <device> ::= [<num>] <device-mapper>+
// <device-mapper> ::= <head> "," <target>+
// <head> ::= <name> <uuid> <mode> [<num>]
// <target> ::= <start> <length> <type> <options> ","
// <mode> ::= "ro" | "rw"
// <uuid> ::= xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | "none"
// <type> ::= "verity" | "bootcache" | ...
//
// Notes:
// 1. uuid is a label for the device and we set it to "none".
// 2. The <num> field will be optional initially and assumed to be 1.
// Once all the scripts that set these fields have been set, it will
// made mandatory.
//
// Coming attractions:
// The upstream version of verity does not use name/value pairs for
// arguments. All arguments are positional. The current code for
// finding the root_hexdigest and salt will need to change accordingly.
//
// Don't know if we can make the code parse both types of arguments.
bool SetImage(const InstallConfig& install_config) {
LOG(INFO) << "SetImage";
// Re-hash the root filesystem and use the table for dm-verity.
// We extract the parameters for verification from the kernel
// partition, but we regenerate and reappend the hash tree to
// keep the updater from needing to manage them explicitly.
// Instead, rootfs integrity will be validated on next boot through
// the verified kernel configuration.
string kernel_config = DumpKernelConfig(install_config.kernel.device());
LOG(INFO) << "KERNEL_CONFIG: " << kernel_config;
// An example value: <root_hexdigest and salt values shortened>
//
// quiet loglevel=1 console=tty2 init=/sbin/init add_efi_memmap boot=local
// noresume noswap i915.modeset=1 cros_secure tpm_tis.force=1
// tpm_tis.interrupts=0 nmi_watchdog=panic,lapic root=/dev/dm-0 rootwait
// ro dm_verity.error_behavior=3 dm_verity.max_bios=-1 dm_verity.dev_wait=1
// dm="vroot none ro,0 1740800 verity payload=%U+1 hashtree=%U+1
// hashstart=1740800 alg=sha1 root_hexdigest=30348c07f salt=a9864eaf11f4
// 66fc48dffef" noinitrd cros_debug vt.global_cursor_default=0 kern_guid=%U
//
string kernel_config_root = ExtractKernelArg(kernel_config, "root");
string dm_config = ExtractKernelArg(kernel_config, "dm");
std::vector<string> dm_parts = base::SplitString(
dm_config, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
// Extract verity specific options
string verity_args;
for (unsigned i = 0; i < dm_parts.size(); i++) {
if (dm_parts[i].find(" verity ") != string::npos) {
verity_args = dm_parts[i];
break;
}
}
if (verity_args.empty()) {
LOG(ERROR) << "Didn't find verity args in the dm command line: "
<< dm_config;
return false;
}
// Extract specific verity arguments
string rootfs_sectors = ExtractKernelArg(verity_args, "hashstart");
string verity_algorithm = ExtractKernelArg(verity_args, "alg");
string expected_hash = ExtractKernelArg(verity_args, "root_hexdigest");
string salt = ExtractKernelArg(verity_args, "salt");
bool enable_rootfs_verification = IsReadonly(kernel_config_root);
if (!enable_rootfs_verification)
MakeFileSystemRw(install_config.root.device());
LOG(INFO) << "Setting up verity.";
LoggingTimerStart();
int result = chromeos_verity(verity_algorithm, install_config.root.device(),
getpagesize(),
(uint64_t)(atoi(rootfs_sectors.c_str()) / 8),
salt, expected_hash, enable_rootfs_verification);
LoggingTimerFinish();
return result == 0;
}