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