]>
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> | |
9fb625ce | 10 | #include <env.h> |
60b2f9e7 IO |
11 | #include <image.h> |
12 | #include <malloc.h> | |
13 | #include <mmc.h> | |
14 | ||
15 | #define AVB_BOOTARGS "avb_bootargs" | |
16 | static struct AvbOps *avb_ops; | |
17 | ||
09140113 | 18 | int do_avb_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
60b2f9e7 IO |
19 | { |
20 | unsigned long mmc_dev; | |
21 | ||
22 | if (argc != 2) | |
23 | return CMD_RET_USAGE; | |
24 | ||
25 | mmc_dev = simple_strtoul(argv[1], NULL, 16); | |
26 | ||
27 | if (avb_ops) | |
28 | avb_ops_free(avb_ops); | |
29 | ||
30 | avb_ops = avb_ops_alloc(mmc_dev); | |
31 | if (avb_ops) | |
32 | return CMD_RET_SUCCESS; | |
33 | ||
6d89902d JW |
34 | printf("Failed to initialize avb2\n"); |
35 | ||
60b2f9e7 IO |
36 | return CMD_RET_FAILURE; |
37 | } | |
38 | ||
09140113 SG |
39 | int do_avb_read_part(struct cmd_tbl *cmdtp, int flag, int argc, |
40 | char *const argv[]) | |
60b2f9e7 IO |
41 | { |
42 | const char *part; | |
43 | s64 offset; | |
44 | size_t bytes, bytes_read = 0; | |
45 | void *buffer; | |
46 | ||
47 | if (!avb_ops) { | |
48 | printf("AVB 2.0 is not initialized, please run 'avb init'\n"); | |
49 | return CMD_RET_USAGE; | |
50 | } | |
51 | ||
52 | if (argc != 5) | |
53 | return CMD_RET_USAGE; | |
54 | ||
55 | part = argv[1]; | |
56 | offset = simple_strtoul(argv[2], NULL, 16); | |
57 | bytes = simple_strtoul(argv[3], NULL, 16); | |
58 | buffer = (void *)simple_strtoul(argv[4], NULL, 16); | |
59 | ||
60 | if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, | |
61 | buffer, &bytes_read) == | |
62 | AVB_IO_RESULT_OK) { | |
63 | printf("Read %zu bytes\n", bytes_read); | |
64 | return CMD_RET_SUCCESS; | |
65 | } | |
66 | ||
6d89902d JW |
67 | printf("Failed to read from partition\n"); |
68 | ||
60b2f9e7 IO |
69 | return CMD_RET_FAILURE; |
70 | } | |
71 | ||
09140113 | 72 | int do_avb_read_part_hex(struct cmd_tbl *cmdtp, int flag, int argc, |
60b2f9e7 IO |
73 | char *const argv[]) |
74 | { | |
75 | const char *part; | |
76 | s64 offset; | |
77 | size_t bytes, bytes_read = 0; | |
78 | char *buffer; | |
79 | ||
80 | if (!avb_ops) { | |
81 | printf("AVB 2.0 is not initialized, please run 'avb init'\n"); | |
82 | return CMD_RET_USAGE; | |
83 | } | |
84 | ||
85 | if (argc != 4) | |
86 | return CMD_RET_USAGE; | |
87 | ||
88 | part = argv[1]; | |
89 | offset = simple_strtoul(argv[2], NULL, 16); | |
90 | bytes = simple_strtoul(argv[3], NULL, 16); | |
91 | ||
92 | buffer = malloc(bytes); | |
93 | if (!buffer) { | |
94 | printf("Failed to tlb_allocate buffer for data\n"); | |
95 | return CMD_RET_FAILURE; | |
96 | } | |
97 | memset(buffer, 0, bytes); | |
98 | ||
99 | if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, buffer, | |
100 | &bytes_read) == AVB_IO_RESULT_OK) { | |
101 | printf("Requested %zu, read %zu bytes\n", bytes, bytes_read); | |
102 | printf("Data: "); | |
103 | for (int i = 0; i < bytes_read; i++) | |
104 | printf("%02X", buffer[i]); | |
105 | ||
106 | printf("\n"); | |
107 | ||
108 | free(buffer); | |
109 | return CMD_RET_SUCCESS; | |
110 | } | |
111 | ||
6d89902d JW |
112 | printf("Failed to read from partition\n"); |
113 | ||
60b2f9e7 IO |
114 | free(buffer); |
115 | return CMD_RET_FAILURE; | |
116 | } | |
117 | ||
09140113 SG |
118 | int do_avb_write_part(struct cmd_tbl *cmdtp, int flag, int argc, |
119 | char *const argv[]) | |
60b2f9e7 IO |
120 | { |
121 | const char *part; | |
122 | s64 offset; | |
123 | size_t bytes; | |
124 | void *buffer; | |
125 | ||
126 | if (!avb_ops) { | |
127 | printf("AVB 2.0 is not initialized, run 'avb init' first\n"); | |
128 | return CMD_RET_FAILURE; | |
129 | } | |
130 | ||
131 | if (argc != 5) | |
132 | return CMD_RET_USAGE; | |
133 | ||
134 | part = argv[1]; | |
135 | offset = simple_strtoul(argv[2], NULL, 16); | |
136 | bytes = simple_strtoul(argv[3], NULL, 16); | |
137 | buffer = (void *)simple_strtoul(argv[4], NULL, 16); | |
138 | ||
139 | if (avb_ops->write_to_partition(avb_ops, part, offset, bytes, buffer) == | |
140 | AVB_IO_RESULT_OK) { | |
141 | printf("Wrote %zu bytes\n", bytes); | |
142 | return CMD_RET_SUCCESS; | |
143 | } | |
144 | ||
6d89902d JW |
145 | printf("Failed to write in partition\n"); |
146 | ||
60b2f9e7 IO |
147 | return CMD_RET_FAILURE; |
148 | } | |
149 | ||
09140113 SG |
150 | int do_avb_read_rb(struct cmd_tbl *cmdtp, int flag, int argc, |
151 | char *const argv[]) | |
60b2f9e7 IO |
152 | { |
153 | size_t index; | |
154 | u64 rb_idx; | |
155 | ||
156 | if (!avb_ops) { | |
157 | printf("AVB 2.0 is not initialized, run 'avb init' first\n"); | |
158 | return CMD_RET_FAILURE; | |
159 | } | |
160 | ||
161 | if (argc != 2) | |
162 | return CMD_RET_USAGE; | |
163 | ||
164 | index = (size_t)simple_strtoul(argv[1], NULL, 16); | |
165 | ||
166 | if (avb_ops->read_rollback_index(avb_ops, index, &rb_idx) == | |
167 | AVB_IO_RESULT_OK) { | |
ab2d7382 | 168 | printf("Rollback index: %llx\n", rb_idx); |
60b2f9e7 IO |
169 | return CMD_RET_SUCCESS; |
170 | } | |
6d89902d JW |
171 | |
172 | printf("Failed to read rollback index\n"); | |
173 | ||
60b2f9e7 IO |
174 | return CMD_RET_FAILURE; |
175 | } | |
176 | ||
09140113 SG |
177 | int do_avb_write_rb(struct cmd_tbl *cmdtp, int flag, int argc, |
178 | char *const argv[]) | |
60b2f9e7 IO |
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 | ||
09140113 SG |
203 | int do_avb_get_uuid(struct cmd_tbl *cmdtp, int flag, |
204 | int argc, char *const argv[]) | |
60b2f9e7 IO |
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 | ||
09140113 | 231 | int do_avb_verify_part(struct cmd_tbl *cmdtp, int flag, |
60b2f9e7 IO |
232 | int argc, char *const argv[]) |
233 | { | |
bb43c278 | 234 | const char * const requested_partitions[] = {"boot", NULL}; |
60b2f9e7 IO |
235 | AvbSlotVerifyResult slot_result; |
236 | AvbSlotVerifyData *out_data; | |
5d4fd877 IO |
237 | char *cmdline; |
238 | char *extra_args; | |
965ec3ca | 239 | char *slot_suffix = ""; |
60b2f9e7 IO |
240 | |
241 | bool unlocked = false; | |
242 | int res = CMD_RET_FAILURE; | |
243 | ||
244 | if (!avb_ops) { | |
245 | printf("AVB 2.0 is not initialized, run 'avb init' first\n"); | |
246 | return CMD_RET_FAILURE; | |
247 | } | |
248 | ||
965ec3ca | 249 | if (argc < 1 || argc > 2) |
60b2f9e7 IO |
250 | return CMD_RET_USAGE; |
251 | ||
965ec3ca SP |
252 | if (argc == 2) |
253 | slot_suffix = argv[1]; | |
254 | ||
60b2f9e7 IO |
255 | printf("## Android Verified Boot 2.0 version %s\n", |
256 | avb_version_string()); | |
257 | ||
258 | if (avb_ops->read_is_device_unlocked(avb_ops, &unlocked) != | |
259 | AVB_IO_RESULT_OK) { | |
260 | printf("Can't determine device lock state.\n"); | |
261 | return CMD_RET_FAILURE; | |
262 | } | |
263 | ||
264 | slot_result = | |
265 | avb_slot_verify(avb_ops, | |
266 | requested_partitions, | |
965ec3ca | 267 | slot_suffix, |
60b2f9e7 IO |
268 | unlocked, |
269 | AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, | |
270 | &out_data); | |
271 | ||
272 | switch (slot_result) { | |
273 | case AVB_SLOT_VERIFY_RESULT_OK: | |
5d4fd877 IO |
274 | /* Until we don't have support of changing unlock states, we |
275 | * assume that we are by default in locked state. | |
276 | * So in this case we can boot only when verification is | |
277 | * successful; we also supply in cmdline GREEN boot state | |
278 | */ | |
60b2f9e7 IO |
279 | printf("Verification passed successfully\n"); |
280 | ||
281 | /* export additional bootargs to AVB_BOOTARGS env var */ | |
5d4fd877 IO |
282 | |
283 | extra_args = avb_set_state(avb_ops, AVB_GREEN); | |
284 | if (extra_args) | |
285 | cmdline = append_cmd_line(out_data->cmdline, | |
286 | extra_args); | |
287 | else | |
288 | cmdline = out_data->cmdline; | |
289 | ||
290 | env_set(AVB_BOOTARGS, cmdline); | |
60b2f9e7 IO |
291 | |
292 | res = CMD_RET_SUCCESS; | |
293 | break; | |
294 | case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: | |
295 | printf("Verification failed\n"); | |
296 | break; | |
297 | case AVB_SLOT_VERIFY_RESULT_ERROR_IO: | |
298 | printf("I/O error occurred during verification\n"); | |
299 | break; | |
300 | case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: | |
301 | printf("OOM error occurred during verification\n"); | |
302 | break; | |
303 | case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: | |
304 | printf("Corrupted dm-verity metadata detected\n"); | |
305 | break; | |
306 | case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: | |
307 | printf("Unsupported version avbtool was used\n"); | |
308 | break; | |
309 | case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: | |
310 | printf("Checking rollback index failed\n"); | |
311 | break; | |
312 | case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: | |
313 | printf("Public key was rejected\n"); | |
314 | break; | |
315 | default: | |
316 | printf("Unknown error occurred\n"); | |
317 | } | |
318 | ||
319 | return res; | |
320 | } | |
321 | ||
09140113 SG |
322 | int do_avb_is_unlocked(struct cmd_tbl *cmdtp, int flag, |
323 | int argc, char *const argv[]) | |
60b2f9e7 IO |
324 | { |
325 | bool unlock; | |
326 | ||
327 | if (!avb_ops) { | |
328 | printf("AVB not initialized, run 'avb init' first\n"); | |
329 | return CMD_RET_FAILURE; | |
330 | } | |
331 | ||
332 | if (argc != 1) { | |
333 | printf("--%s(-1)\n", __func__); | |
334 | return CMD_RET_USAGE; | |
335 | } | |
336 | ||
337 | if (avb_ops->read_is_device_unlocked(avb_ops, &unlock) == | |
338 | AVB_IO_RESULT_OK) { | |
339 | printf("Unlocked = %d\n", unlock); | |
340 | return CMD_RET_SUCCESS; | |
341 | } | |
342 | ||
6d89902d JW |
343 | printf("Can't determine device lock state.\n"); |
344 | ||
60b2f9e7 IO |
345 | return CMD_RET_FAILURE; |
346 | } | |
347 | ||
09140113 SG |
348 | int do_avb_read_pvalue(struct cmd_tbl *cmdtp, int flag, int argc, |
349 | char *const argv[]) | |
fc1fe01b IO |
350 | { |
351 | const char *name; | |
352 | size_t bytes; | |
353 | size_t bytes_read; | |
354 | void *buffer; | |
355 | char *endp; | |
356 | ||
357 | if (!avb_ops) { | |
358 | printf("AVB 2.0 is not initialized, run 'avb init' first\n"); | |
359 | return CMD_RET_FAILURE; | |
360 | } | |
361 | ||
362 | if (argc != 3) | |
363 | return CMD_RET_USAGE; | |
364 | ||
365 | name = argv[1]; | |
366 | bytes = simple_strtoul(argv[2], &endp, 10); | |
367 | if (*endp && *endp != '\n') | |
368 | return CMD_RET_USAGE; | |
369 | ||
370 | buffer = malloc(bytes); | |
371 | if (!buffer) | |
372 | return CMD_RET_FAILURE; | |
373 | ||
374 | if (avb_ops->read_persistent_value(avb_ops, name, bytes, buffer, | |
375 | &bytes_read) == AVB_IO_RESULT_OK) { | |
97f3c097 | 376 | printf("Read %zu bytes, value = %s\n", bytes_read, |
fc1fe01b IO |
377 | (char *)buffer); |
378 | free(buffer); | |
379 | return CMD_RET_SUCCESS; | |
380 | } | |
381 | ||
382 | printf("Failed to read persistent value\n"); | |
383 | ||
384 | free(buffer); | |
385 | ||
386 | return CMD_RET_FAILURE; | |
387 | } | |
388 | ||
09140113 SG |
389 | int do_avb_write_pvalue(struct cmd_tbl *cmdtp, int flag, int argc, |
390 | char *const argv[]) | |
fc1fe01b IO |
391 | { |
392 | const char *name; | |
393 | const char *value; | |
394 | ||
395 | if (!avb_ops) { | |
396 | printf("AVB 2.0 is not initialized, run 'avb init' first\n"); | |
397 | return CMD_RET_FAILURE; | |
398 | } | |
399 | ||
400 | if (argc != 3) | |
401 | return CMD_RET_USAGE; | |
402 | ||
403 | name = argv[1]; | |
404 | value = argv[2]; | |
405 | ||
406 | if (avb_ops->write_persistent_value(avb_ops, name, strlen(value) + 1, | |
407 | (const uint8_t *)value) == | |
408 | AVB_IO_RESULT_OK) { | |
97f3c097 | 409 | printf("Wrote %zu bytes\n", strlen(value) + 1); |
fc1fe01b IO |
410 | return CMD_RET_SUCCESS; |
411 | } | |
412 | ||
413 | printf("Failed to write persistent value\n"); | |
414 | ||
415 | return CMD_RET_FAILURE; | |
416 | } | |
417 | ||
09140113 | 418 | static struct cmd_tbl cmd_avb[] = { |
60b2f9e7 IO |
419 | U_BOOT_CMD_MKENT(init, 2, 0, do_avb_init, "", ""), |
420 | U_BOOT_CMD_MKENT(read_rb, 2, 0, do_avb_read_rb, "", ""), | |
421 | U_BOOT_CMD_MKENT(write_rb, 3, 0, do_avb_write_rb, "", ""), | |
422 | U_BOOT_CMD_MKENT(is_unlocked, 1, 0, do_avb_is_unlocked, "", ""), | |
423 | U_BOOT_CMD_MKENT(get_uuid, 2, 0, do_avb_get_uuid, "", ""), | |
424 | U_BOOT_CMD_MKENT(read_part, 5, 0, do_avb_read_part, "", ""), | |
425 | U_BOOT_CMD_MKENT(read_part_hex, 4, 0, do_avb_read_part_hex, "", ""), | |
426 | U_BOOT_CMD_MKENT(write_part, 5, 0, do_avb_write_part, "", ""), | |
965ec3ca | 427 | U_BOOT_CMD_MKENT(verify, 2, 0, do_avb_verify_part, "", ""), |
fc1fe01b IO |
428 | #ifdef CONFIG_OPTEE_TA_AVB |
429 | U_BOOT_CMD_MKENT(read_pvalue, 3, 0, do_avb_read_pvalue, "", ""), | |
430 | U_BOOT_CMD_MKENT(write_pvalue, 3, 0, do_avb_write_pvalue, "", ""), | |
431 | #endif | |
60b2f9e7 IO |
432 | }; |
433 | ||
09140113 | 434 | static int do_avb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
60b2f9e7 | 435 | { |
09140113 | 436 | struct cmd_tbl *cp; |
60b2f9e7 IO |
437 | |
438 | cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb)); | |
439 | ||
440 | argc--; | |
441 | argv++; | |
442 | ||
443 | if (!cp || argc > cp->maxargs) | |
444 | return CMD_RET_USAGE; | |
445 | ||
446 | if (flag == CMD_FLAG_REPEAT) | |
447 | return CMD_RET_FAILURE; | |
448 | ||
449 | return cp->cmd(cmdtp, flag, argc, argv); | |
450 | } | |
451 | ||
452 | U_BOOT_CMD( | |
453 | avb, 29, 0, do_avb, | |
454 | "Provides commands for testing Android Verified Boot 2.0 functionality", | |
455 | "init <dev> - initialize avb2 for <dev>\n" | |
456 | "avb read_rb <num> - read rollback index at location <num>\n" | |
457 | "avb write_rb <num> <rb> - write rollback index <rb> to <num>\n" | |
458 | "avb is_unlocked - returns unlock status of the device\n" | |
459 | "avb get_uuid <partname> - read and print uuid of partition <part>\n" | |
460 | "avb read_part <partname> <offset> <num> <addr> - read <num> bytes from\n" | |
461 | " partition <partname> to buffer <addr>\n" | |
462 | "avb read_part_hex <partname> <offset> <num> - read <num> bytes from\n" | |
463 | " partition <partname> and print to stdout\n" | |
464 | "avb write_part <partname> <offset> <num> <addr> - write <num> bytes to\n" | |
465 | " <partname> by <offset> using data from <addr>\n" | |
fc1fe01b IO |
466 | #ifdef CONFIG_OPTEE_TA_AVB |
467 | "avb read_pvalue <name> <bytes> - read a persistent value <name>\n" | |
468 | "avb write_pvalue <name> <value> - write a persistent value <name>\n" | |
469 | #endif | |
965ec3ca | 470 | "avb verify [slot_suffix] - run verification process using hash data\n" |
60b2f9e7 | 471 | " from vbmeta structure\n" |
965ec3ca | 472 | " [slot_suffix] - _a, _b, etc (if vbmeta partition is slotted)\n" |
60b2f9e7 | 473 | ); |