cmd_vbutil_kernel.c 17 KB

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