1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <sysexits.h>
28
29 #include <android/hardware/boot/1.0/IBootControl.h>
30
31 #include <libavb_user/libavb_user.h>
32
33 using android::sp;
34 using android::hardware::hidl_string;
35 using android::hardware::Return;
36 using android::hardware::boot::V1_0::IBootControl;
37 using android::hardware::boot::V1_0::Slot;
38
39 namespace {
40
41 /* Prints program usage to |where|. */
usage(FILE * where,int,char * argv[])42 void usage(FILE* where, int /* argc */, char* argv[]) {
43 fprintf(where,
44 "%s - command-line tool for AVB.\n"
45 "\n"
46 "Usage:\n"
47 " %s COMMAND\n"
48 "\n"
49 "Commands:\n"
50 " %s disable-verity - Disable verity in current slot.\n"
51 " %s enable-verity - Enable verity in current slot.\n",
52 argv[0],
53 argv[0],
54 argv[0],
55 argv[0]);
56 }
57
58 /* Returns the A/B suffix the device booted from or the empty string
59 * if A/B is not in use.
60 */
get_ab_suffix(sp<IBootControl> module)61 std::string get_ab_suffix(sp<IBootControl> module) {
62 std::string suffix = "";
63
64 if (module != nullptr) {
65 uint32_t num_slots = module->getNumberSlots();
66 if (num_slots > 1) {
67 Slot cur_slot = module->getCurrentSlot();
68 Return<void> ret =
69 module->getSuffix(cur_slot, [&suffix](const hidl_string& value) {
70 suffix = std::string(value.c_str());
71 });
72 if (!ret.isOk()) {
73 fprintf(stderr, "Error getting suffix for slot %d.\n", cur_slot);
74 }
75 }
76 }
77
78 return suffix;
79 }
80
81 /* Loads the toplevel AvbVBMetaImageHeader from the slot denoted by
82 * |ab_suffix| into |vbmeta_image|. No validation, verification, or
83 * byteswapping is performed.
84 *
85 * If successful, |true| is returned and the partition it was loaded
86 * from is returned in |out_partition_name| and the offset on said
87 * partition is returned in |out_vbmeta_offset|.
88 */
load_top_level_vbmeta_header(AvbOps * ops,const std::string & ab_suffix,uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE],std::string * out_partition_name,uint64_t * out_vbmeta_offset)89 bool load_top_level_vbmeta_header(
90 AvbOps* ops,
91 const std::string& ab_suffix,
92 uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE],
93 std::string* out_partition_name,
94 uint64_t* out_vbmeta_offset) {
95 std::string partition_name = std::string("vbmeta") + ab_suffix;
96 uint64_t vbmeta_offset = 0;
97
98 // Only read the header.
99 size_t num_read;
100 AvbIOResult io_res = ops->read_from_partition(ops,
101 partition_name.c_str(),
102 vbmeta_offset,
103 AVB_VBMETA_IMAGE_HEADER_SIZE,
104 vbmeta_image,
105 &num_read);
106 if (io_res == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
107 AvbFooter footer;
108 // Try looking for the vbmeta struct in 'boot' via the footer.
109 partition_name = std::string("boot") + ab_suffix;
110 io_res = ops->read_from_partition(ops,
111 partition_name.c_str(),
112 -AVB_FOOTER_SIZE,
113 AVB_FOOTER_SIZE,
114 &footer,
115 &num_read);
116 if (io_res != AVB_IO_RESULT_OK) {
117 fprintf(stderr,
118 "Error loading footer from partition '%s' (%d).\n",
119 partition_name.c_str(),
120 io_res);
121 return false;
122 }
123
124 if (memcmp(footer.magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != 0) {
125 fprintf(stderr,
126 "Data from '%s' does not look like a vbmeta footer.\n",
127 partition_name.c_str());
128 return false;
129 }
130
131 vbmeta_offset = avb_be64toh(footer.vbmeta_offset);
132 io_res = ops->read_from_partition(ops,
133 partition_name.c_str(),
134 vbmeta_offset,
135 AVB_VBMETA_IMAGE_HEADER_SIZE,
136 vbmeta_image,
137 &num_read);
138 }
139
140 if (io_res != AVB_IO_RESULT_OK) {
141 fprintf(stderr,
142 "Error loading from offset %" PRIu64 " of partition '%s' (%d).\n",
143 vbmeta_offset,
144 partition_name.c_str(),
145 io_res);
146 return false;
147 }
148
149 if (out_partition_name != nullptr) {
150 *out_partition_name = partition_name;
151 }
152 if (out_vbmeta_offset != nullptr) {
153 *out_vbmeta_offset = vbmeta_offset;
154 }
155 return true;
156 }
157
158 /* Function to enable and disable dm-verity. The |ops| parameter
159 * should be an |AvbOps| from libavb_user and |module| can either be
160 * |nullptr| or a valid boot_control module.
161 */
do_set_verity(AvbOps * ops,sp<IBootControl> module,bool enable_verity)162 int do_set_verity(AvbOps* ops, sp<IBootControl> module, bool enable_verity) {
163 uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE]; // 256 bytes.
164 std::string ab_suffix;
165 std::string partition_name;
166 uint64_t vbmeta_offset;
167 AvbIOResult io_res;
168
169 ab_suffix = get_ab_suffix(module);
170
171 if (!load_top_level_vbmeta_header(
172 ops, ab_suffix, vbmeta_image, &partition_name, &vbmeta_offset)) {
173 return EX_SOFTWARE;
174 }
175
176 if (memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
177 fprintf(stderr,
178 "Data from '%s' does not look like a vbmeta header.\n",
179 partition_name.c_str());
180 return EX_SOFTWARE;
181 }
182
183 // Set/clear the HASHTREE_DISABLED bit, as requested.
184 AvbVBMetaImageHeader* header =
185 reinterpret_cast<AvbVBMetaImageHeader*>(vbmeta_image);
186 uint32_t flags = avb_be32toh(header->flags);
187 flags &= ~AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED;
188 if (!enable_verity) {
189 flags |= AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED;
190 }
191 header->flags = avb_htobe32(flags);
192
193 // Write the header.
194 io_res = ops->write_to_partition(ops,
195 partition_name.c_str(),
196 vbmeta_offset,
197 AVB_VBMETA_IMAGE_HEADER_SIZE,
198 vbmeta_image);
199 if (io_res != AVB_IO_RESULT_OK) {
200 fprintf(stderr,
201 "Error writing to offset %" PRIu64 " of partition '%s' (%d).\n",
202 vbmeta_offset,
203 partition_name.c_str(),
204 io_res);
205 return EX_SOFTWARE;
206 }
207
208 fprintf(stdout,
209 "Successfully %s verity on %s.\n",
210 enable_verity ? "enabled" : "disabled",
211 partition_name.c_str());
212
213 return EX_OK;
214 }
215
216 } // namespace
217
main(int argc,char * argv[])218 int main(int argc, char* argv[]) {
219 int ret;
220 sp<IBootControl> module;
221 AvbOps* ops = nullptr;
222
223 if (argc < 2) {
224 usage(stderr, argc, argv);
225 ret = EX_USAGE;
226 goto out;
227 }
228
229 ops = avb_ops_user_new();
230 if (ops == nullptr) {
231 fprintf(stderr, "Error getting AVB ops.\n");
232 ret = EX_SOFTWARE;
233 goto out;
234 }
235
236 // Failing to get the boot_control HAL is not a fatal error - it can
237 // happen if A/B is not in use, in which case |nullptr| is returned.
238 module = IBootControl::getService();
239
240 if (strcmp(argv[1], "disable-verity") == 0) {
241 ret = do_set_verity(ops, module, false);
242 } else if (strcmp(argv[1], "enable-verity") == 0) {
243 ret = do_set_verity(ops, module, true);
244 } else {
245 usage(stderr, argc, argv);
246 ret = EX_USAGE;
247 }
248
249 ret = EX_OK;
250 out:
251 if (ops != nullptr) {
252 avb_ops_user_free(ops);
253 }
254 return ret;
255 }
256