1 /* 2 * Copyright 2014 The Chromium OS Authors. All rights reserved. 3 * Use of this source code is governed by a BSD-style license that can be 4 * found in the LICENSE file. 5 * 6 * Verified boot kernel utility 7 */ 8 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <getopt.h> 12 #include <inttypes.h> /* For PRIu64 */ 13 #ifndef HAVE_MACOS 14 #include <linux/fs.h> /* For BLKGETSIZE64 */ 15 #endif 16 #include <stdarg.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <sys/ioctl.h> 20 #include <sys/stat.h> 21 #include <unistd.h> 22 23 #include "file_type.h" 24 #include "futility.h" 25 #include "host_common.h" 26 #include "kernel_blob.h" 27 #include "traversal.h" 28 #include "vb1_helper.h" 29 30 static void Fatal(const char *format, ...) 31 { 32 va_list ap; 33 va_start(ap, format); 34 fprintf(stderr, "ERROR: "); 35 vfprintf(stderr, format, ap); 36 va_end(ap); 37 exit(1); 38 } 39 40 /* Global opts */ 41 static int opt_verbose; 42 static int opt_vblockonly; 43 static uint64_t opt_pad = 65536; 44 45 /* Command line options */ 46 enum { 47 OPT_MODE_PACK = 1000, 48 OPT_MODE_REPACK, 49 OPT_MODE_VERIFY, 50 OPT_MODE_GET_VMLINUZ, 51 OPT_ARCH, 52 OPT_OLDBLOB, 53 OPT_KLOADADDR, 54 OPT_KEYBLOCK, 55 OPT_SIGNPUBKEY, 56 OPT_SIGNPRIVATE, 57 OPT_VERSION, 58 OPT_VMLINUZ, 59 OPT_BOOTLOADER, 60 OPT_CONFIG, 61 OPT_VBLOCKONLY, 62 OPT_PAD, 63 OPT_VERBOSE, 64 OPT_MINVERSION, 65 OPT_VMLINUZ_OUT, 66 OPT_FLAGS, 67 }; 68 69 static const struct option long_opts[] = { 70 {"pack", 1, 0, OPT_MODE_PACK}, 71 {"repack", 1, 0, OPT_MODE_REPACK}, 72 {"verify", 1, 0, OPT_MODE_VERIFY}, 73 {"get-vmlinuz", 1, 0, OPT_MODE_GET_VMLINUZ}, 74 {"arch", 1, 0, OPT_ARCH}, 75 {"oldblob", 1, 0, OPT_OLDBLOB}, 76 {"kloadaddr", 1, 0, OPT_KLOADADDR}, 77 {"keyblock", 1, 0, OPT_KEYBLOCK}, 78 {"signpubkey", 1, 0, OPT_SIGNPUBKEY}, 79 {"signprivate", 1, 0, OPT_SIGNPRIVATE}, 80 {"version", 1, 0, OPT_VERSION}, 81 {"minversion", 1, 0, OPT_MINVERSION}, 82 {"vmlinuz", 1, 0, OPT_VMLINUZ}, 83 {"bootloader", 1, 0, OPT_BOOTLOADER}, 84 {"config", 1, 0, OPT_CONFIG}, 85 {"vblockonly", 0, 0, OPT_VBLOCKONLY}, 86 {"pad", 1, 0, OPT_PAD}, 87 {"verbose", 0, &opt_verbose, 1}, 88 {"debug", 0, &debugging_enabled, 1}, 89 {"vmlinuz-out", 1, 0, OPT_VMLINUZ_OUT}, 90 {"flags", 1, 0, OPT_FLAGS}, 91 {NULL, 0, 0, 0} 92 }; 93 94 95 96 static const char usage[] = 97 "\n" 98 "Usage: " MYNAME " %s --pack <file> [PARAMETERS]\n" 99 "\n" 100 " Required parameters:\n" 101 " --keyblock <file> Key block in .keyblock format\n" 102 " --signprivate <file> Private key to sign kernel data,\n" 103 " in .vbprivk format\n" 104 " --version <number> Kernel version\n" 105 " --vmlinuz <file> Linux kernel bzImage file\n" 106 " --bootloader <file> Bootloader stub\n" 107 " --config <file> Command line file\n" 108 " --arch <arch> Cpu architecture (default x86)\n" 109 "\n" 110 " Optional:\n" 111 " --kloadaddr <address> Assign kernel body load address\n" 112 " --pad <number> Verification padding size in bytes\n" 113 " --vblockonly Emit just the verification blob\n" 114 " --flags NUM Flags to be passed in the header\n" 115 "\nOR\n\n" 116 "Usage: " MYNAME " %s --repack <file> [PARAMETERS]\n" 117 "\n" 118 " Required parameters:\n" 119 " --signprivate <file> Private key to sign kernel data,\n" 120 " in .vbprivk format\n" 121 " --oldblob <file> Previously packed kernel blob\n" 122 " (including verfication blob)\n" 123 "\n" 124 " Optional:\n" 125 " --keyblock <file> Key block in .keyblock format\n" 126 " --config <file> New command line file\n" 127 " --version <number> Kernel version\n" 128 " --kloadaddr <address> Assign kernel body load address\n" 129 " --pad <number> Verification blob size in bytes\n" 130 " --vblockonly Emit just the verification blob\n" 131 "\nOR\n\n" 132 "Usage: " MYNAME " %s --verify <file> [PARAMETERS]\n" 133 "\n" 134 " Optional:\n" 135 " --signpubkey <file>" 136 " Public key to verify kernel keyblock,\n" 137 " in .vbpubk format\n" 138 " --verbose Print a more detailed report\n" 139 " --keyblock <file> Outputs the verified key block,\n" 140 " in .keyblock format\n" 141 " --pad <number> Verification padding size in bytes\n" 142 " --minversion <number> Minimum combined kernel key version\n" 143 "\nOR\n\n" 144 "Usage: " MYNAME " %s --get-vmlinuz <file> [PARAMETERS]\n" 145 "\n" 146 " Required parameters:\n" 147 " --vmlinuz-out <file> vmlinuz image output file\n" 148 "\n"; 149 150 151 /* Print help and return error */ 152 static void print_help(const char *progname) 153 { 154 printf(usage, progname, progname, progname, progname); 155 } 156 157 158 /* Return an explanation when fread() fails. */ 159 static const char *error_fread(FILE *fp) 160 { 161 const char *retval = "beats me why"; 162 if (feof(fp)) 163 retval = "EOF"; 164 else if (ferror(fp)) 165 retval = strerror(errno); 166 clearerr(fp); 167 return retval; 168 } 169 170 171 /* This reads a complete kernel partition into a buffer */ 172 static uint8_t *ReadOldKPartFromFileOrDie(const char *filename, 173 uint64_t *size_ptr) 174 { 175 FILE *fp = NULL; 176 struct stat statbuf; 177 uint8_t *buf; 178 uint64_t file_size = 0; 179 180 if (0 != stat(filename, &statbuf)) 181 Fatal("Unable to stat %s: %s\n", filename, strerror(errno)); 182 183 if (S_ISBLK(statbuf.st_mode)) { 184 #ifndef HAVE_MACOS 185 int fd = open(filename, O_RDONLY); 186 if (fd >= 0) { 187 ioctl(fd, BLKGETSIZE64, &file_size); 188 close(fd); 189 } 190 #endif 191 } else { 192 file_size = statbuf.st_size; 193 } 194 Debug("%s size is 0x%" PRIx64 "\n", filename, file_size); 195 if (file_size < opt_pad) 196 Fatal("%s is too small to be a valid kernel blob\n"); 197 198 Debug("Reading %s\n", filename); 199 fp = fopen(filename, "rb"); 200 if (!fp) 201 Fatal("Unable to open file %s: %s\n", filename, 202 strerror(errno)); 203 204 buf = malloc(file_size); 205 if (1 != fread(buf, file_size, 1, fp)) 206 Fatal("Unable to read entirety of %s: %s\n", filename, 207 error_fread(fp)); 208 209 if (size_ptr) 210 *size_ptr = file_size; 211 212 return buf; 213 } 214 215 /****************************************************************************/ 216 217 static int do_vbutil_kernel(int argc, char *argv[]) 218 { 219 char *filename = NULL; 220 char *oldfile = NULL; 221 char *keyblock_file = NULL; 222 char *signpubkey_file = NULL; 223 char *signprivkey_file = NULL; 224 char *version_str = NULL; 225 int version = -1; 226 char *vmlinuz_file = NULL; 227 char *bootloader_file = NULL; 228 char *config_file = NULL; 229 char *vmlinuz_out_file = NULL; 230 enum arch_t arch = ARCH_X86; 231 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR; 232 int mode = 0; 233 int parse_error = 0; 234 uint64_t min_version = 0; 235 char *e; 236 int i = 0; 237 int errcount = 0; 238 int rv; 239 VbKeyBlockHeader *keyblock = NULL; 240 VbKeyBlockHeader *t_keyblock = NULL; 241 VbPrivateKey *signpriv_key = NULL; 242 VbPublicKey *signpub_key = NULL; 243 uint8_t *kpart_data = NULL; 244 uint64_t kpart_size = 0; 245 uint8_t *vmlinuz_buf = NULL; 246 uint64_t vmlinuz_size = 0; 247 uint8_t *t_config_data; 248 uint64_t t_config_size; 249 uint8_t *t_bootloader_data; 250 uint64_t t_bootloader_size; 251 uint64_t vmlinuz_header_size = 0; 252 uint64_t vmlinuz_header_address = 0; 253 uint64_t vmlinuz_header_offset = 0; 254 VbKernelPreambleHeader *preamble = NULL; 255 uint8_t *kblob_data = NULL; 256 uint64_t kblob_size = 0; 257 uint8_t *vblock_data = NULL; 258 uint64_t vblock_size = 0; 259 uint32_t flags = 0; 260 FILE *f; 261 262 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && 263 !parse_error) { 264 switch (i) { 265 default: 266 case '?': 267 /* Unhandled option */ 268 parse_error = 1; 269 break; 270 271 case 0: 272 /* silently handled option */ 273 break; 274 275 case OPT_MODE_PACK: 276 case OPT_MODE_REPACK: 277 case OPT_MODE_VERIFY: 278 case OPT_MODE_GET_VMLINUZ: 279 if (mode && (mode != i)) { 280 fprintf(stderr, 281 "Only one mode can be specified\n"); 282 parse_error = 1; 283 break; 284 } 285 mode = i; 286 filename = optarg; 287 break; 288 289 case OPT_ARCH: 290 /* check the first 3 characters to also detect x86_64 */ 291 if ((!strncasecmp(optarg, "x86", 3)) || 292 (!strcasecmp(optarg, "amd64"))) 293 arch = ARCH_X86; 294 else if ((!strcasecmp(optarg, "arm")) || 295 (!strcasecmp(optarg, "aarch64"))) 296 arch = ARCH_ARM; 297 else if (!strcasecmp(optarg, "mips")) 298 arch = ARCH_MIPS; 299 else { 300 fprintf(stderr, 301 "Unknown architecture string: %s\n", 302 optarg); 303 parse_error = 1; 304 } 305 break; 306 307 case OPT_OLDBLOB: 308 oldfile = optarg; 309 break; 310 311 case OPT_KLOADADDR: 312 kernel_body_load_address = strtoul(optarg, &e, 0); 313 if (!*optarg || (e && *e)) { 314 fprintf(stderr, "Invalid --kloadaddr\n"); 315 parse_error = 1; 316 } 317 break; 318 319 case OPT_KEYBLOCK: 320 keyblock_file = optarg; 321 break; 322 323 case OPT_SIGNPUBKEY: 324 signpubkey_file = optarg; 325 break; 326 327 case OPT_SIGNPRIVATE: 328 signprivkey_file = optarg; 329 break; 330 331 case OPT_VMLINUZ: 332 vmlinuz_file = optarg; 333 break; 334 335 case OPT_FLAGS: 336 flags = (uint32_t)strtoul(optarg, &e, 0); 337 if (!*optarg || (e && *e)) { 338 fprintf(stderr, "Invalid --flags\n"); 339 parse_error = 1; 340 } 341 break; 342 343 case OPT_BOOTLOADER: 344 bootloader_file = optarg; 345 break; 346 347 case OPT_CONFIG: 348 config_file = optarg; 349 break; 350 351 case OPT_VBLOCKONLY: 352 opt_vblockonly = 1; 353 break; 354 355 case OPT_VERSION: 356 version_str = optarg; 357 version = strtoul(optarg, &e, 0); 358 if (!*optarg || (e && *e)) { 359 fprintf(stderr, "Invalid --version\n"); 360 parse_error = 1; 361 } 362 break; 363 364 case OPT_MINVERSION: 365 min_version = strtoul(optarg, &e, 0); 366 if (!*optarg || (e && *e)) { 367 fprintf(stderr, "Invalid --minversion\n"); 368 parse_error = 1; 369 } 370 break; 371 372 case OPT_PAD: 373 opt_pad = strtoul(optarg, &e, 0); 374 if (!*optarg || (e && *e)) { 375 fprintf(stderr, "Invalid --pad\n"); 376 parse_error = 1; 377 } 378 break; 379 case OPT_VMLINUZ_OUT: 380 vmlinuz_out_file = optarg; 381 } 382 } 383 384 if (parse_error) { 385 print_help(argv[0]); 386 return 1; 387 } 388 389 switch (mode) { 390 case OPT_MODE_PACK: 391 392 if (!keyblock_file) 393 Fatal("Missing required keyblock file.\n"); 394 395 t_keyblock = (VbKeyBlockHeader *)ReadFile(keyblock_file, 0); 396 if (!t_keyblock) 397 Fatal("Error reading key block.\n"); 398 399 if (!signprivkey_file) 400 Fatal("Missing required signprivate file.\n"); 401 402 signpriv_key = PrivateKeyRead(signprivkey_file); 403 if (!signpriv_key) 404 Fatal("Error reading signing key.\n"); 405 406 if (!config_file) 407 Fatal("Missing required config file.\n"); 408 409 Debug("Reading %s\n", config_file); 410 t_config_data = 411 ReadConfigFile(config_file, &t_config_size); 412 if (!t_config_data) 413 Fatal("Error reading config file.\n"); 414 415 if (!bootloader_file) 416 Fatal("Missing required bootloader file.\n"); 417 418 Debug("Reading %s\n", bootloader_file); 419 t_bootloader_data = ReadFile(bootloader_file, 420 &t_bootloader_size); 421 if (!t_bootloader_data) 422 Fatal("Error reading bootloader file.\n"); 423 Debug(" bootloader file size=0x%" PRIx64 "\n", 424 t_bootloader_size); 425 426 if (!vmlinuz_file) 427 Fatal("Missing required vmlinuz file.\n"); 428 Debug("Reading %s\n", vmlinuz_file); 429 vmlinuz_buf = ReadFile(vmlinuz_file, &vmlinuz_size); 430 if (!vmlinuz_buf) 431 Fatal("Error reading vmlinuz file.\n"); 432 Debug(" vmlinuz file size=0x%" PRIx64 "\n", 433 vmlinuz_size); 434 if (!vmlinuz_size) 435 Fatal("Empty vmlinuz file\n"); 436 437 kblob_data = CreateKernelBlob( 438 vmlinuz_buf, vmlinuz_size, 439 arch, kernel_body_load_address, 440 t_config_data, t_config_size, 441 t_bootloader_data, t_bootloader_size, 442 &kblob_size); 443 if (!kblob_data) 444 Fatal("Unable to create kernel blob\n"); 445 446 Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size); 447 448 vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad, 449 version, kernel_body_load_address, 450 t_keyblock, signpriv_key, flags, 451 &vblock_size); 452 if (!vblock_data) 453 Fatal("Unable to sign kernel blob\n"); 454 455 Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size); 456 457 if (opt_vblockonly) 458 rv = WriteSomeParts(filename, 459 vblock_data, vblock_size, 460 NULL, 0); 461 else 462 rv = WriteSomeParts(filename, 463 vblock_data, vblock_size, 464 kblob_data, kblob_size); 465 return rv; 466 467 case OPT_MODE_REPACK: 468 469 /* Required */ 470 471 if (!signprivkey_file) 472 Fatal("Missing required signprivate file.\n"); 473 474 signpriv_key = PrivateKeyRead(signprivkey_file); 475 if (!signpriv_key) 476 Fatal("Error reading signing key.\n"); 477 478 if (!oldfile) 479 Fatal("Missing previously packed blob.\n"); 480 481 /* Load the kernel partition */ 482 kpart_data = ReadOldKPartFromFileOrDie(oldfile, &kpart_size); 483 484 /* Make sure we have a kernel partition */ 485 if (FILE_TYPE_KERN_PREAMBLE != 486 futil_file_type_buf(kpart_data, kpart_size)) 487 Fatal("%s is not a kernel blob\n", oldfile); 488 489 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad, 490 &keyblock, &preamble, &kblob_size); 491 492 if (!kblob_data) 493 Fatal("Unable to unpack kernel partition\n"); 494 495 kernel_body_load_address = preamble->body_load_address; 496 497 /* Update the config if asked */ 498 if (config_file) { 499 Debug("Reading %s\n", config_file); 500 t_config_data = 501 ReadConfigFile(config_file, &t_config_size); 502 if (!t_config_data) 503 Fatal("Error reading config file.\n"); 504 if (0 != UpdateKernelBlobConfig( 505 kblob_data, kblob_size, 506 t_config_data, t_config_size)) 507 Fatal("Unable to update config\n"); 508 } 509 510 if (!version_str) 511 version = preamble->kernel_version; 512 513 if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) 514 flags = preamble->flags; 515 516 if (keyblock_file) { 517 t_keyblock = 518 (VbKeyBlockHeader *)ReadFile(keyblock_file, 0); 519 if (!t_keyblock) 520 Fatal("Error reading key block.\n"); 521 } 522 523 /* Reuse previous body size */ 524 vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad, 525 version, kernel_body_load_address, 526 t_keyblock ? t_keyblock : keyblock, 527 signpriv_key, flags, &vblock_size); 528 if (!vblock_data) 529 Fatal("Unable to sign kernel blob\n"); 530 531 if (opt_vblockonly) 532 rv = WriteSomeParts(filename, 533 vblock_data, vblock_size, 534 NULL, 0); 535 else 536 rv = WriteSomeParts(filename, 537 vblock_data, vblock_size, 538 kblob_data, kblob_size); 539 return rv; 540 541 case OPT_MODE_VERIFY: 542 543 /* Optional */ 544 545 if (signpubkey_file) { 546 signpub_key = PublicKeyRead(signpubkey_file); 547 if (!signpub_key) 548 Fatal("Error reading public key.\n"); 549 } 550 551 /* Do it */ 552 553 /* Load the kernel partition */ 554 kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size); 555 556 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad, 557 0, 0, &kblob_size); 558 if (!kblob_data) 559 Fatal("Unable to unpack kernel partition\n"); 560 561 rv = VerifyKernelBlob(kblob_data, kblob_size, 562 signpub_key, keyblock_file, min_version); 563 564 return rv; 565 566 case OPT_MODE_GET_VMLINUZ: 567 568 if (!vmlinuz_out_file) { 569 fprintf(stderr, 570 "USE: vbutil_kernel --get-vmlinuz <file> " 571 "--vmlinuz-out <file>\n"); 572 print_help(argv[0]); 573 return 1; 574 } 575 576 kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size); 577 578 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad, 579 &keyblock, &preamble, &kblob_size); 580 581 if (!kblob_data) 582 Fatal("Unable to unpack kernel partition\n"); 583 584 f = fopen(vmlinuz_out_file, "wb"); 585 if (!f) { 586 VbExError("Can't open output file %s\n", 587 vmlinuz_out_file); 588 return 1; 589 } 590 591 /* Now stick 16-bit header followed by kernel block into 592 output */ 593 if (VbGetKernelVmlinuzHeader(preamble, 594 &vmlinuz_header_address, 595 &vmlinuz_header_size) 596 != VBOOT_SUCCESS) { 597 Fatal("Unable to retrieve Vmlinuz Header!"); 598 } 599 600 if (vmlinuz_header_size) { 601 // verify that the 16-bit header is included in the 602 // kblob (to make sure that it's included in the 603 // signature) 604 if (VerifyVmlinuzInsideKBlob(preamble->body_load_address, 605 kblob_size, 606 vmlinuz_header_address, 607 vmlinuz_header_size)) { 608 VbExError("Vmlinuz header not signed!\n"); 609 fclose(f); 610 unlink(vmlinuz_out_file); 611 return 1; 612 } 613 // calculate the vmlinuz_header offset from 614 // the beginning of the kpart_data. The kblob doesn't 615 // include the body_load_offset, but does include 616 // the keyblock and preamble sections. 617 vmlinuz_header_offset = vmlinuz_header_address - 618 preamble->body_load_address + 619 keyblock->key_block_size + 620 preamble->preamble_size; 621 errcount |= 622 (1 != fwrite(kpart_data + vmlinuz_header_offset, 623 vmlinuz_header_size, 624 1, 625 f)); 626 } 627 errcount |= (1 != fwrite(kblob_data, 628 kblob_size, 629 1, 630 f)); 631 if (errcount) { 632 VbExError("Can't write output file %s\n", 633 vmlinuz_out_file); 634 fclose(f); 635 unlink(vmlinuz_out_file); 636 return 1; 637 } 638 639 fclose(f); 640 return 0; 641 } 642 643 fprintf(stderr, 644 "You must specify a mode: " 645 "--pack, --repack, --verify, or --get-vmlinuz\n"); 646 print_help(argv[0]); 647 return 1; 648 } 649 650 DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel, 651 VBOOT_VERSION_1_0, 652 "Creates, signs, and verifies the kernel partition", 653 print_help); 654