]>
Commit | Line | Data |
---|---|---|
a14aa59e | 1 | // SPDX-License-Identifier: GPL-2.0+ |
60b2f9e7 IO |
2 | /* |
3 | * (C) Copyright 2018, Linaro Limited | |
60b2f9e7 IO |
4 | */ |
5 | ||
6 | #include <avb_verify.h> | |
7 | #include <command.h> | |
9fb625ce | 8 | #include <env.h> |
60b2f9e7 IO |
9 | #include <image.h> |
10 | #include <malloc.h> | |
11 | #include <mmc.h> | |
12 | ||
13 | #define AVB_BOOTARGS "avb_bootargs" | |
0ef0825a | 14 | |
60b2f9e7 IO |
15 | static struct AvbOps *avb_ops; |
16 | ||
09140113 | 17 | int do_avb_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
60b2f9e7 IO |
18 | { |
19 | unsigned long mmc_dev; | |
20 | ||
21 | if (argc != 2) | |
22 | return CMD_RET_USAGE; | |
23 | ||
7e5f460e | 24 | mmc_dev = hextoul(argv[1], NULL); |
60b2f9e7 IO |
25 | |
26 | if (avb_ops) | |
27 | avb_ops_free(avb_ops); | |
28 | ||
29 | avb_ops = avb_ops_alloc(mmc_dev); | |
30 | if (avb_ops) | |
31 | return CMD_RET_SUCCESS; | |
0ef0825a IO |
32 | else |
33 | printf("Can't allocate AvbOps"); | |
60b2f9e7 | 34 | |
0ef0825a | 35 | printf("Failed to initialize AVB\n"); |
6d89902d | 36 | |
60b2f9e7 IO |
37 | return CMD_RET_FAILURE; |
38 | } | |
39 | ||
09140113 SG |
40 | int do_avb_read_part(struct cmd_tbl *cmdtp, int flag, int argc, |
41 | char *const argv[]) | |
60b2f9e7 IO |
42 | { |
43 | const char *part; | |
44 | s64 offset; | |
45 | size_t bytes, bytes_read = 0; | |
46 | void *buffer; | |
0ef0825a | 47 | int ret; |
60b2f9e7 IO |
48 | |
49 | if (!avb_ops) { | |
0ef0825a IO |
50 | printf("AVB is not initialized, please run 'avb init <id>'\n"); |
51 | return CMD_RET_FAILURE; | |
60b2f9e7 IO |
52 | } |
53 | ||
54 | if (argc != 5) | |
55 | return CMD_RET_USAGE; | |
56 | ||
57 | part = argv[1]; | |
7e5f460e SG |
58 | offset = hextoul(argv[2], NULL); |
59 | bytes = hextoul(argv[3], NULL); | |
60 | buffer = (void *)hextoul(argv[4], NULL); | |
60b2f9e7 | 61 | |
0ef0825a IO |
62 | ret = avb_ops->read_from_partition(avb_ops, part, offset, |
63 | bytes, buffer, &bytes_read); | |
64 | if (ret == AVB_IO_RESULT_OK) { | |
60b2f9e7 IO |
65 | printf("Read %zu bytes\n", bytes_read); |
66 | return CMD_RET_SUCCESS; | |
67 | } | |
68 | ||
0ef0825a IO |
69 | printf("Failed to read from partition '%s', err = %d\n", |
70 | part, ret); | |
6d89902d | 71 | |
60b2f9e7 IO |
72 | return CMD_RET_FAILURE; |
73 | } | |
74 | ||
09140113 | 75 | int do_avb_read_part_hex(struct cmd_tbl *cmdtp, int flag, int argc, |
60b2f9e7 IO |
76 | char *const argv[]) |
77 | { | |
78 | const char *part; | |
79 | s64 offset; | |
80 | size_t bytes, bytes_read = 0; | |
81 | char *buffer; | |
0ef0825a | 82 | int ret; |
60b2f9e7 IO |
83 | |
84 | if (!avb_ops) { | |
0ef0825a IO |
85 | printf("AVB is not initialized, please run 'avb init <id>'\n"); |
86 | return CMD_RET_FAILURE; | |
60b2f9e7 IO |
87 | } |
88 | ||
89 | if (argc != 4) | |
90 | return CMD_RET_USAGE; | |
91 | ||
92 | part = argv[1]; | |
7e5f460e SG |
93 | offset = hextoul(argv[2], NULL); |
94 | bytes = hextoul(argv[3], NULL); | |
60b2f9e7 IO |
95 | |
96 | buffer = malloc(bytes); | |
97 | if (!buffer) { | |
98 | printf("Failed to tlb_allocate buffer for data\n"); | |
99 | return CMD_RET_FAILURE; | |
100 | } | |
101 | memset(buffer, 0, bytes); | |
102 | ||
0ef0825a IO |
103 | ret = avb_ops->read_from_partition(avb_ops, part, offset, |
104 | bytes, buffer, &bytes_read); | |
105 | if (ret == AVB_IO_RESULT_OK) { | |
60b2f9e7 IO |
106 | printf("Requested %zu, read %zu bytes\n", bytes, bytes_read); |
107 | printf("Data: "); | |
108 | for (int i = 0; i < bytes_read; i++) | |
109 | printf("%02X", buffer[i]); | |
110 | ||
111 | printf("\n"); | |
112 | ||
113 | free(buffer); | |
114 | return CMD_RET_SUCCESS; | |
115 | } | |
116 | ||
0ef0825a IO |
117 | printf("Failed to read from partition '%s', err = %d\n", |
118 | part, ret); | |
6d89902d | 119 | |
60b2f9e7 IO |
120 | free(buffer); |
121 | return CMD_RET_FAILURE; | |
122 | } | |
123 | ||
09140113 SG |
124 | int do_avb_write_part(struct cmd_tbl *cmdtp, int flag, int argc, |
125 | char *const argv[]) | |
60b2f9e7 IO |
126 | { |
127 | const char *part; | |
128 | s64 offset; | |
129 | size_t bytes; | |
130 | void *buffer; | |
0ef0825a | 131 | int ret; |
60b2f9e7 IO |
132 | |
133 | if (!avb_ops) { | |
0ef0825a | 134 | printf("AVB is not initialized, please run 'avb init <id>'\n"); |
60b2f9e7 IO |
135 | return CMD_RET_FAILURE; |
136 | } | |
137 | ||
138 | if (argc != 5) | |
139 | return CMD_RET_USAGE; | |
140 | ||
141 | part = argv[1]; | |
7e5f460e SG |
142 | offset = hextoul(argv[2], NULL); |
143 | bytes = hextoul(argv[3], NULL); | |
144 | buffer = (void *)hextoul(argv[4], NULL); | |
60b2f9e7 | 145 | |
0ef0825a IO |
146 | ret = avb_ops->write_to_partition(avb_ops, part, offset, |
147 | bytes, buffer); | |
148 | if (ret == AVB_IO_RESULT_OK) { | |
60b2f9e7 IO |
149 | printf("Wrote %zu bytes\n", bytes); |
150 | return CMD_RET_SUCCESS; | |
151 | } | |
152 | ||
0ef0825a IO |
153 | printf("Failed to write in partition '%s', err = %d\n", |
154 | part, ret); | |
6d89902d | 155 | |
60b2f9e7 IO |
156 | return CMD_RET_FAILURE; |
157 | } | |
158 | ||
09140113 SG |
159 | int do_avb_read_rb(struct cmd_tbl *cmdtp, int flag, int argc, |
160 | char *const argv[]) | |
60b2f9e7 IO |
161 | { |
162 | size_t index; | |
163 | u64 rb_idx; | |
0ef0825a | 164 | int ret; |
60b2f9e7 IO |
165 | |
166 | if (!avb_ops) { | |
0ef0825a | 167 | printf("AVB is not initialized, please run 'avb init <id>'\n"); |
60b2f9e7 IO |
168 | return CMD_RET_FAILURE; |
169 | } | |
170 | ||
171 | if (argc != 2) | |
172 | return CMD_RET_USAGE; | |
173 | ||
7e5f460e | 174 | index = (size_t)hextoul(argv[1], NULL); |
60b2f9e7 | 175 | |
0ef0825a IO |
176 | ret = avb_ops->read_rollback_index(avb_ops, index, &rb_idx); |
177 | if (ret == AVB_IO_RESULT_OK) { | |
ab2d7382 | 178 | printf("Rollback index: %llx\n", rb_idx); |
60b2f9e7 IO |
179 | return CMD_RET_SUCCESS; |
180 | } | |
6d89902d | 181 | |
0ef0825a IO |
182 | printf("Failed to read rollback index id = %zu, err = %d\n", |
183 | index, ret); | |
6d89902d | 184 | |
60b2f9e7 IO |
185 | return CMD_RET_FAILURE; |
186 | } | |
187 | ||
09140113 SG |
188 | int do_avb_write_rb(struct cmd_tbl *cmdtp, int flag, int argc, |
189 | char *const argv[]) | |
60b2f9e7 IO |
190 | { |
191 | size_t index; | |
192 | u64 rb_idx; | |
0ef0825a | 193 | int ret; |
60b2f9e7 IO |
194 | |
195 | if (!avb_ops) { | |
0ef0825a | 196 | printf("AVB is not initialized, please run 'avb init <id>'\n"); |
60b2f9e7 IO |
197 | return CMD_RET_FAILURE; |
198 | } | |
199 | ||
200 | if (argc != 3) | |
201 | return CMD_RET_USAGE; | |
202 | ||
7e5f460e SG |
203 | index = (size_t)hextoul(argv[1], NULL); |
204 | rb_idx = hextoul(argv[2], NULL); | |
60b2f9e7 | 205 | |
0ef0825a IO |
206 | ret = avb_ops->write_rollback_index(avb_ops, index, rb_idx); |
207 | if (ret == AVB_IO_RESULT_OK) | |
60b2f9e7 IO |
208 | return CMD_RET_SUCCESS; |
209 | ||
0ef0825a IO |
210 | printf("Failed to write rollback index id = %zu, err = %d\n", |
211 | index, ret); | |
6d89902d | 212 | |
60b2f9e7 IO |
213 | return CMD_RET_FAILURE; |
214 | } | |
215 | ||
09140113 SG |
216 | int do_avb_get_uuid(struct cmd_tbl *cmdtp, int flag, |
217 | int argc, char *const argv[]) | |
60b2f9e7 IO |
218 | { |
219 | const char *part; | |
220 | char buffer[UUID_STR_LEN + 1]; | |
0ef0825a | 221 | int ret; |
60b2f9e7 IO |
222 | |
223 | if (!avb_ops) { | |
0ef0825a | 224 | printf("AVB is not initialized, please run 'avb init <id>'\n"); |
60b2f9e7 IO |
225 | return CMD_RET_FAILURE; |
226 | } | |
227 | ||
228 | if (argc != 2) | |
229 | return CMD_RET_USAGE; | |
230 | ||
231 | part = argv[1]; | |
232 | ||
0ef0825a IO |
233 | ret = avb_ops->get_unique_guid_for_partition(avb_ops, part, |
234 | buffer, | |
235 | UUID_STR_LEN + 1); | |
236 | if (ret == AVB_IO_RESULT_OK) { | |
60b2f9e7 IO |
237 | printf("'%s' UUID: %s\n", part, buffer); |
238 | return CMD_RET_SUCCESS; | |
239 | } | |
240 | ||
0ef0825a IO |
241 | printf("Failed to read partition '%s' UUID, err = %d\n", |
242 | part, ret); | |
6d89902d | 243 | |
60b2f9e7 IO |
244 | return CMD_RET_FAILURE; |
245 | } | |
246 | ||
09140113 | 247 | int do_avb_verify_part(struct cmd_tbl *cmdtp, int flag, |
60b2f9e7 IO |
248 | int argc, char *const argv[]) |
249 | { | |
bb43c278 | 250 | const char * const requested_partitions[] = {"boot", NULL}; |
60b2f9e7 IO |
251 | AvbSlotVerifyResult slot_result; |
252 | AvbSlotVerifyData *out_data; | |
df3cfcee | 253 | enum avb_boot_state boot_state; |
5d4fd877 IO |
254 | char *cmdline; |
255 | char *extra_args; | |
965ec3ca | 256 | char *slot_suffix = ""; |
0ef0825a | 257 | int ret; |
60b2f9e7 IO |
258 | |
259 | bool unlocked = false; | |
260 | int res = CMD_RET_FAILURE; | |
261 | ||
262 | if (!avb_ops) { | |
0ef0825a | 263 | printf("AVB is not initialized, please run 'avb init <id>'\n"); |
60b2f9e7 IO |
264 | return CMD_RET_FAILURE; |
265 | } | |
266 | ||
965ec3ca | 267 | if (argc < 1 || argc > 2) |
60b2f9e7 IO |
268 | return CMD_RET_USAGE; |
269 | ||
965ec3ca SP |
270 | if (argc == 2) |
271 | slot_suffix = argv[1]; | |
272 | ||
60b2f9e7 IO |
273 | printf("## Android Verified Boot 2.0 version %s\n", |
274 | avb_version_string()); | |
275 | ||
0ef0825a IO |
276 | ret = avb_ops->read_is_device_unlocked(avb_ops, &unlocked); |
277 | if (ret != AVB_IO_RESULT_OK) { | |
278 | printf("Can't determine device lock state, err = %d\n", | |
279 | ret); | |
60b2f9e7 IO |
280 | return CMD_RET_FAILURE; |
281 | } | |
282 | ||
283 | slot_result = | |
284 | avb_slot_verify(avb_ops, | |
285 | requested_partitions, | |
965ec3ca | 286 | slot_suffix, |
60b2f9e7 IO |
287 | unlocked, |
288 | AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, | |
289 | &out_data); | |
290 | ||
df3cfcee IO |
291 | /* |
292 | * LOCKED devices with custom root of trust setup is not supported (YELLOW) | |
293 | */ | |
294 | if (slot_result == AVB_SLOT_VERIFY_RESULT_OK) { | |
60b2f9e7 IO |
295 | printf("Verification passed successfully\n"); |
296 | ||
df3cfcee IO |
297 | /* |
298 | * ORANGE state indicates that device may be freely modified. | |
299 | * Device integrity is left to the user to verify out-of-band. | |
300 | */ | |
301 | if (unlocked) | |
302 | boot_state = AVB_ORANGE; | |
303 | else | |
304 | boot_state = AVB_GREEN; | |
5d4fd877 | 305 | |
df3cfcee IO |
306 | /* export boot state to AVB_BOOTARGS env var */ |
307 | extra_args = avb_set_state(avb_ops, boot_state); | |
5d4fd877 IO |
308 | if (extra_args) |
309 | cmdline = append_cmd_line(out_data->cmdline, | |
310 | extra_args); | |
311 | else | |
312 | cmdline = out_data->cmdline; | |
313 | ||
314 | env_set(AVB_BOOTARGS, cmdline); | |
60b2f9e7 IO |
315 | |
316 | res = CMD_RET_SUCCESS; | |
df3cfcee IO |
317 | } else { |
318 | printf("Verification failed, reason: %s\n", str_avb_slot_error(slot_result)); | |
60b2f9e7 IO |
319 | } |
320 | ||
b09e1b61 GB |
321 | if (out_data) |
322 | avb_slot_verify_data_free(out_data); | |
323 | ||
60b2f9e7 IO |
324 | return res; |
325 | } | |
326 | ||
09140113 SG |
327 | int do_avb_is_unlocked(struct cmd_tbl *cmdtp, int flag, |
328 | int argc, char *const argv[]) | |
60b2f9e7 IO |
329 | { |
330 | bool unlock; | |
0ef0825a | 331 | int ret; |
60b2f9e7 IO |
332 | |
333 | if (!avb_ops) { | |
0ef0825a | 334 | printf("AVB is not initialized, please run 'avb init <id>'\n"); |
60b2f9e7 IO |
335 | return CMD_RET_FAILURE; |
336 | } | |
337 | ||
338 | if (argc != 1) { | |
339 | printf("--%s(-1)\n", __func__); | |
340 | return CMD_RET_USAGE; | |
341 | } | |
342 | ||
0ef0825a IO |
343 | ret = avb_ops->read_is_device_unlocked(avb_ops, &unlock); |
344 | if (ret == AVB_IO_RESULT_OK) { | |
60b2f9e7 IO |
345 | printf("Unlocked = %d\n", unlock); |
346 | return CMD_RET_SUCCESS; | |
347 | } | |
348 | ||
0ef0825a IO |
349 | printf("Can't determine device lock state, err = %d\n", |
350 | ret); | |
6d89902d | 351 | |
60b2f9e7 IO |
352 | return CMD_RET_FAILURE; |
353 | } | |
354 | ||
09140113 SG |
355 | int do_avb_read_pvalue(struct cmd_tbl *cmdtp, int flag, int argc, |
356 | char *const argv[]) | |
fc1fe01b IO |
357 | { |
358 | const char *name; | |
359 | size_t bytes; | |
360 | size_t bytes_read; | |
361 | void *buffer; | |
362 | char *endp; | |
0ef0825a | 363 | int ret; |
fc1fe01b IO |
364 | |
365 | if (!avb_ops) { | |
0ef0825a | 366 | printf("AVB is not initialized, please run 'avb init <id>'\n"); |
fc1fe01b IO |
367 | return CMD_RET_FAILURE; |
368 | } | |
369 | ||
370 | if (argc != 3) | |
371 | return CMD_RET_USAGE; | |
372 | ||
373 | name = argv[1]; | |
0b1284eb | 374 | bytes = dectoul(argv[2], &endp); |
fc1fe01b IO |
375 | if (*endp && *endp != '\n') |
376 | return CMD_RET_USAGE; | |
377 | ||
378 | buffer = malloc(bytes); | |
379 | if (!buffer) | |
380 | return CMD_RET_FAILURE; | |
381 | ||
0ef0825a IO |
382 | ret = avb_ops->read_persistent_value(avb_ops, name, bytes, |
383 | buffer, &bytes_read); | |
384 | if (ret == AVB_IO_RESULT_OK) { | |
97f3c097 | 385 | printf("Read %zu bytes, value = %s\n", bytes_read, |
fc1fe01b IO |
386 | (char *)buffer); |
387 | free(buffer); | |
388 | return CMD_RET_SUCCESS; | |
389 | } | |
390 | ||
0ef0825a | 391 | printf("Failed to read persistent value, err = %d\n", ret); |
fc1fe01b IO |
392 | |
393 | free(buffer); | |
394 | ||
395 | return CMD_RET_FAILURE; | |
396 | } | |
397 | ||
09140113 SG |
398 | int do_avb_write_pvalue(struct cmd_tbl *cmdtp, int flag, int argc, |
399 | char *const argv[]) | |
fc1fe01b IO |
400 | { |
401 | const char *name; | |
402 | const char *value; | |
0ef0825a | 403 | int ret; |
fc1fe01b IO |
404 | |
405 | if (!avb_ops) { | |
0ef0825a | 406 | printf("AVB is not initialized, please run 'avb init <id>'\n"); |
fc1fe01b IO |
407 | return CMD_RET_FAILURE; |
408 | } | |
409 | ||
410 | if (argc != 3) | |
411 | return CMD_RET_USAGE; | |
412 | ||
413 | name = argv[1]; | |
414 | value = argv[2]; | |
415 | ||
0ef0825a IO |
416 | ret = avb_ops->write_persistent_value(avb_ops, name, |
417 | strlen(value) + 1, | |
418 | (const uint8_t *)value); | |
419 | if (ret == AVB_IO_RESULT_OK) { | |
97f3c097 | 420 | printf("Wrote %zu bytes\n", strlen(value) + 1); |
fc1fe01b IO |
421 | return CMD_RET_SUCCESS; |
422 | } | |
423 | ||
0ef0825a IO |
424 | printf("Failed to write persistent value `%s` = `%s`, err = %d\n", |
425 | name, value, ret); | |
fc1fe01b IO |
426 | |
427 | return CMD_RET_FAILURE; | |
428 | } | |
429 | ||
09140113 | 430 | static struct cmd_tbl cmd_avb[] = { |
60b2f9e7 IO |
431 | U_BOOT_CMD_MKENT(init, 2, 0, do_avb_init, "", ""), |
432 | U_BOOT_CMD_MKENT(read_rb, 2, 0, do_avb_read_rb, "", ""), | |
433 | U_BOOT_CMD_MKENT(write_rb, 3, 0, do_avb_write_rb, "", ""), | |
434 | U_BOOT_CMD_MKENT(is_unlocked, 1, 0, do_avb_is_unlocked, "", ""), | |
435 | U_BOOT_CMD_MKENT(get_uuid, 2, 0, do_avb_get_uuid, "", ""), | |
436 | U_BOOT_CMD_MKENT(read_part, 5, 0, do_avb_read_part, "", ""), | |
437 | U_BOOT_CMD_MKENT(read_part_hex, 4, 0, do_avb_read_part_hex, "", ""), | |
438 | U_BOOT_CMD_MKENT(write_part, 5, 0, do_avb_write_part, "", ""), | |
965ec3ca | 439 | U_BOOT_CMD_MKENT(verify, 2, 0, do_avb_verify_part, "", ""), |
fc1fe01b IO |
440 | #ifdef CONFIG_OPTEE_TA_AVB |
441 | U_BOOT_CMD_MKENT(read_pvalue, 3, 0, do_avb_read_pvalue, "", ""), | |
442 | U_BOOT_CMD_MKENT(write_pvalue, 3, 0, do_avb_write_pvalue, "", ""), | |
443 | #endif | |
60b2f9e7 IO |
444 | }; |
445 | ||
09140113 | 446 | static int do_avb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
60b2f9e7 | 447 | { |
09140113 | 448 | struct cmd_tbl *cp; |
60b2f9e7 IO |
449 | |
450 | cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb)); | |
451 | ||
452 | argc--; | |
453 | argv++; | |
454 | ||
455 | if (!cp || argc > cp->maxargs) | |
456 | return CMD_RET_USAGE; | |
457 | ||
458 | if (flag == CMD_FLAG_REPEAT) | |
459 | return CMD_RET_FAILURE; | |
460 | ||
461 | return cp->cmd(cmdtp, flag, argc, argv); | |
462 | } | |
463 | ||
464 | U_BOOT_CMD( | |
465 | avb, 29, 0, do_avb, | |
466 | "Provides commands for testing Android Verified Boot 2.0 functionality", | |
467 | "init <dev> - initialize avb2 for <dev>\n" | |
468 | "avb read_rb <num> - read rollback index at location <num>\n" | |
469 | "avb write_rb <num> <rb> - write rollback index <rb> to <num>\n" | |
470 | "avb is_unlocked - returns unlock status of the device\n" | |
471 | "avb get_uuid <partname> - read and print uuid of partition <part>\n" | |
472 | "avb read_part <partname> <offset> <num> <addr> - read <num> bytes from\n" | |
473 | " partition <partname> to buffer <addr>\n" | |
474 | "avb read_part_hex <partname> <offset> <num> - read <num> bytes from\n" | |
475 | " partition <partname> and print to stdout\n" | |
476 | "avb write_part <partname> <offset> <num> <addr> - write <num> bytes to\n" | |
477 | " <partname> by <offset> using data from <addr>\n" | |
fc1fe01b IO |
478 | #ifdef CONFIG_OPTEE_TA_AVB |
479 | "avb read_pvalue <name> <bytes> - read a persistent value <name>\n" | |
480 | "avb write_pvalue <name> <value> - write a persistent value <name>\n" | |
481 | #endif | |
965ec3ca | 482 | "avb verify [slot_suffix] - run verification process using hash data\n" |
60b2f9e7 | 483 | " from vbmeta structure\n" |
965ec3ca | 484 | " [slot_suffix] - _a, _b, etc (if vbmeta partition is slotted)\n" |
60b2f9e7 | 485 | ); |