xref: /openbmc/u-boot/cmd/avb.c (revision c83c436d)
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 	printf("Failed to initialize avb2\n");
39 
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 
70 	printf("Failed to read from partition\n");
71 
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 
115 	printf("Failed to read from partition\n");
116 
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 
147 	printf("Failed to write in partition\n");
148 
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) {
169 		printf("Rollback index: %llx\n", rb_idx);
170 		return CMD_RET_SUCCESS;
171 	}
172 
173 	printf("Failed to read rollback index\n");
174 
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 
198 	printf("Failed to write rollback index\n");
199 
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 
226 	printf("Failed to read UUID\n");
227 
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;
236 	char *cmdline;
237 	char *extra_args;
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:
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 		 */
274 		printf("Verification passed successfully\n");
275 
276 		/* export additional bootargs to AVB_BOOTARGS env var */
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);
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 
338 	printf("Can't determine device lock state.\n");
339 
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 	);
390