• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Fatal(const char * format,...)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 */
print_help(const char * progname)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. */
error_fread(FILE * fp)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 */
ReadOldKPartFromFileOrDie(const char * filename,uint64_t * size_ptr)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", filename);
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 
do_vbutil_kernel(int argc,char * argv[])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