blob: c9198e0910a475ec6ccc5fbf00fe06b6fbe02873 [file] [log] [blame]
Alex Deymoa26432a2015-03-12 16:08:04 -07001// Copyright 2015 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/payload_generator/verity_utils.h"
6
7#include <algorithm>
8#include <utility>
9#include <vector>
10
11#include <base/logging.h>
12#include <base/strings/string_number_conversions.h>
13#include <base/strings/string_util.h>
14#include <chromeos/strings/string_utils.h>
15extern "C" {
16#include <vboot/vboot_host.h>
17}
18
19using std::string;
20using std::vector;
21
22extern "C" {
23
24// vboot_host.h has a default VbExError() that will call exit() when a function
25// fails. We redefine that function here so it doesn't exit.
26void VbExError(const char* format, ...) {
27 va_list ap;
28 va_start(ap, format);
29 fprintf(stderr, "ERROR: ");
30 va_end(ap);
31}
32
33}
34
35namespace {
36
37// Splits a string with zero or more arguments separated by spaces into a list
38// of strings, but respecting the double quotes. For example, the string:
39// a="foo" b=foo c="bar baz" "my dir"/"my file"
40// has only four arguments, since some parts are grouped together due to the
41// double quotes.
42vector<string> SplitQuotedArgs(const string arglist) {
43 vector<string> terms = chromeos::string_utils::Split(
44 arglist, " ", false, false);
45 vector<string> result;
46 string last_term;
47 size_t quotes = 0;
48 for (const string& term : terms) {
49 if (quotes % 2 == 0 && term.empty())
50 continue;
51
52 quotes += std::count(term.begin(), term.end(), '"');
53 if (last_term.empty()) {
54 last_term = term;
55 } else {
56 last_term += " " + term;
57 }
58 if (quotes % 2 == 0) {
59 result.push_back(last_term);
60 last_term.clear();
61 quotes = 0;
62 }
63 }
64 // Unterminated quoted string found.
65 if (!last_term.empty())
66 result.push_back(last_term);
67 return result;
68}
69
70} // namespace
71
72namespace chromeos_update_engine {
73
74bool ParseVerityRootfsSize(const string& kernel_cmdline,
75 uint64_t* rootfs_size) {
76 vector<string> kernel_args = SplitQuotedArgs(kernel_cmdline);
77
78 for (const string& arg : kernel_args) {
79 std::pair<string, string> key_value =
80 chromeos::string_utils::SplitAtFirst(arg, "=", true);
81 if (key_value.first != "dm")
82 continue;
83 string value = key_value.second;
84 if (value.size() > 1 && value.front() == '"' && value.back() == '"')
85 value = value.substr(1, value.size() - 1);
86
87 vector<string> dm_parts = SplitQuotedArgs(value);
88 // Check if this is a dm-verity device.
89 if (std::find(dm_parts.begin(), dm_parts.end(), "verity") == dm_parts.end())
90 continue;
91 for (const string& dm_part : dm_parts) {
92 key_value = chromeos::string_utils::SplitAtFirst(dm_part, "=", true);
93 if (key_value.first != "hashstart")
94 continue;
95 if (!base::StringToUint64(key_value.second, rootfs_size))
96 continue;
97 // The hashstart= value is specified in 512-byte blocks, so we need to
98 // convert that to bytes.
99 *rootfs_size *= 512;
100 return true;
101 }
102 }
103 return false;
104}
105
106bool GetVerityRootfsSize(const string& kernel_dev, uint64_t* rootfs_size) {
107 string kernel_cmdline;
108 char *config = FindKernelConfig(kernel_dev.c_str(), USE_PREAMBLE_LOAD_ADDR);
109 if (!config) {
110 LOG(WARNING) << "Error retrieving kernel command line from '"
111 << kernel_dev << "', ignoring.";
112 return false;
113 }
114 kernel_cmdline = string(config, MAX_KERNEL_CONFIG_SIZE);
115
116 // FindKernelConfig() expects the caller to free the char*.
117 free(config);
118
119 if (!ParseVerityRootfsSize(kernel_cmdline, rootfs_size)) {
120 LOG(INFO) << "Didn't find the rootfs size in the kernel command line: "
121 << kernel_cmdline;
122 return false;
123 }
124 return true;
125}
126
127} // namespace chromeos_update_engine