]>
Commit | Line | Data |
---|---|---|
60b2f9e7 IO |
1 | |
2 | /* | |
3 | * (C) Copyright 2018, Linaro Limited | |
4 | * | |
5 | * SPDX-License-Identifier: GPL-2.0+ | |
6 | */ | |
7 | ||
8 | #include <avb_verify.h> | |
9 | #include <command.h> | |
10 | #include <image.h> | |
11 | #include <malloc.h> | |
12 | #include <mmc.h> | |
13 | ||
14 | #define AVB_BOOTARGS "avb_bootargs" | |
15 | static struct AvbOps *avb_ops; | |
16 | ||
17 | static const char * const requested_partitions[] = {"boot", | |
18 | "system", | |
19 | "vendor", | |
20 | NULL}; | |
21 | ||
22 | int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
23 | { | |
24 | unsigned long mmc_dev; | |
25 | ||
26 | if (argc != 2) | |
27 | return CMD_RET_USAGE; | |
28 | ||
29 | mmc_dev = simple_strtoul(argv[1], NULL, 16); | |
30 | ||
31 | if (avb_ops) | |
32 | avb_ops_free(avb_ops); | |
33 | ||
34 | avb_ops = avb_ops_alloc(mmc_dev); | |
35 | if (avb_ops) | |
36 | return CMD_RET_SUCCESS; | |
37 | ||
6d89902d JW |
38 | printf("Failed to initialize avb2\n"); |
39 | ||
60b2f9e7 IO |
40 | return CMD_RET_FAILURE; |
41 | } | |
42 | ||
43 | int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
44 | { | |
45 | const char *part; | |
46 | s64 offset; | |
47 | size_t bytes, bytes_read = 0; | |
48 | void *buffer; | |
49 | ||
50 | if (!avb_ops) { | |
51 | printf("AVB 2.0 is not initialized, please run 'avb init'\n"); | |
52 | return CMD_RET_USAGE; | |
53 | } | |
54 | ||
55 | if (argc != 5) | |
56 | return CMD_RET_USAGE; | |
57 | ||
58 | part = argv[1]; | |
59 | offset = simple_strtoul(argv[2], NULL, 16); | |
60 | bytes = simple_strtoul(argv[3], NULL, 16); | |
61 | buffer = (void *)simple_strtoul(argv[4], NULL, 16); | |
62 | ||
63 | if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, | |
64 | buffer, &bytes_read) == | |
65 | AVB_IO_RESULT_OK) { | |
66 | printf("Read %zu bytes\n", bytes_read); | |
67 | return CMD_RET_SUCCESS; | |
68 | } | |
69 | ||
6d89902d JW |
70 | printf("Failed to read from partition\n"); |
71 | ||
60b2f9e7 IO |
72 | return CMD_RET_FAILURE; |
73 | } | |
74 | ||
75 | int do_avb_read_part_hex(cmd_tbl_t *cmdtp, int flag, int argc, | |
76 | char *const argv[]) | |
77 | { | |
78 | const char *part; | |
79 | s64 offset; | |
80 | size_t bytes, bytes_read = 0; | |
81 | char *buffer; | |
82 | ||
83 | if (!avb_ops) { | |
84 | printf("AVB 2.0 is not initialized, please run 'avb init'\n"); | |
85 | return CMD_RET_USAGE; | |
86 | } | |
87 | ||
88 | if (argc != 4) | |
89 | return CMD_RET_USAGE; | |
90 | ||
91 | part = argv[1]; | |
92 | offset = simple_strtoul(argv[2], NULL, 16); | |
93 | bytes = simple_strtoul(argv[3], NULL, 16); | |
94 | ||
95 | buffer = malloc(bytes); | |
96 | if (!buffer) { | |
97 | printf("Failed to tlb_allocate buffer for data\n"); | |
98 | return CMD_RET_FAILURE; | |
99 | } | |
100 | memset(buffer, 0, bytes); | |
101 | ||
102 | if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, buffer, | |
103 | &bytes_read) == AVB_IO_RESULT_OK) { | |
104 | printf("Requested %zu, read %zu bytes\n", bytes, bytes_read); | |
105 | printf("Data: "); | |
106 | for (int i = 0; i < bytes_read; i++) | |
107 | printf("%02X", buffer[i]); | |
108 | ||
109 | printf("\n"); | |
110 | ||
111 | free(buffer); | |
112 | return CMD_RET_SUCCESS; | |
113 | } | |
114 | ||
6d89902d JW |
115 | printf("Failed to read from partition\n"); |
116 | ||
60b2f9e7 IO |
117 | free(buffer); |
118 | return CMD_RET_FAILURE; | |
119 | } | |
120 | ||
121 | int do_avb_write_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
122 | { | |
123 | const char *part; | |
124 | s64 offset; | |
125 | size_t bytes; | |
126 | void *buffer; | |
127 | ||
128 | if (!avb_ops) { | |
129 | printf("AVB 2.0 is not initialized, run 'avb init' first\n"); | |
130 | return CMD_RET_FAILURE; | |
131 | } | |
132 | ||
133 | if (argc != 5) | |
134 | return CMD_RET_USAGE; | |
135 | ||
136 | part = argv[1]; | |
137 | offset = simple_strtoul(argv[2], NULL, 16); | |
138 | bytes = simple_strtoul(argv[3], NULL, 16); | |
139 | buffer = (void *)simple_strtoul(argv[4], NULL, 16); | |
140 | ||
141 | if (avb_ops->write_to_partition(avb_ops, part, offset, bytes, buffer) == | |
142 | AVB_IO_RESULT_OK) { | |
143 | printf("Wrote %zu bytes\n", bytes); | |
144 | return CMD_RET_SUCCESS; | |
145 | } | |
146 | ||
6d89902d JW |
147 | printf("Failed to write in partition\n"); |
148 | ||
60b2f9e7 IO |
149 | return CMD_RET_FAILURE; |
150 | } | |
151 | ||
152 | int do_avb_read_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
153 | { | |
154 | size_t index; | |
155 | u64 rb_idx; | |
156 | ||
157 | if (!avb_ops) { | |
158 | printf("AVB 2.0 is not initialized, run 'avb init' first\n"); | |
159 | return CMD_RET_FAILURE; | |
160 | } | |
161 | ||
162 | if (argc != 2) | |
163 | return CMD_RET_USAGE; | |
164 | ||
165 | index = (size_t)simple_strtoul(argv[1], NULL, 16); | |
166 | ||
167 | if (avb_ops->read_rollback_index(avb_ops, index, &rb_idx) == | |
168 | AVB_IO_RESULT_OK) { | |
ab2d7382 | 169 | printf("Rollback index: %llx\n", rb_idx); |
60b2f9e7 IO |
170 | return CMD_RET_SUCCESS; |
171 | } | |
6d89902d JW |
172 | |
173 | printf("Failed to read rollback index\n"); | |
174 | ||
60b2f9e7 IO |
175 | return CMD_RET_FAILURE; |
176 | } | |
177 | ||
178 | int do_avb_write_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
179 | { | |
180 | size_t index; | |
181 | u64 rb_idx; | |
182 | ||
183 | if (!avb_ops) { | |
184 | printf("AVB 2.0 is not initialized, run 'avb init' first\n"); | |
185 | return CMD_RET_FAILURE; | |
186 | } | |
187 | ||
188 | if (argc != 3) | |
189 | return CMD_RET_USAGE; | |
190 | ||
191 | index = (size_t)simple_strtoul(argv[1], NULL, 16); | |
192 | rb_idx = simple_strtoul(argv[2], NULL, 16); | |
193 | ||
194 | if (avb_ops->write_rollback_index(avb_ops, index, rb_idx) == | |
195 | AVB_IO_RESULT_OK) | |
196 | return CMD_RET_SUCCESS; | |
197 | ||
6d89902d JW |
198 | printf("Failed to write rollback index\n"); |
199 | ||
60b2f9e7 IO |
200 | return CMD_RET_FAILURE; |
201 | } | |
202 | ||
203 | int do_avb_get_uuid(cmd_tbl_t *cmdtp, int flag, | |
204 | int argc, char * const argv[]) | |
205 | { | |
206 | const char *part; | |
207 | char buffer[UUID_STR_LEN + 1]; | |
208 | ||
209 | if (!avb_ops) { | |
210 | printf("AVB 2.0 is not initialized, run 'avb init' first\n"); | |
211 | return CMD_RET_FAILURE; | |
212 | } | |
213 | ||
214 | if (argc != 2) | |
215 | return CMD_RET_USAGE; | |
216 | ||
217 | part = argv[1]; | |
218 | ||
219 | if (avb_ops->get_unique_guid_for_partition(avb_ops, part, buffer, | |
220 | UUID_STR_LEN + 1) == | |
221 | AVB_IO_RESULT_OK) { | |
222 | printf("'%s' UUID: %s\n", part, buffer); | |
223 | return CMD_RET_SUCCESS; | |
224 | } | |
225 | ||
6d89902d JW |
226 | printf("Failed to read UUID\n"); |
227 | ||
60b2f9e7 IO |
228 | return CMD_RET_FAILURE; |
229 | } | |
230 | ||
231 | int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag, | |
232 | int argc, char *const argv[]) | |
233 | { | |
234 | AvbSlotVerifyResult slot_result; | |
235 | AvbSlotVerifyData *out_data; | |
5d4fd877 IO |
236 | char *cmdline; |
237 | char *extra_args; | |
60b2f9e7 IO |
238 | |
239 | bool unlocked = false; | |
240 | int res = CMD_RET_FAILURE; | |
241 | ||
242 | if (!avb_ops) { | |
243 | printf("AVB 2.0 is not initialized, run 'avb init' first\n"); | |
244 | return CMD_RET_FAILURE; | |
245 | } | |
246 | ||
247 | if (argc != 1) | |
248 | return CMD_RET_USAGE; | |
249 | ||
250 | printf("## Android Verified Boot 2.0 version %s\n", | |
251 | avb_version_string()); | |
252 | ||
253 | if (avb_ops->read_is_device_unlocked(avb_ops, &unlocked) != | |
254 | AVB_IO_RESULT_OK) { | |
255 | printf("Can't determine device lock state.\n"); | |
256 | return CMD_RET_FAILURE; | |
257 | } | |
258 | ||
259 | slot_result = | |
260 | avb_slot_verify(avb_ops, | |
261 | requested_partitions, | |
262 | "", | |
263 | unlocked, | |
264 | AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, | |
265 | &out_data); | |
266 | ||
267 | switch (slot_result) { | |
268 | case AVB_SLOT_VERIFY_RESULT_OK: | |
5d4fd877 IO |
269 | /* Until we don't have support of changing unlock states, we |
270 | * assume that we are by default in locked state. | |
271 | * So in this case we can boot only when verification is | |
272 | * successful; we also supply in cmdline GREEN boot state | |
273 | */ | |
60b2f9e7 IO |
274 | printf("Verification passed successfully\n"); |
275 | ||
276 | /* export additional bootargs to AVB_BOOTARGS env var */ | |
5d4fd877 IO |
277 | |
278 | extra_args = avb_set_state(avb_ops, AVB_GREEN); | |
279 | if (extra_args) | |
280 | cmdline = append_cmd_line(out_data->cmdline, | |
281 | extra_args); | |
282 | else | |
283 | cmdline = out_data->cmdline; | |
284 | ||
285 | env_set(AVB_BOOTARGS, cmdline); | |
60b2f9e7 IO |
286 | |
287 | res = CMD_RET_SUCCESS; | |
288 | break; | |
289 | case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: | |
290 | printf("Verification failed\n"); | |
291 | break; | |
292 | case AVB_SLOT_VERIFY_RESULT_ERROR_IO: | |
293 | printf("I/O error occurred during verification\n"); | |
294 | break; | |
295 | case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: | |
296 | printf("OOM error occurred during verification\n"); | |
297 | break; | |
298 | case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: | |
299 | printf("Corrupted dm-verity metadata detected\n"); | |
300 | break; | |
301 | case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: | |
302 | printf("Unsupported version avbtool was used\n"); | |
303 | break; | |
304 | case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: | |
305 | printf("Checking rollback index failed\n"); | |
306 | break; | |
307 | case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: | |
308 | printf("Public key was rejected\n"); | |
309 | break; | |
310 | default: | |
311 | printf("Unknown error occurred\n"); | |
312 | } | |
313 | ||
314 | return res; | |
315 | } | |
316 | ||
317 | int do_avb_is_unlocked(cmd_tbl_t *cmdtp, int flag, | |
318 | int argc, char * const argv[]) | |
319 | { | |
320 | bool unlock; | |
321 | ||
322 | if (!avb_ops) { | |
323 | printf("AVB not initialized, run 'avb init' first\n"); | |
324 | return CMD_RET_FAILURE; | |
325 | } | |
326 | ||
327 | if (argc != 1) { | |
328 | printf("--%s(-1)\n", __func__); | |
329 | return CMD_RET_USAGE; | |
330 | } | |
331 | ||
332 | if (avb_ops->read_is_device_unlocked(avb_ops, &unlock) == | |
333 | AVB_IO_RESULT_OK) { | |
334 | printf("Unlocked = %d\n", unlock); | |
335 | return CMD_RET_SUCCESS; | |
336 | } | |
337 | ||
6d89902d JW |
338 | printf("Can't determine device lock state.\n"); |
339 | ||
60b2f9e7 IO |
340 | return CMD_RET_FAILURE; |
341 | } | |
342 | ||
343 | static cmd_tbl_t cmd_avb[] = { | |
344 | U_BOOT_CMD_MKENT(init, 2, 0, do_avb_init, "", ""), | |
345 | U_BOOT_CMD_MKENT(read_rb, 2, 0, do_avb_read_rb, "", ""), | |
346 | U_BOOT_CMD_MKENT(write_rb, 3, 0, do_avb_write_rb, "", ""), | |
347 | U_BOOT_CMD_MKENT(is_unlocked, 1, 0, do_avb_is_unlocked, "", ""), | |
348 | U_BOOT_CMD_MKENT(get_uuid, 2, 0, do_avb_get_uuid, "", ""), | |
349 | U_BOOT_CMD_MKENT(read_part, 5, 0, do_avb_read_part, "", ""), | |
350 | U_BOOT_CMD_MKENT(read_part_hex, 4, 0, do_avb_read_part_hex, "", ""), | |
351 | U_BOOT_CMD_MKENT(write_part, 5, 0, do_avb_write_part, "", ""), | |
352 | U_BOOT_CMD_MKENT(verify, 1, 0, do_avb_verify_part, "", ""), | |
353 | }; | |
354 | ||
355 | static int do_avb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
356 | { | |
357 | cmd_tbl_t *cp; | |
358 | ||
359 | cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb)); | |
360 | ||
361 | argc--; | |
362 | argv++; | |
363 | ||
364 | if (!cp || argc > cp->maxargs) | |
365 | return CMD_RET_USAGE; | |
366 | ||
367 | if (flag == CMD_FLAG_REPEAT) | |
368 | return CMD_RET_FAILURE; | |
369 | ||
370 | return cp->cmd(cmdtp, flag, argc, argv); | |
371 | } | |
372 | ||
373 | U_BOOT_CMD( | |
374 | avb, 29, 0, do_avb, | |
375 | "Provides commands for testing Android Verified Boot 2.0 functionality", | |
376 | "init <dev> - initialize avb2 for <dev>\n" | |
377 | "avb read_rb <num> - read rollback index at location <num>\n" | |
378 | "avb write_rb <num> <rb> - write rollback index <rb> to <num>\n" | |
379 | "avb is_unlocked - returns unlock status of the device\n" | |
380 | "avb get_uuid <partname> - read and print uuid of partition <part>\n" | |
381 | "avb read_part <partname> <offset> <num> <addr> - read <num> bytes from\n" | |
382 | " partition <partname> to buffer <addr>\n" | |
383 | "avb read_part_hex <partname> <offset> <num> - read <num> bytes from\n" | |
384 | " partition <partname> and print to stdout\n" | |
385 | "avb write_part <partname> <offset> <num> <addr> - write <num> bytes to\n" | |
386 | " <partname> by <offset> using data from <addr>\n" | |
387 | "avb verify - run verification process using hash data\n" | |
388 | " from vbmeta structure\n" | |
389 | ); |