Home | History | Annotate | Download | only in futility
      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