cmd_gbb_utility.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  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. #include <errno.h>
  7. #include <getopt.h>
  8. #include <inttypes.h>
  9. #include <stddef.h>
  10. #include <stdint.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <sys/stat.h>
  15. #include <sys/types.h>
  16. #include <unistd.h>
  17. #include "futility.h"
  18. #include "gbb_header.h"
  19. static void print_help(int argc, char *argv[])
  20. {
  21. printf("\n"
  22. "Usage: " MYNAME " %s [-g|-s|-c] [OPTIONS] "
  23. "bios_file [output_file]\n"
  24. "\n"
  25. "GET MODE:\n"
  26. "-g, --get (default)\tGet (read) from bios_file, "
  27. "with following options:\n"
  28. " --hwid \tReport hardware id (default).\n"
  29. " --flags \tReport header flags.\n"
  30. " --digest \tReport digest of hwid (>= v1.2)\n"
  31. " --roothash \tCheck ryu root key hash\n"
  32. " -k, --rootkey=FILE \tFile name to export Root Key.\n"
  33. " -b, --bmpfv=FILE \tFile name to export Bitmap FV.\n"
  34. " -r --recoverykey=FILE\tFile name to export Recovery Key.\n"
  35. "\n"
  36. "SET MODE:\n"
  37. "-s, --set \tSet (write) to bios_file, "
  38. "with following options:\n"
  39. " -o, --output=FILE \tNew file name for ouptput.\n"
  40. " --hwid=HWID \tThe new hardware id to be changed.\n"
  41. " --flags=FLAGS \tThe new (numeric) flags value.\n"
  42. " -k, --rootkey=FILE \tFile name of new Root Key.\n"
  43. " -b, --bmpfv=FILE \tFile name of new Bitmap FV.\n"
  44. " -r --recoverykey=FILE\tFile name of new Recovery Key.\n"
  45. "\n"
  46. "CREATE MODE:\n"
  47. "-c, --create=hwid_size,rootkey_size,bmpfv_size,"
  48. "recoverykey_size\n"
  49. " \tCreate a GBB blob by given size list.\n"
  50. "SAMPLE:\n"
  51. " %s -g bios.bin\n"
  52. " %s --set --hwid='New Model' -k key.bin"
  53. " bios.bin newbios.bin\n"
  54. " %s -c 0x100,0x1000,0x03DE80,0x1000 gbb.blob\n\n",
  55. argv[0], argv[0], argv[0], argv[0]);
  56. }
  57. enum {
  58. OPT_HWID = 1000,
  59. OPT_FLAGS,
  60. OPT_DIGEST,
  61. OPT_HELP,
  62. OPT_ROOTHASH,
  63. };
  64. /* Command line options */
  65. static struct option long_opts[] = {
  66. /* name has_arg *flag val */
  67. {"get", 0, NULL, 'g'},
  68. {"set", 0, NULL, 's'},
  69. {"create", 1, NULL, 'c'},
  70. {"output", 1, NULL, 'o'},
  71. {"rootkey", 1, NULL, 'k'},
  72. {"bmpfv", 1, NULL, 'b'},
  73. {"recoverykey", 1, NULL, 'r'},
  74. {"hwid", 0, NULL, OPT_HWID},
  75. {"flags", 0, NULL, OPT_FLAGS},
  76. {"digest", 0, NULL, OPT_DIGEST},
  77. {"help", 0, NULL, OPT_HELP},
  78. {"roothash", 0, NULL, OPT_ROOTHASH},
  79. {NULL, 0, NULL, 0},
  80. };
  81. static char *short_opts = ":gsc:o:k:b:r:";
  82. /* Change the has_arg field of a long_opts entry */
  83. static void opt_has_arg(const char *name, int val)
  84. {
  85. struct option *p;
  86. for (p = long_opts; p->name; p++)
  87. if (!strcmp(name, p->name)) {
  88. p->has_arg = val;
  89. break;
  90. }
  91. }
  92. static int errorcnt;
  93. #define GBB_SEARCH_STRIDE 4
  94. static GoogleBinaryBlockHeader *FindGbbHeader(uint8_t *ptr, size_t size)
  95. {
  96. size_t i;
  97. GoogleBinaryBlockHeader *tmp, *gbb_header = NULL;
  98. int count = 0;
  99. for (i = 0; i <= size - GBB_SEARCH_STRIDE; i += GBB_SEARCH_STRIDE) {
  100. if (0 != memcmp(ptr + i, GBB_SIGNATURE, GBB_SIGNATURE_SIZE))
  101. continue;
  102. /* Found something. See if it's any good. */
  103. tmp = (GoogleBinaryBlockHeader *) (ptr + i);
  104. if (futil_valid_gbb_header(tmp, size - i, NULL))
  105. if (!count++)
  106. gbb_header = tmp;
  107. }
  108. switch (count) {
  109. case 0:
  110. errorcnt++;
  111. return NULL;
  112. case 1:
  113. return gbb_header;
  114. default:
  115. fprintf(stderr, "ERROR: multiple GBB headers found\n");
  116. errorcnt++;
  117. return NULL;
  118. }
  119. }
  120. static uint8_t *create_gbb(const char *desc, off_t *sizeptr)
  121. {
  122. char *str, *sizes, *param, *e = NULL;
  123. size_t size = GBB_HEADER_SIZE;
  124. int i = 0;
  125. /* Danger Will Robinson! four entries ==> four paramater blocks */
  126. uint32_t val[] = { 0, 0, 0, 0 };
  127. uint8_t *buf;
  128. GoogleBinaryBlockHeader *gbb;
  129. sizes = strdup(desc);
  130. if (!sizes) {
  131. errorcnt++;
  132. fprintf(stderr, "ERROR: strdup() failed: %s\n",
  133. strerror(errno));
  134. return NULL;
  135. }
  136. for (str = sizes; (param = strtok(str, ", ")) != NULL; str = NULL) {
  137. val[i] = (uint32_t) strtoul(param, &e, 0);
  138. if (e && *e) {
  139. errorcnt++;
  140. fprintf(stderr,
  141. "ERROR: invalid creation parameter: \"%s\"\n",
  142. param);
  143. free(sizes);
  144. return NULL;
  145. }
  146. size += val[i++];
  147. if (i > ARRAY_SIZE(val))
  148. break;
  149. }
  150. buf = (uint8_t *) calloc(1, size);
  151. if (!buf) {
  152. errorcnt++;
  153. fprintf(stderr, "ERROR: can't malloc %zu bytes: %s\n",
  154. size, strerror(errno));
  155. free(sizes);
  156. return NULL;
  157. } else if (sizeptr) {
  158. *sizeptr = size;
  159. }
  160. gbb = (GoogleBinaryBlockHeader *) buf;
  161. memcpy(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE);
  162. gbb->major_version = GBB_MAJOR_VER;
  163. gbb->minor_version = GBB_MINOR_VER;
  164. gbb->header_size = GBB_HEADER_SIZE;
  165. gbb->flags = 0;
  166. i = GBB_HEADER_SIZE;
  167. gbb->hwid_offset = i;
  168. gbb->hwid_size = val[0];
  169. i += val[0];
  170. gbb->rootkey_offset = i;
  171. gbb->rootkey_size = val[1];
  172. i += val[1];
  173. gbb->bmpfv_offset = i;
  174. gbb->bmpfv_size = val[2];
  175. i += val[2];
  176. gbb->recovery_key_offset = i;
  177. gbb->recovery_key_size = val[3];
  178. i += val[1];
  179. free(sizes);
  180. return buf;
  181. }
  182. static uint8_t *read_entire_file(const char *filename, off_t *sizeptr)
  183. {
  184. FILE *fp = NULL;
  185. uint8_t *buf = NULL;
  186. struct stat sb;
  187. fp = fopen(filename, "rb");
  188. if (!fp) {
  189. fprintf(stderr, "ERROR: Unable to open %s for reading: %s\n",
  190. filename, strerror(errno));
  191. goto fail;
  192. }
  193. if (0 != fstat(fileno(fp), &sb)) {
  194. fprintf(stderr, "ERROR: can't fstat %s: %s\n",
  195. filename, strerror(errno));
  196. goto fail;
  197. }
  198. if (sizeptr)
  199. *sizeptr = sb.st_size;
  200. buf = (uint8_t *) malloc(sb.st_size);
  201. if (!buf) {
  202. fprintf(stderr, "ERROR: can't malloc %" PRIi64 " bytes: %s\n",
  203. sb.st_size, strerror(errno));
  204. goto fail;
  205. }
  206. if (1 != fread(buf, sb.st_size, 1, fp)) {
  207. fprintf(stderr, "ERROR: Unable to read from %s: %s\n",
  208. filename, strerror(errno));
  209. goto fail;
  210. }
  211. if (0 != fclose(fp)) {
  212. fprintf(stderr, "ERROR: Unable to close %s: %s\n",
  213. filename, strerror(errno));
  214. fp = NULL; /* Don't try to close it again */
  215. goto fail;
  216. }
  217. return buf;
  218. fail:
  219. errorcnt++;
  220. if (buf)
  221. free(buf);
  222. if (fp && 0 != fclose(fp))
  223. fprintf(stderr, "ERROR: Unable to close %s: %s\n",
  224. filename, strerror(errno));
  225. return NULL;
  226. }
  227. static int write_to_file(const char *msg, const char *filename,
  228. uint8_t *start, size_t size)
  229. {
  230. FILE *fp;
  231. int r = 0;
  232. fp = fopen(filename, "wb");
  233. if (!fp) {
  234. fprintf(stderr, "ERROR: Unable to open %s for writing: %s\n",
  235. filename, strerror(errno));
  236. errorcnt++;
  237. return errno;
  238. }
  239. /* Don't write zero bytes */
  240. if (size && 1 != fwrite(start, size, 1, fp)) {
  241. fprintf(stderr, "ERROR: Unable to write to %s: %s\n",
  242. filename, strerror(errno));
  243. errorcnt++;
  244. r = errno;
  245. }
  246. if (0 != fclose(fp)) {
  247. fprintf(stderr, "ERROR: Unable to close %s: %s\n",
  248. filename, strerror(errno));
  249. errorcnt++;
  250. if (!r)
  251. r = errno;
  252. }
  253. if (!r && msg)
  254. printf("%s %s\n", msg, filename);
  255. return r;
  256. }
  257. static int read_from_file(const char *msg, const char *filename,
  258. uint8_t *start, uint32_t size)
  259. {
  260. FILE *fp;
  261. struct stat sb;
  262. size_t count;
  263. int r = 0;
  264. fp = fopen(filename, "rb");
  265. if (!fp) {
  266. fprintf(stderr, "ERROR: Unable to open %s for reading: %s\n",
  267. filename, strerror(errno));
  268. errorcnt++;
  269. return errno;
  270. }
  271. if (0 != fstat(fileno(fp), &sb)) {
  272. fprintf(stderr, "ERROR: can't fstat %s: %s\n",
  273. filename, strerror(errno));
  274. errorcnt++;
  275. r = errno;
  276. goto done_close;
  277. }
  278. if (sb.st_size > size) {
  279. fprintf(stderr,
  280. "ERROR: file %s exceeds capacity (%" PRIu32 ")\n",
  281. filename, size);
  282. errorcnt++;
  283. r = errno;
  284. goto done_close;
  285. }
  286. /* Wipe existing data. */
  287. memset(start, 0, size);
  288. /* It's okay if we read less than size. That's just the max. */
  289. count = fread(start, 1, size, fp);
  290. if (ferror(fp)) {
  291. fprintf(stderr,
  292. "ERROR: Read %zu/%" PRIi64 " bytes from %s: %s\n",
  293. count, sb.st_size, filename, strerror(errno));
  294. errorcnt++;
  295. r = errno;
  296. }
  297. done_close:
  298. if (0 != fclose(fp)) {
  299. fprintf(stderr, "ERROR: Unable to close %s: %s\n",
  300. filename, strerror(errno));
  301. errorcnt++;
  302. if (!r)
  303. r = errno;
  304. }
  305. if (!r && msg)
  306. printf(" - import %s from %s: success\n", msg, filename);
  307. return r;
  308. }
  309. static int do_gbb_utility(int argc, char *argv[])
  310. {
  311. enum do_what_now { DO_GET, DO_SET, DO_CREATE } mode = DO_GET;
  312. char *infile = NULL;
  313. char *outfile = NULL;
  314. char *opt_create = NULL;
  315. char *opt_rootkey = NULL;
  316. char *opt_bmpfv = NULL;
  317. char *opt_recoverykey = NULL;
  318. char *opt_hwid = NULL;
  319. char *opt_flags = NULL;
  320. int sel_hwid = 0;
  321. int sel_digest = 0;
  322. int sel_flags = 0;
  323. int sel_roothash = 0;
  324. uint8_t *inbuf = NULL;
  325. off_t filesize;
  326. uint8_t *outbuf = NULL;
  327. GoogleBinaryBlockHeader *gbb;
  328. uint8_t *gbb_base;
  329. int i;
  330. opterr = 0; /* quiet, you */
  331. while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
  332. switch (i) {
  333. case 'g':
  334. mode = DO_GET;
  335. opt_has_arg("flags", 0);
  336. opt_has_arg("hwid", 0);
  337. break;
  338. case 's':
  339. mode = DO_SET;
  340. opt_has_arg("flags", 1);
  341. opt_has_arg("hwid", 1);
  342. break;
  343. case 'c':
  344. mode = DO_CREATE;
  345. opt_create = optarg;
  346. break;
  347. case 'o':
  348. outfile = optarg;
  349. break;
  350. case 'k':
  351. opt_rootkey = optarg;
  352. break;
  353. case 'b':
  354. opt_bmpfv = optarg;
  355. break;
  356. case 'r':
  357. opt_recoverykey = optarg;
  358. break;
  359. case OPT_HWID:
  360. /* --hwid is optional: null might be okay */
  361. opt_hwid = optarg;
  362. sel_hwid = 1;
  363. break;
  364. case OPT_FLAGS:
  365. /* --flags is optional: null might be okay */
  366. opt_flags = optarg;
  367. sel_flags = 1;
  368. break;
  369. case OPT_DIGEST:
  370. sel_digest = 1;
  371. break;
  372. case OPT_ROOTHASH:
  373. sel_roothash = 1;
  374. break;
  375. case OPT_HELP:
  376. print_help(argc, argv);
  377. return !!errorcnt;
  378. case '?':
  379. errorcnt++;
  380. if (optopt)
  381. fprintf(stderr,
  382. "ERROR: unrecognized option: -%c\n",
  383. optopt);
  384. else if (argv[optind - 1])
  385. fprintf(stderr,
  386. "ERROR: unrecognized option "
  387. "(possibly \"%s\")\n",
  388. argv[optind - 1]);
  389. else
  390. fprintf(stderr, "ERROR: unrecognized option\n");
  391. break;
  392. case ':':
  393. errorcnt++;
  394. if (argv[optind - 1])
  395. fprintf(stderr,
  396. "ERROR: missing argument to -%c (%s)\n",
  397. optopt, argv[optind - 1]);
  398. else
  399. fprintf(stderr,
  400. "ERROR: missing argument to -%c\n",
  401. optopt);
  402. break;
  403. default:
  404. errorcnt++;
  405. fprintf(stderr,
  406. "ERROR: error while parsing options\n");
  407. }
  408. }
  409. /* Problems? */
  410. if (errorcnt) {
  411. print_help(argc, argv);
  412. return 1;
  413. }
  414. /* Now try to do something */
  415. switch (mode) {
  416. case DO_GET:
  417. if (argc - optind < 1) {
  418. fprintf(stderr, "\nERROR: missing input filename\n");
  419. print_help(argc, argv);
  420. return 1;
  421. } else {
  422. infile = argv[optind++];
  423. }
  424. /* With no args, show the HWID */
  425. if (!opt_rootkey && !opt_bmpfv && !opt_recoverykey
  426. && !sel_flags && !sel_digest)
  427. sel_hwid = 1;
  428. inbuf = read_entire_file(infile, &filesize);
  429. if (!inbuf)
  430. break;
  431. gbb = FindGbbHeader(inbuf, filesize);
  432. if (!gbb) {
  433. fprintf(stderr, "ERROR: No GBB found in %s\n", infile);
  434. break;
  435. }
  436. gbb_base = (uint8_t *) gbb;
  437. /* Get the stuff */
  438. if (sel_hwid)
  439. printf("hardware_id: %s\n",
  440. gbb->hwid_size ? (char *)(gbb_base +
  441. gbb->
  442. hwid_offset) : "");
  443. if (sel_digest)
  444. print_hwid_digest(gbb, "digest: ", "\n");
  445. if (sel_roothash)
  446. verify_ryu_root_header(inbuf, filesize, gbb);
  447. if (sel_flags)
  448. printf("flags: 0x%08x\n", gbb->flags);
  449. if (opt_rootkey)
  450. write_to_file(" - exported root_key to file:",
  451. opt_rootkey,
  452. gbb_base + gbb->rootkey_offset,
  453. gbb->rootkey_size);
  454. if (opt_bmpfv)
  455. write_to_file(" - exported bmp_fv to file:", opt_bmpfv,
  456. gbb_base + gbb->bmpfv_offset,
  457. gbb->bmpfv_size);
  458. if (opt_recoverykey)
  459. write_to_file(" - exported recovery_key to file:",
  460. opt_recoverykey,
  461. gbb_base + gbb->recovery_key_offset,
  462. gbb->recovery_key_size);
  463. break;
  464. case DO_SET:
  465. if (argc - optind < 1) {
  466. fprintf(stderr, "\nERROR: missing input filename\n");
  467. print_help(argc, argv);
  468. return 1;
  469. }
  470. infile = argv[optind++];
  471. if (!outfile)
  472. outfile = (argc - optind < 1) ? infile : argv[optind++];
  473. if (sel_hwid && !opt_hwid) {
  474. fprintf(stderr, "\nERROR: missing new HWID value\n");
  475. print_help(argc, argv);
  476. return 1;
  477. }
  478. if (sel_flags && (!opt_flags || !*opt_flags)) {
  479. fprintf(stderr, "\nERROR: missing new flags value\n");
  480. print_help(argc, argv);
  481. return 1;
  482. }
  483. /* With no args, we'll either copy it unchanged or do nothing */
  484. inbuf = read_entire_file(infile, &filesize);
  485. if (!inbuf)
  486. break;
  487. gbb = FindGbbHeader(inbuf, filesize);
  488. if (!gbb) {
  489. fprintf(stderr, "ERROR: No GBB found in %s\n", infile);
  490. break;
  491. }
  492. gbb_base = (uint8_t *) gbb;
  493. outbuf = (uint8_t *) malloc(filesize);
  494. if (!outbuf) {
  495. errorcnt++;
  496. fprintf(stderr,
  497. "ERROR: can't malloc %" PRIi64 " bytes: %s\n",
  498. filesize, strerror(errno));
  499. break;
  500. }
  501. /* Switch pointers to outbuf */
  502. memcpy(outbuf, inbuf, filesize);
  503. gbb = FindGbbHeader(outbuf, filesize);
  504. if (!gbb) {
  505. fprintf(stderr,
  506. "INTERNAL ERROR: No GBB found in outbuf\n");
  507. exit(1);
  508. }
  509. gbb_base = (uint8_t *) gbb;
  510. if (opt_hwid) {
  511. if (strlen(opt_hwid) + 1 > gbb->hwid_size) {
  512. fprintf(stderr,
  513. "ERROR: null-terminated HWID"
  514. " exceeds capacity (%d)\n",
  515. gbb->hwid_size);
  516. errorcnt++;
  517. } else {
  518. /* Wipe data before writing new value. */
  519. memset(gbb_base + gbb->hwid_offset, 0,
  520. gbb->hwid_size);
  521. strcpy((char *)(gbb_base + gbb->hwid_offset),
  522. opt_hwid);
  523. update_hwid_digest(gbb);
  524. }
  525. }
  526. if (opt_flags) {
  527. char *e = NULL;
  528. uint32_t val;
  529. val = (uint32_t) strtoul(opt_flags, &e, 0);
  530. if (e && *e) {
  531. fprintf(stderr,
  532. "ERROR: invalid flags value: %s\n",
  533. opt_flags);
  534. errorcnt++;
  535. } else {
  536. gbb->flags = val;
  537. }
  538. }
  539. if (opt_rootkey) {
  540. read_from_file("root_key", opt_rootkey,
  541. gbb_base + gbb->rootkey_offset,
  542. gbb->rootkey_size);
  543. if (fill_ryu_root_header(outbuf, filesize, gbb))
  544. errorcnt++;
  545. }
  546. if (opt_bmpfv)
  547. read_from_file("bmp_fv", opt_bmpfv,
  548. gbb_base + gbb->bmpfv_offset,
  549. gbb->bmpfv_size);
  550. if (opt_recoverykey)
  551. read_from_file("recovery_key", opt_recoverykey,
  552. gbb_base + gbb->recovery_key_offset,
  553. gbb->recovery_key_size);
  554. /* Write it out if there are no problems. */
  555. if (!errorcnt)
  556. write_to_file("successfully saved new image to:",
  557. outfile, outbuf, filesize);
  558. break;
  559. case DO_CREATE:
  560. if (!outfile) {
  561. if (argc - optind < 1) {
  562. fprintf(stderr,
  563. "\nERROR: missing output filename\n");
  564. print_help(argc, argv);
  565. return 1;
  566. }
  567. outfile = argv[optind++];
  568. }
  569. /* Parse the creation args */
  570. outbuf = create_gbb(opt_create, &filesize);
  571. if (!outbuf) {
  572. fprintf(stderr,
  573. "\nERROR: unable to parse creation spec (%s)\n",
  574. opt_create);
  575. print_help(argc, argv);
  576. return 1;
  577. }
  578. if (!errorcnt)
  579. write_to_file("successfully created new GBB to:",
  580. outfile, outbuf, filesize);
  581. break;
  582. }
  583. if (inbuf)
  584. free(inbuf);
  585. if (outbuf)
  586. free(outbuf);
  587. return !!errorcnt;
  588. }
  589. DECLARE_FUTIL_COMMAND(gbb_utility, do_gbb_utility, VBOOT_VERSION_ALL,
  590. "Manipulate the Google Binary Block (GBB)");