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