mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-24 16:57:21 +00:00
Ryu will store a hash of the GBB root key in a struct inside its boot
block. Add a vb2_ryu_root_key_hash struct for that.
If 'futility gbb_utility' is used to set the root key, also look for a
root key hash struct and fill it in. No error if not found, because
this needs to work on other platforms where the struct is not present.
This way, we don't need to change the signing scripts.
Added a --roothash option which can be used to check if the root key
hash is found, and if so, whether it's empty, valid, or invalid.
BUG=chromium:511405
BRANCH=ryu
TEST=manual
Take any existing image.bin.
cp image.bin image.orig
gbb_utility --roothash image.bin
- ryu root hash not found
Extract the root key
gbb_utility -k rootkey.bin image.bin
- exported root_key to file: rootkey.bin
Now, append a blank ryu root hash struct to it
echo '0000000: 5274 4b79 4861 7368 0100 0000 3000 0000' | xxd -r >> image.bin
echo '0000000: 0000 0000 0000 0000 0000 0000 0000 0000' | xxd -r >> image.bin
echo '0000000: 0000 0000 0000 0000 0000 0000 0000 0000' | xxd -r >> image.bin
Nothing is set yet
gbb_utility --roothash image.bin
- ryu root hash is unset
Setting the root key also sets the root hash
gbb_utility -s -k rootkey.bin image.bin
- import root_key from rootkey.bin: success
- calculate ryu root hash: success
successfully saved new image to: image.bin
See, it verifies
gbb_utility --roothash image.bin
- ryu root hash verified
Now, append a bad ryu root hash struct to it
cp image.orig image.bin
echo '0000000: 5274 4b79 4861 7368 0100 0000 3000 0000' | xxd -r >> image.bin
echo '0000000: 0001 0000 0000 0000 0000 0000 0000 0000' | xxd -r >> image.bin
echo '0000000: 0000 0000 0000 0000 0000 0000 0000 0000' | xxd -r >> image.bin
See, it fails
gbb_utility --roothash image.bin
- ryu root hash does not verify
Make sure the library doesn't contain the magic string
strings `which futility` | grep RtKyHash
(should be no output)
Change-Id: Ib46f93cac0f2b532bada4b187ae48efcf4926702
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/286237
Reviewed-by: Furquan Shaikh <furquan@chromium.org>
662 lines
15 KiB
C
662 lines
15 KiB
C
/*
|
|
* Copyright 2014 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
#include <errno.h>
|
|
#include <getopt.h>
|
|
#include <inttypes.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "futility.h"
|
|
#include "gbb_header.h"
|
|
|
|
static void print_help(int argc, char *argv[])
|
|
{
|
|
printf("\n"
|
|
"Usage: " MYNAME " %s [-g|-s|-c] [OPTIONS] "
|
|
"bios_file [output_file]\n"
|
|
"\n"
|
|
"GET MODE:\n"
|
|
"-g, --get (default)\tGet (read) from bios_file, "
|
|
"with following options:\n"
|
|
" --hwid \tReport hardware id (default).\n"
|
|
" --flags \tReport header flags.\n"
|
|
" --digest \tReport digest of hwid (>= v1.2)\n"
|
|
" --roothash \tCheck ryu root key hash\n"
|
|
" -k, --rootkey=FILE \tFile name to export Root Key.\n"
|
|
" -b, --bmpfv=FILE \tFile name to export Bitmap FV.\n"
|
|
" -r --recoverykey=FILE\tFile name to export Recovery Key.\n"
|
|
"\n"
|
|
"SET MODE:\n"
|
|
"-s, --set \tSet (write) to bios_file, "
|
|
"with following options:\n"
|
|
" -o, --output=FILE \tNew file name for ouptput.\n"
|
|
" --hwid=HWID \tThe new hardware id to be changed.\n"
|
|
" --flags=FLAGS \tThe new (numeric) flags value.\n"
|
|
" -k, --rootkey=FILE \tFile name of new Root Key.\n"
|
|
" -b, --bmpfv=FILE \tFile name of new Bitmap FV.\n"
|
|
" -r --recoverykey=FILE\tFile name of new Recovery Key.\n"
|
|
"\n"
|
|
"CREATE MODE:\n"
|
|
"-c, --create=hwid_size,rootkey_size,bmpfv_size,"
|
|
"recoverykey_size\n"
|
|
" \tCreate a GBB blob by given size list.\n"
|
|
"SAMPLE:\n"
|
|
" %s -g bios.bin\n"
|
|
" %s --set --hwid='New Model' -k key.bin"
|
|
" bios.bin newbios.bin\n"
|
|
" %s -c 0x100,0x1000,0x03DE80,0x1000 gbb.blob\n\n",
|
|
argv[0], argv[0], argv[0], argv[0]);
|
|
}
|
|
|
|
enum {
|
|
OPT_HWID = 1000,
|
|
OPT_FLAGS,
|
|
OPT_DIGEST,
|
|
OPT_HELP,
|
|
OPT_ROOTHASH,
|
|
};
|
|
|
|
/* Command line options */
|
|
static struct option long_opts[] = {
|
|
/* name has_arg *flag val */
|
|
{"get", 0, NULL, 'g'},
|
|
{"set", 0, NULL, 's'},
|
|
{"create", 1, NULL, 'c'},
|
|
{"output", 1, NULL, 'o'},
|
|
{"rootkey", 1, NULL, 'k'},
|
|
{"bmpfv", 1, NULL, 'b'},
|
|
{"recoverykey", 1, NULL, 'r'},
|
|
{"hwid", 0, NULL, OPT_HWID},
|
|
{"flags", 0, NULL, OPT_FLAGS},
|
|
{"digest", 0, NULL, OPT_DIGEST},
|
|
{"help", 0, NULL, OPT_HELP},
|
|
{"roothash", 0, NULL, OPT_ROOTHASH},
|
|
{NULL, 0, NULL, 0},
|
|
};
|
|
|
|
static char *short_opts = ":gsc:o:k:b:r:";
|
|
|
|
/* Change the has_arg field of a long_opts entry */
|
|
static void opt_has_arg(const char *name, int val)
|
|
{
|
|
struct option *p;
|
|
for (p = long_opts; p->name; p++)
|
|
if (!strcmp(name, p->name)) {
|
|
p->has_arg = val;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int errorcnt;
|
|
|
|
#define GBB_SEARCH_STRIDE 4
|
|
static GoogleBinaryBlockHeader *FindGbbHeader(uint8_t *ptr, size_t size)
|
|
{
|
|
size_t i;
|
|
GoogleBinaryBlockHeader *tmp, *gbb_header = NULL;
|
|
int count = 0;
|
|
|
|
for (i = 0; i <= size - GBB_SEARCH_STRIDE; i += GBB_SEARCH_STRIDE) {
|
|
if (0 != memcmp(ptr + i, GBB_SIGNATURE, GBB_SIGNATURE_SIZE))
|
|
continue;
|
|
|
|
/* Found something. See if it's any good. */
|
|
tmp = (GoogleBinaryBlockHeader *) (ptr + i);
|
|
if (futil_valid_gbb_header(tmp, size - i, NULL))
|
|
if (!count++)
|
|
gbb_header = tmp;
|
|
}
|
|
|
|
switch (count) {
|
|
case 0:
|
|
errorcnt++;
|
|
return NULL;
|
|
case 1:
|
|
return gbb_header;
|
|
default:
|
|
fprintf(stderr, "ERROR: multiple GBB headers found\n");
|
|
errorcnt++;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static uint8_t *create_gbb(const char *desc, off_t *sizeptr)
|
|
{
|
|
char *str, *sizes, *param, *e = NULL;
|
|
size_t size = GBB_HEADER_SIZE;
|
|
int i = 0;
|
|
/* Danger Will Robinson! four entries ==> four paramater blocks */
|
|
uint32_t val[] = { 0, 0, 0, 0 };
|
|
uint8_t *buf;
|
|
GoogleBinaryBlockHeader *gbb;
|
|
|
|
sizes = strdup(desc);
|
|
if (!sizes) {
|
|
errorcnt++;
|
|
fprintf(stderr, "ERROR: strdup() failed: %s\n",
|
|
strerror(errno));
|
|
return NULL;
|
|
}
|
|
|
|
for (str = sizes; (param = strtok(str, ", ")) != NULL; str = NULL) {
|
|
val[i] = (uint32_t) strtoul(param, &e, 0);
|
|
if (e && *e) {
|
|
errorcnt++;
|
|
fprintf(stderr,
|
|
"ERROR: invalid creation parameter: \"%s\"\n",
|
|
param);
|
|
free(sizes);
|
|
return NULL;
|
|
}
|
|
size += val[i++];
|
|
if (i > ARRAY_SIZE(val))
|
|
break;
|
|
}
|
|
|
|
buf = (uint8_t *) calloc(1, size);
|
|
if (!buf) {
|
|
errorcnt++;
|
|
fprintf(stderr, "ERROR: can't malloc %zu bytes: %s\n",
|
|
size, strerror(errno));
|
|
free(sizes);
|
|
return NULL;
|
|
} else if (sizeptr) {
|
|
*sizeptr = size;
|
|
}
|
|
|
|
gbb = (GoogleBinaryBlockHeader *) buf;
|
|
memcpy(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE);
|
|
gbb->major_version = GBB_MAJOR_VER;
|
|
gbb->minor_version = GBB_MINOR_VER;
|
|
gbb->header_size = GBB_HEADER_SIZE;
|
|
gbb->flags = 0;
|
|
|
|
i = GBB_HEADER_SIZE;
|
|
gbb->hwid_offset = i;
|
|
gbb->hwid_size = val[0];
|
|
i += val[0];
|
|
|
|
gbb->rootkey_offset = i;
|
|
gbb->rootkey_size = val[1];
|
|
i += val[1];
|
|
|
|
gbb->bmpfv_offset = i;
|
|
gbb->bmpfv_size = val[2];
|
|
i += val[2];
|
|
|
|
gbb->recovery_key_offset = i;
|
|
gbb->recovery_key_size = val[3];
|
|
i += val[1];
|
|
|
|
free(sizes);
|
|
return buf;
|
|
}
|
|
|
|
static uint8_t *read_entire_file(const char *filename, off_t *sizeptr)
|
|
{
|
|
FILE *fp = NULL;
|
|
uint8_t *buf = NULL;
|
|
struct stat sb;
|
|
|
|
fp = fopen(filename, "rb");
|
|
if (!fp) {
|
|
fprintf(stderr, "ERROR: Unable to open %s for reading: %s\n",
|
|
filename, strerror(errno));
|
|
goto fail;
|
|
}
|
|
|
|
if (0 != fstat(fileno(fp), &sb)) {
|
|
fprintf(stderr, "ERROR: can't fstat %s: %s\n",
|
|
filename, strerror(errno));
|
|
goto fail;
|
|
}
|
|
if (sizeptr)
|
|
*sizeptr = sb.st_size;
|
|
|
|
buf = (uint8_t *) malloc(sb.st_size);
|
|
if (!buf) {
|
|
fprintf(stderr, "ERROR: can't malloc %" PRIi64 " bytes: %s\n",
|
|
sb.st_size, strerror(errno));
|
|
goto fail;
|
|
}
|
|
|
|
if (1 != fread(buf, sb.st_size, 1, fp)) {
|
|
fprintf(stderr, "ERROR: Unable to read from %s: %s\n",
|
|
filename, strerror(errno));
|
|
goto fail;
|
|
}
|
|
|
|
if (fp && 0 != fclose(fp)) {
|
|
fprintf(stderr, "ERROR: Unable to close %s: %s\n",
|
|
filename, strerror(errno));
|
|
goto fail;
|
|
}
|
|
|
|
return buf;
|
|
|
|
fail:
|
|
errorcnt++;
|
|
|
|
if (buf)
|
|
free(buf);
|
|
|
|
if (fp && 0 != fclose(fp))
|
|
fprintf(stderr, "ERROR: Unable to close %s: %s\n",
|
|
filename, strerror(errno));
|
|
return NULL;
|
|
}
|
|
|
|
static int write_to_file(const char *msg, const char *filename,
|
|
uint8_t *start, size_t size)
|
|
{
|
|
FILE *fp;
|
|
int r = 0;
|
|
|
|
fp = fopen(filename, "wb");
|
|
if (!fp) {
|
|
fprintf(stderr, "ERROR: Unable to open %s for writing: %s\n",
|
|
filename, strerror(errno));
|
|
errorcnt++;
|
|
return errno;
|
|
}
|
|
|
|
/* Don't write zero bytes */
|
|
if (size && 1 != fwrite(start, size, 1, fp)) {
|
|
fprintf(stderr, "ERROR: Unable to write to %s: %s\n",
|
|
filename, strerror(errno));
|
|
errorcnt++;
|
|
r = errno;
|
|
}
|
|
|
|
if (0 != fclose(fp)) {
|
|
fprintf(stderr, "ERROR: Unable to close %s: %s\n",
|
|
filename, strerror(errno));
|
|
errorcnt++;
|
|
if (!r)
|
|
r = errno;
|
|
}
|
|
|
|
if (!r && msg)
|
|
printf("%s %s\n", msg, filename);
|
|
|
|
return r;
|
|
}
|
|
|
|
static int read_from_file(const char *msg, const char *filename,
|
|
uint8_t *start, uint32_t size)
|
|
{
|
|
FILE *fp;
|
|
struct stat sb;
|
|
size_t count;
|
|
int r = 0;
|
|
|
|
fp = fopen(filename, "rb");
|
|
if (!fp) {
|
|
fprintf(stderr, "ERROR: Unable to open %s for reading: %s\n",
|
|
filename, strerror(errno));
|
|
errorcnt++;
|
|
return errno;
|
|
}
|
|
|
|
if (0 != fstat(fileno(fp), &sb)) {
|
|
fprintf(stderr, "ERROR: can't fstat %s: %s\n",
|
|
filename, strerror(errno));
|
|
errorcnt++;
|
|
r = errno;
|
|
goto done_close;
|
|
}
|
|
|
|
if (sb.st_size > size) {
|
|
fprintf(stderr,
|
|
"ERROR: file %s exceeds capacity (%" PRIu32 ")\n",
|
|
filename, size);
|
|
errorcnt++;
|
|
r = errno;
|
|
goto done_close;
|
|
}
|
|
|
|
/* Wipe existing data. */
|
|
memset(start, 0, size);
|
|
|
|
/* It's okay if we read less than size. That's just the max. */
|
|
count = fread(start, 1, size, fp);
|
|
if (ferror(fp)) {
|
|
fprintf(stderr,
|
|
"ERROR: Read %zu/%" PRIi64 " bytes from %s: %s\n",
|
|
count, sb.st_size, filename, strerror(errno));
|
|
errorcnt++;
|
|
r = errno;
|
|
}
|
|
|
|
done_close:
|
|
if (0 != fclose(fp)) {
|
|
fprintf(stderr, "ERROR: Unable to close %s: %s\n",
|
|
filename, strerror(errno));
|
|
errorcnt++;
|
|
if (!r)
|
|
r = errno;
|
|
}
|
|
|
|
if (!r && msg)
|
|
printf(" - import %s from %s: success\n", msg, filename);
|
|
|
|
return r;
|
|
}
|
|
|
|
static int do_gbb_utility(int argc, char *argv[])
|
|
{
|
|
enum do_what_now { DO_GET, DO_SET, DO_CREATE } mode = DO_GET;
|
|
char *infile = NULL;
|
|
char *outfile = NULL;
|
|
char *opt_create = NULL;
|
|
char *opt_rootkey = NULL;
|
|
char *opt_bmpfv = NULL;
|
|
char *opt_recoverykey = NULL;
|
|
char *opt_hwid = NULL;
|
|
char *opt_flags = NULL;
|
|
int sel_hwid = 0;
|
|
int sel_digest = 0;
|
|
int sel_flags = 0;
|
|
int sel_roothash = 0;
|
|
uint8_t *inbuf = NULL;
|
|
off_t filesize;
|
|
uint8_t *outbuf = NULL;
|
|
GoogleBinaryBlockHeader *gbb;
|
|
uint8_t *gbb_base;
|
|
int i;
|
|
|
|
opterr = 0; /* quiet, you */
|
|
while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
|
|
switch (i) {
|
|
case 'g':
|
|
mode = DO_GET;
|
|
opt_has_arg("flags", 0);
|
|
opt_has_arg("hwid", 0);
|
|
break;
|
|
case 's':
|
|
mode = DO_SET;
|
|
opt_has_arg("flags", 1);
|
|
opt_has_arg("hwid", 1);
|
|
break;
|
|
case 'c':
|
|
mode = DO_CREATE;
|
|
opt_create = optarg;
|
|
break;
|
|
case 'o':
|
|
outfile = optarg;
|
|
break;
|
|
case 'k':
|
|
opt_rootkey = optarg;
|
|
break;
|
|
case 'b':
|
|
opt_bmpfv = optarg;
|
|
break;
|
|
case 'r':
|
|
opt_recoverykey = optarg;
|
|
break;
|
|
case OPT_HWID:
|
|
/* --hwid is optional: null might be okay */
|
|
opt_hwid = optarg;
|
|
sel_hwid = 1;
|
|
break;
|
|
case OPT_FLAGS:
|
|
/* --flags is optional: null might be okay */
|
|
opt_flags = optarg;
|
|
sel_flags = 1;
|
|
break;
|
|
case OPT_DIGEST:
|
|
sel_digest = 1;
|
|
break;
|
|
case OPT_ROOTHASH:
|
|
sel_roothash = 1;
|
|
break;
|
|
case OPT_HELP:
|
|
print_help(argc, argv);
|
|
return !!errorcnt;
|
|
|
|
case '?':
|
|
errorcnt++;
|
|
if (optopt)
|
|
fprintf(stderr,
|
|
"ERROR: unrecognized option: -%c\n",
|
|
optopt);
|
|
else if (argv[optind - 1])
|
|
fprintf(stderr,
|
|
"ERROR: unrecognized option "
|
|
"(possibly \"%s\")\n",
|
|
argv[optind - 1]);
|
|
else
|
|
fprintf(stderr, "ERROR: unrecognized option\n");
|
|
break;
|
|
case ':':
|
|
errorcnt++;
|
|
if (argv[optind - 1])
|
|
fprintf(stderr,
|
|
"ERROR: missing argument to -%c (%s)\n",
|
|
optopt, argv[optind - 1]);
|
|
else
|
|
fprintf(stderr,
|
|
"ERROR: missing argument to -%c\n",
|
|
optopt);
|
|
break;
|
|
default:
|
|
errorcnt++;
|
|
fprintf(stderr,
|
|
"ERROR: error while parsing options\n");
|
|
}
|
|
}
|
|
|
|
/* Problems? */
|
|
if (errorcnt) {
|
|
print_help(argc, argv);
|
|
return 1;
|
|
}
|
|
|
|
/* Now try to do something */
|
|
switch (mode) {
|
|
case DO_GET:
|
|
if (argc - optind < 1) {
|
|
fprintf(stderr, "\nERROR: missing input filename\n");
|
|
print_help(argc, argv);
|
|
return 1;
|
|
} else {
|
|
infile = argv[optind++];
|
|
}
|
|
|
|
/* With no args, show the HWID */
|
|
if (!opt_rootkey && !opt_bmpfv && !opt_recoverykey
|
|
&& !sel_flags && !sel_digest)
|
|
sel_hwid = 1;
|
|
|
|
inbuf = read_entire_file(infile, &filesize);
|
|
if (!inbuf)
|
|
break;
|
|
|
|
gbb = FindGbbHeader(inbuf, filesize);
|
|
if (!gbb) {
|
|
fprintf(stderr, "ERROR: No GBB found in %s\n", infile);
|
|
break;
|
|
}
|
|
gbb_base = (uint8_t *) gbb;
|
|
|
|
/* Get the stuff */
|
|
if (sel_hwid)
|
|
printf("hardware_id: %s\n",
|
|
gbb->hwid_size ? (char *)(gbb_base +
|
|
gbb->
|
|
hwid_offset) : "");
|
|
if (sel_digest)
|
|
print_hwid_digest(gbb, "digest: ", "\n");
|
|
|
|
if (sel_roothash)
|
|
verify_ryu_root_header(inbuf, filesize, gbb);
|
|
|
|
if (sel_flags)
|
|
printf("flags: 0x%08x\n", gbb->flags);
|
|
if (opt_rootkey)
|
|
write_to_file(" - exported root_key to file:",
|
|
opt_rootkey,
|
|
gbb_base + gbb->rootkey_offset,
|
|
gbb->rootkey_size);
|
|
if (opt_bmpfv)
|
|
write_to_file(" - exported bmp_fv to file:", opt_bmpfv,
|
|
gbb_base + gbb->bmpfv_offset,
|
|
gbb->bmpfv_size);
|
|
if (opt_recoverykey)
|
|
write_to_file(" - exported recovery_key to file:",
|
|
opt_recoverykey,
|
|
gbb_base + gbb->recovery_key_offset,
|
|
gbb->recovery_key_size);
|
|
break;
|
|
|
|
case DO_SET:
|
|
if (argc - optind < 1) {
|
|
fprintf(stderr, "\nERROR: missing input filename\n");
|
|
print_help(argc, argv);
|
|
return 1;
|
|
}
|
|
infile = argv[optind++];
|
|
if (!outfile)
|
|
outfile = (argc - optind < 1) ? infile : argv[optind++];
|
|
|
|
if (sel_hwid && !opt_hwid) {
|
|
fprintf(stderr, "\nERROR: missing new HWID value\n");
|
|
print_help(argc, argv);
|
|
return 1;
|
|
}
|
|
if (sel_flags && (!opt_flags || !*opt_flags)) {
|
|
fprintf(stderr, "\nERROR: missing new flags value\n");
|
|
print_help(argc, argv);
|
|
return 1;
|
|
}
|
|
|
|
/* With no args, we'll either copy it unchanged or do nothing */
|
|
inbuf = read_entire_file(infile, &filesize);
|
|
if (!inbuf)
|
|
break;
|
|
|
|
gbb = FindGbbHeader(inbuf, filesize);
|
|
if (!gbb) {
|
|
fprintf(stderr, "ERROR: No GBB found in %s\n", infile);
|
|
break;
|
|
}
|
|
gbb_base = (uint8_t *) gbb;
|
|
|
|
outbuf = (uint8_t *) malloc(filesize);
|
|
if (!outbuf) {
|
|
errorcnt++;
|
|
fprintf(stderr,
|
|
"ERROR: can't malloc %" PRIi64 " bytes: %s\n",
|
|
filesize, strerror(errno));
|
|
break;
|
|
}
|
|
|
|
/* Switch pointers to outbuf */
|
|
memcpy(outbuf, inbuf, filesize);
|
|
gbb = FindGbbHeader(outbuf, filesize);
|
|
if (!gbb) {
|
|
fprintf(stderr,
|
|
"INTERNAL ERROR: No GBB found in outbuf\n");
|
|
exit(1);
|
|
}
|
|
gbb_base = (uint8_t *) gbb;
|
|
|
|
if (opt_hwid) {
|
|
if (strlen(opt_hwid) + 1 > gbb->hwid_size) {
|
|
fprintf(stderr,
|
|
"ERROR: null-terminated HWID"
|
|
" exceeds capacity (%d)\n",
|
|
gbb->hwid_size);
|
|
errorcnt++;
|
|
} else {
|
|
/* Wipe data before writing new value. */
|
|
memset(gbb_base + gbb->hwid_offset, 0,
|
|
gbb->hwid_size);
|
|
strcpy((char *)(gbb_base + gbb->hwid_offset),
|
|
opt_hwid);
|
|
update_hwid_digest(gbb);
|
|
}
|
|
}
|
|
|
|
if (opt_flags) {
|
|
char *e = NULL;
|
|
uint32_t val;
|
|
val = (uint32_t) strtoul(opt_flags, &e, 0);
|
|
if (e && *e) {
|
|
fprintf(stderr,
|
|
"ERROR: invalid flags value: %s\n",
|
|
opt_flags);
|
|
errorcnt++;
|
|
} else {
|
|
gbb->flags = val;
|
|
}
|
|
}
|
|
|
|
if (opt_rootkey) {
|
|
read_from_file("root_key", opt_rootkey,
|
|
gbb_base + gbb->rootkey_offset,
|
|
gbb->rootkey_size);
|
|
|
|
if (fill_ryu_root_header(outbuf, filesize, gbb))
|
|
errorcnt++;
|
|
}
|
|
if (opt_bmpfv)
|
|
read_from_file("bmp_fv", opt_bmpfv,
|
|
gbb_base + gbb->bmpfv_offset,
|
|
gbb->bmpfv_size);
|
|
if (opt_recoverykey)
|
|
read_from_file("recovery_key", opt_recoverykey,
|
|
gbb_base + gbb->recovery_key_offset,
|
|
gbb->recovery_key_size);
|
|
|
|
/* Write it out if there are no problems. */
|
|
if (!errorcnt)
|
|
write_to_file("successfully saved new image to:",
|
|
outfile, outbuf, filesize);
|
|
|
|
break;
|
|
|
|
case DO_CREATE:
|
|
if (!outfile) {
|
|
if (argc - optind < 1) {
|
|
fprintf(stderr,
|
|
"\nERROR: missing output filename\n");
|
|
print_help(argc, argv);
|
|
return 1;
|
|
}
|
|
outfile = argv[optind++];
|
|
}
|
|
/* Parse the creation args */
|
|
outbuf = create_gbb(opt_create, &filesize);
|
|
if (!outbuf) {
|
|
fprintf(stderr,
|
|
"\nERROR: unable to parse creation spec (%s)\n",
|
|
opt_create);
|
|
print_help(argc, argv);
|
|
return 1;
|
|
}
|
|
if (!errorcnt)
|
|
write_to_file("successfully created new GBB to:",
|
|
outfile, outbuf, filesize);
|
|
break;
|
|
}
|
|
|
|
if (inbuf)
|
|
free(inbuf);
|
|
if (outbuf)
|
|
free(outbuf);
|
|
return !!errorcnt;
|
|
}
|
|
|
|
DECLARE_FUTIL_COMMAND(gbb_utility, do_gbb_utility, VBOOT_VERSION_ALL,
|
|
"Manipulate the Google Binary Block (GBB)");
|