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