mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-26 11:15:13 +00:00
futility: Reformat to use kernel coding style
This just reformats the futility sources to conform to the Linux kernel coding style. No functional changes. BUG=chromium:224734 BRANCH=ToT TEST=make runtests Change-Id: I82df07dd3f8be2ad2f3df24cebe00a9a378b13f4 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/213915 Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
8f15d74fd6
commit
31d95c2386
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <inttypes.h> /* For PRIu64 */
|
#include <inttypes.h> /* For PRIu64 */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -23,336 +23,351 @@
|
|||||||
#include "kernel_blob.h"
|
#include "kernel_blob.h"
|
||||||
#include "vboot_common.h"
|
#include "vboot_common.h"
|
||||||
|
|
||||||
|
|
||||||
/* Global opt */
|
/* Global opt */
|
||||||
static int opt_debug = 0;
|
static int opt_debug = 0;
|
||||||
|
|
||||||
/* Command line options */
|
/* Command line options */
|
||||||
enum {
|
enum {
|
||||||
OPT_MODE_SIGN = 1000,
|
OPT_MODE_SIGN = 1000,
|
||||||
OPT_MODE_VERIFY,
|
OPT_MODE_VERIFY,
|
||||||
OPT_KEYBLOCK,
|
OPT_KEYBLOCK,
|
||||||
OPT_SIGNPRIVATE,
|
OPT_SIGNPRIVATE,
|
||||||
OPT_VBLOCK,
|
OPT_VBLOCK,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option long_opts[] = {
|
static const struct option long_opts[] = {
|
||||||
{"sign", 1, 0, OPT_MODE_SIGN },
|
{"sign", 1, 0, OPT_MODE_SIGN},
|
||||||
{"verify", 1, 0, OPT_MODE_VERIFY },
|
{"verify", 1, 0, OPT_MODE_VERIFY},
|
||||||
{"keyblock", 1, 0, OPT_KEYBLOCK },
|
{"keyblock", 1, 0, OPT_KEYBLOCK},
|
||||||
{"signprivate", 1, 0, OPT_SIGNPRIVATE },
|
{"signprivate", 1, 0, OPT_SIGNPRIVATE},
|
||||||
{"vblock", 1, 0, OPT_VBLOCK },
|
{"vblock", 1, 0, OPT_VBLOCK},
|
||||||
{"debug", 0, &opt_debug, 1 },
|
{"debug", 0, &opt_debug, 1},
|
||||||
{NULL, 0, 0, 0}
|
{NULL, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Print help and return error */
|
/* Print help and return error */
|
||||||
static int PrintHelp(const char *progname) {
|
static int PrintHelp(const char *progname)
|
||||||
fprintf(stderr,
|
{
|
||||||
"This program is used to sign and verify developer-mode files\n");
|
fprintf(stderr,
|
||||||
fprintf(stderr,
|
"This is used to sign and verify developer-mode files\n");
|
||||||
"\n"
|
fprintf(stderr,
|
||||||
"Usage: %s --sign <file> [PARAMETERS]\n"
|
"\n"
|
||||||
"\n"
|
"Usage: %s --sign <file> [PARAMETERS]\n"
|
||||||
" Required parameters:\n"
|
"\n"
|
||||||
" --keyblock <file> Key block in .keyblock format\n"
|
" Required parameters:\n"
|
||||||
" --signprivate <file>"
|
" --keyblock <file> Key block in .keyblock format\n"
|
||||||
" Private key to sign file data, in .vbprivk format\n"
|
" --signprivate <file>"
|
||||||
" --vblock <file> Output signature in .vblock format\n"
|
" Private key to sign file data, in .vbprivk format\n"
|
||||||
"\n",
|
" --vblock <file>"
|
||||||
progname);
|
" Output signature in .vblock format\n"
|
||||||
fprintf(stderr,
|
"\n", progname);
|
||||||
"OR\n\n"
|
fprintf(stderr,
|
||||||
"Usage: %s --verify <file> [PARAMETERS]\n"
|
"OR\n\n"
|
||||||
"\n"
|
"Usage: %s --verify <file> [PARAMETERS]\n"
|
||||||
" Required parameters:\n"
|
"\n"
|
||||||
" --vblock <file> Signature file in .vblock format\n"
|
" Required parameters:\n"
|
||||||
"\n"
|
" --vblock <file>"
|
||||||
" Optional parameters:\n"
|
" Signature file in .vblock format\n"
|
||||||
" --keyblock <file>"
|
"\n"
|
||||||
" Extract .keyblock to file if verification succeeds\n"
|
" Optional parameters:\n"
|
||||||
"\n",
|
" --keyblock <file>"
|
||||||
progname);
|
" Extract .keyblock to file if verification succeeds\n"
|
||||||
return 1;
|
"\n", progname);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Debug(const char *format, ...) {
|
static void Debug(const char *format, ...)
|
||||||
if (!opt_debug)
|
{
|
||||||
return;
|
if (!opt_debug)
|
||||||
|
return;
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
fprintf(stderr, "DEBUG: ");
|
fprintf(stderr, "DEBUG: ");
|
||||||
vfprintf(stderr, format, ap);
|
vfprintf(stderr, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Sign a file. We'll reuse the same structs used to sign kernels, to avoid
|
/* Sign a file. We'll reuse the same structs used to sign kernels, to avoid
|
||||||
having to declare yet another one for just this purpose. */
|
having to declare yet another one for just this purpose. */
|
||||||
static int Sign(const char* filename, const char* keyblock_file,
|
static int Sign(const char *filename, const char *keyblock_file,
|
||||||
const char* signprivate_file, const char* outfile) {
|
const char *signprivate_file, const char *outfile)
|
||||||
uint8_t* file_data;
|
{
|
||||||
uint64_t file_size;
|
uint8_t *file_data;
|
||||||
VbKeyBlockHeader* key_block;
|
uint64_t file_size;
|
||||||
uint64_t key_block_size;
|
VbKeyBlockHeader *key_block;
|
||||||
VbPrivateKey* signing_key;
|
uint64_t key_block_size;
|
||||||
VbSignature* body_sig;
|
VbPrivateKey *signing_key;
|
||||||
VbKernelPreambleHeader* preamble;
|
VbSignature *body_sig;
|
||||||
FILE* output_fp;
|
VbKernelPreambleHeader *preamble;
|
||||||
|
FILE *output_fp;
|
||||||
|
|
||||||
/* Read the file that we're going to sign. */
|
/* Read the file that we're going to sign. */
|
||||||
file_data = ReadFile(filename, &file_size);
|
file_data = ReadFile(filename, &file_size);
|
||||||
if (!file_data) {
|
if (!file_data) {
|
||||||
VbExError("Error reading file to sign.\n");
|
VbExError("Error reading file to sign.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the key block and read the private key corresponding to it. */
|
/* Get the key block and read the private key corresponding to it. */
|
||||||
key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
|
key_block =
|
||||||
if (!key_block) {
|
(VbKeyBlockHeader *) ReadFile(keyblock_file, &key_block_size);
|
||||||
VbExError("Error reading key block.\n");
|
if (!key_block) {
|
||||||
return 1;
|
VbExError("Error reading key block.\n");
|
||||||
}
|
return 1;
|
||||||
signing_key = PrivateKeyRead(signprivate_file);
|
}
|
||||||
if (!signing_key) {
|
signing_key = PrivateKeyRead(signprivate_file);
|
||||||
VbExError("Error reading signing key.\n");
|
if (!signing_key) {
|
||||||
return 1;
|
VbExError("Error reading signing key.\n");
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Sign the file data */
|
/* Sign the file data */
|
||||||
body_sig = CalculateSignature(file_data, file_size, signing_key);
|
body_sig = CalculateSignature(file_data, file_size, signing_key);
|
||||||
if (!body_sig) {
|
if (!body_sig) {
|
||||||
VbExError("Error calculating body signature\n");
|
VbExError("Error calculating body signature\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create preamble */
|
/* Create preamble */
|
||||||
preamble = CreateKernelPreamble((uint64_t)0,
|
preamble = CreateKernelPreamble((uint64_t) 0,
|
||||||
(uint64_t)0,
|
(uint64_t) 0,
|
||||||
(uint64_t)0,
|
(uint64_t) 0,
|
||||||
(uint64_t)0,
|
(uint64_t) 0,
|
||||||
body_sig,
|
body_sig, (uint64_t) 0, signing_key);
|
||||||
(uint64_t)0,
|
if (!preamble) {
|
||||||
signing_key);
|
VbExError("Error creating preamble.\n");
|
||||||
if (!preamble) {
|
return 1;
|
||||||
VbExError("Error creating preamble.\n");
|
}
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the output file */
|
/* Write the output file */
|
||||||
Debug("writing %s...\n", outfile);
|
Debug("writing %s...\n", outfile);
|
||||||
output_fp = fopen(outfile, "wb");
|
output_fp = fopen(outfile, "wb");
|
||||||
if (!output_fp) {
|
if (!output_fp) {
|
||||||
VbExError("Can't open output file %s\n", outfile);
|
VbExError("Can't open output file %s\n", outfile);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size);
|
Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size);
|
||||||
Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size);
|
Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size);
|
||||||
if ((1 != fwrite(key_block, key_block_size, 1, output_fp)) ||
|
if ((1 != fwrite(key_block, key_block_size, 1, output_fp)) ||
|
||||||
(1 != fwrite(preamble, preamble->preamble_size, 1, output_fp))) {
|
(1 != fwrite(preamble, preamble->preamble_size, 1, output_fp))) {
|
||||||
VbExError("Can't write output file %s\n", outfile);
|
VbExError("Can't write output file %s\n", outfile);
|
||||||
fclose(output_fp);
|
fclose(output_fp);
|
||||||
unlink(outfile);
|
unlink(outfile);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fclose(output_fp);
|
fclose(output_fp);
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
free(preamble);
|
free(preamble);
|
||||||
free(body_sig);
|
free(body_sig);
|
||||||
free(signing_key);
|
free(signing_key);
|
||||||
free(key_block);
|
free(key_block);
|
||||||
free(file_data);
|
free(file_data);
|
||||||
|
|
||||||
/* Success */
|
/* Success */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Verify(const char* filename, const char* vblock_file,
|
static int Verify(const char *filename, const char *vblock_file,
|
||||||
const char* keyblock_file) {
|
const char *keyblock_file)
|
||||||
uint8_t* file_data;
|
{
|
||||||
uint64_t file_size;
|
uint8_t *file_data;
|
||||||
uint8_t* buf;
|
uint64_t file_size;
|
||||||
uint64_t buf_size;
|
uint8_t *buf;
|
||||||
VbKeyBlockHeader* key_block;
|
uint64_t buf_size;
|
||||||
VbKernelPreambleHeader* preamble;
|
VbKeyBlockHeader *key_block;
|
||||||
VbPublicKey* data_key;
|
VbKernelPreambleHeader *preamble;
|
||||||
RSAPublicKey* rsa;
|
VbPublicKey *data_key;
|
||||||
uint64_t current_buf_offset = 0;
|
RSAPublicKey *rsa;
|
||||||
|
uint64_t current_buf_offset = 0;
|
||||||
|
|
||||||
/* Read the file that we're going to verify. */
|
/* Read the file that we're going to verify. */
|
||||||
file_data = ReadFile(filename, &file_size);
|
file_data = ReadFile(filename, &file_size);
|
||||||
if (!file_data) {
|
if (!file_data) {
|
||||||
VbExError("Error reading file to sign.\n");
|
VbExError("Error reading file to sign.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the vblock that we're going to use on it */
|
/* Read the vblock that we're going to use on it */
|
||||||
buf = ReadFile(vblock_file, &buf_size);
|
buf = ReadFile(vblock_file, &buf_size);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
VbExError("Error reading vblock_file.\n");
|
VbExError("Error reading vblock_file.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the key block */
|
/* Find the key block */
|
||||||
key_block = (VbKeyBlockHeader*)buf;
|
key_block = (VbKeyBlockHeader *) buf;
|
||||||
Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
|
Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
|
||||||
current_buf_offset += key_block->key_block_size;
|
current_buf_offset += key_block->key_block_size;
|
||||||
if (current_buf_offset > buf_size) {
|
if (current_buf_offset > buf_size) {
|
||||||
VbExError("key_block_size advances past the end of the buffer\n");
|
VbExError
|
||||||
return 1;
|
("key_block_size advances past the end of the buffer\n");
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find the preamble */
|
/* Find the preamble */
|
||||||
preamble = (VbKernelPreambleHeader*)(buf + current_buf_offset);
|
preamble = (VbKernelPreambleHeader *) (buf + current_buf_offset);
|
||||||
Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
|
Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
|
||||||
current_buf_offset += preamble->preamble_size;
|
current_buf_offset += preamble->preamble_size;
|
||||||
if (current_buf_offset > buf_size ) {
|
if (current_buf_offset > buf_size) {
|
||||||
VbExError("preamble_size advances past the end of the buffer\n");
|
VbExError
|
||||||
return 1;
|
("preamble_size advances past the end of the buffer\n");
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
Debug("Current buf offset is at 0x%" PRIx64 " bytes\n", current_buf_offset);
|
Debug("Current buf offset is at 0x%" PRIx64 " bytes\n",
|
||||||
|
current_buf_offset);
|
||||||
|
|
||||||
/* Check the key block (hash only) */
|
/* Check the key block (hash only) */
|
||||||
if (0 != KeyBlockVerify(key_block, key_block->key_block_size, NULL, 1)) {
|
if (0 != KeyBlockVerify(key_block, key_block->key_block_size,
|
||||||
VbExError("Error verifying key block.\n");
|
NULL, 1)) {
|
||||||
return 1;
|
VbExError("Error verifying key block.\n");
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
printf("Key block:\n");
|
printf("Key block:\n");
|
||||||
data_key = &key_block->data_key;
|
data_key = &key_block->data_key;
|
||||||
printf(" Size: 0x%" PRIx64 "\n", key_block->key_block_size);
|
printf(" Size: 0x%" PRIx64 "\n",
|
||||||
printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
|
key_block->key_block_size);
|
||||||
(data_key->algorithm < kNumAlgorithms ?
|
printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
|
||||||
algo_strings[data_key->algorithm] : "(invalid)"));
|
(data_key->algorithm <
|
||||||
printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
|
kNumAlgorithms ? algo_strings[data_key->
|
||||||
printf(" Flags: %" PRIu64 "\n", key_block->key_block_flags);
|
algorithm] : "(invalid)"));
|
||||||
|
printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
|
||||||
|
printf(" Flags: %" PRIu64 "\n",
|
||||||
|
key_block->key_block_flags);
|
||||||
|
|
||||||
|
/* Verify preamble */
|
||||||
|
rsa = PublicKeyToRSA(&key_block->data_key);
|
||||||
|
if (!rsa) {
|
||||||
|
VbExError("Error parsing data key.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (0 != VerifyKernelPreamble(preamble, preamble->preamble_size, rsa)) {
|
||||||
|
VbExError("Error verifying preamble.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Verify preamble */
|
printf("Preamble:\n");
|
||||||
rsa = PublicKeyToRSA(&key_block->data_key);
|
printf(" Size: 0x%" PRIx64 "\n",
|
||||||
if (!rsa) {
|
preamble->preamble_size);
|
||||||
VbExError("Error parsing data key.\n");
|
printf(" Header version: %" PRIu32 ".%" PRIu32 "\n",
|
||||||
return 1;
|
preamble->header_version_major, preamble->header_version_minor);
|
||||||
}
|
printf(" Kernel version: %" PRIu64 "\n",
|
||||||
if (0 != VerifyKernelPreamble(preamble, preamble->preamble_size, rsa)) {
|
preamble->kernel_version);
|
||||||
VbExError("Error verifying preamble.\n");
|
printf(" Body load address: 0x%" PRIx64 "\n",
|
||||||
return 1;
|
preamble->body_load_address);
|
||||||
}
|
printf(" Body size: 0x%" PRIx64 "\n",
|
||||||
|
preamble->body_signature.data_size);
|
||||||
|
printf(" Bootloader address: 0x%" PRIx64 "\n",
|
||||||
|
preamble->bootloader_address);
|
||||||
|
printf(" Bootloader size: 0x%" PRIx64 "\n",
|
||||||
|
preamble->bootloader_size);
|
||||||
|
|
||||||
printf("Preamble:\n");
|
/* Verify body */
|
||||||
printf(" Size: 0x%" PRIx64 "\n", preamble->preamble_size);
|
if (0 !=
|
||||||
printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
|
VerifyData(file_data, file_size, &preamble->body_signature, rsa)) {
|
||||||
preamble->header_version_major, preamble->header_version_minor);
|
VbExError("Error verifying kernel body.\n");
|
||||||
printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version);
|
return 1;
|
||||||
printf(" Body load address: 0x%" PRIx64 "\n", preamble->body_load_address);
|
}
|
||||||
printf(" Body size: 0x%" PRIx64 "\n",
|
printf("Body verification succeeded.\n");
|
||||||
preamble->body_signature.data_size);
|
|
||||||
printf(" Bootloader address: 0x%" PRIx64 "\n",
|
|
||||||
preamble->bootloader_address);
|
|
||||||
printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size);
|
|
||||||
|
|
||||||
/* Verify body */
|
if (keyblock_file) {
|
||||||
if (0 != VerifyData(file_data, file_size, &preamble->body_signature, rsa)) {
|
if (0 !=
|
||||||
VbExError("Error verifying kernel body.\n");
|
WriteFile(keyblock_file, key_block,
|
||||||
return 1;
|
key_block->key_block_size)) {
|
||||||
}
|
VbExError("Unable to export keyblock file\n");
|
||||||
printf("Body verification succeeded.\n");
|
return 1;
|
||||||
|
}
|
||||||
|
printf("Key block exported to %s\n", keyblock_file);
|
||||||
|
}
|
||||||
|
|
||||||
if (keyblock_file) {
|
return 0;
|
||||||
if (0 != WriteFile(keyblock_file, key_block, key_block->key_block_size)) {
|
|
||||||
VbExError("Unable to export keyblock file\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printf("Key block exported to %s\n", keyblock_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_dev_sign_file(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *filename = NULL;
|
||||||
|
char *keyblock_file = NULL;
|
||||||
|
char *signprivate_file = NULL;
|
||||||
|
char *vblock_file = NULL;
|
||||||
|
int mode = 0;
|
||||||
|
int parse_error = 0;
|
||||||
|
int option_index;
|
||||||
|
|
||||||
static int do_dev_sign_file(int argc, char* argv[]) {
|
char *progname = strrchr(argv[0], '/');
|
||||||
char* filename = NULL;
|
if (progname)
|
||||||
char* keyblock_file = NULL;
|
progname++;
|
||||||
char* signprivate_file = NULL;
|
else
|
||||||
char* vblock_file = NULL;
|
progname = argv[0];
|
||||||
int mode = 0;
|
|
||||||
int parse_error = 0;
|
|
||||||
int option_index;
|
|
||||||
|
|
||||||
char *progname = strrchr(argv[0], '/');
|
while ((option_index =
|
||||||
if (progname)
|
getopt_long(argc, argv, ":", long_opts, NULL)) != -1
|
||||||
progname++;
|
&& !parse_error) {
|
||||||
else
|
switch (option_index) {
|
||||||
progname = argv[0];
|
default:
|
||||||
|
case '?':
|
||||||
|
/* Unhandled option */
|
||||||
|
parse_error = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
while ((option_index = getopt_long(argc, argv, ":", long_opts, NULL)) != -1 &&
|
case 0:
|
||||||
!parse_error) {
|
/* silently handled option */
|
||||||
switch (option_index) {
|
break;
|
||||||
default:
|
|
||||||
case '?':
|
|
||||||
/* Unhandled option */
|
|
||||||
parse_error = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0:
|
case OPT_MODE_SIGN:
|
||||||
/* silently handled option */
|
case OPT_MODE_VERIFY:
|
||||||
break;
|
if (mode && (mode != option_index)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Only one mode can be specified\n");
|
||||||
|
parse_error = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mode = option_index;
|
||||||
|
filename = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case OPT_MODE_SIGN:
|
case OPT_KEYBLOCK:
|
||||||
case OPT_MODE_VERIFY:
|
keyblock_file = optarg;
|
||||||
if (mode && (mode != option_index)) {
|
break;
|
||||||
fprintf(stderr, "Only a single mode can be specified\n");
|
|
||||||
parse_error = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mode = option_index;
|
|
||||||
filename = optarg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPT_KEYBLOCK:
|
case OPT_SIGNPRIVATE:
|
||||||
keyblock_file = optarg;
|
signprivate_file = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_SIGNPRIVATE:
|
case OPT_VBLOCK:
|
||||||
signprivate_file = optarg;
|
vblock_file = optarg;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case OPT_VBLOCK:
|
if (parse_error)
|
||||||
vblock_file = optarg;
|
return PrintHelp(progname);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parse_error)
|
switch (mode) {
|
||||||
return PrintHelp(progname);
|
case OPT_MODE_SIGN:
|
||||||
|
if (!keyblock_file || !signprivate_file || !vblock_file) {
|
||||||
|
fprintf(stderr, "Some required options are missing\n");
|
||||||
|
return PrintHelp(progname);
|
||||||
|
}
|
||||||
|
return Sign(filename, keyblock_file, signprivate_file,
|
||||||
|
vblock_file);
|
||||||
|
|
||||||
switch(mode) {
|
case OPT_MODE_VERIFY:
|
||||||
case OPT_MODE_SIGN:
|
if (!vblock_file) {
|
||||||
if (!keyblock_file || !signprivate_file || !vblock_file) {
|
fprintf(stderr, "Some required options are missing\n");
|
||||||
fprintf(stderr, "Some required options are missing\n");
|
return PrintHelp(progname);
|
||||||
return PrintHelp(progname);
|
}
|
||||||
}
|
return Verify(filename, vblock_file, keyblock_file);
|
||||||
return Sign(filename, keyblock_file, signprivate_file, vblock_file);
|
|
||||||
|
|
||||||
case OPT_MODE_VERIFY:
|
default:
|
||||||
if (!vblock_file) {
|
fprintf(stderr, "You must specify either --sign or --verify\n");
|
||||||
fprintf(stderr, "Some required options are missing\n");
|
return PrintHelp(progname);
|
||||||
return PrintHelp(progname);
|
}
|
||||||
}
|
|
||||||
return Verify(filename, vblock_file, keyblock_file);
|
|
||||||
|
|
||||||
default:
|
/* NOTREACHED */
|
||||||
fprintf(stderr,
|
return 1;
|
||||||
"You must specify either --sign or --verify\n");
|
|
||||||
return PrintHelp(progname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTREACHED */
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_FUTIL_COMMAND(dev_sign_file, do_dev_sign_file,
|
DECLARE_FUTIL_COMMAND(dev_sign_file, do_dev_sign_file,
|
||||||
|
|||||||
@@ -29,452 +29,459 @@ static void *base_of_rom;
|
|||||||
static size_t size_of_rom;
|
static size_t size_of_rom;
|
||||||
static int opt_gaps = 0;
|
static int opt_gaps = 0;
|
||||||
|
|
||||||
|
|
||||||
/* Return 0 if successful */
|
/* Return 0 if successful */
|
||||||
static int dump_fmap(const void *ptr, int argc, char *argv[])
|
static int dump_fmap(const void *ptr, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i, retval = 0;
|
int i, retval = 0;
|
||||||
char buf[80]; // DWR: magic number
|
char buf[80]; /* DWR: magic number */
|
||||||
const FmapHeader *fmh = (const FmapHeader*)ptr;
|
const FmapHeader *fmh = (const FmapHeader *)ptr;
|
||||||
const FmapAreaHeader *ah = (const FmapAreaHeader*)(ptr + sizeof(FmapHeader));
|
const FmapAreaHeader *ah =
|
||||||
|
(const FmapAreaHeader *)(ptr + sizeof(FmapHeader));
|
||||||
|
|
||||||
if (FMT_NORMAL == opt_format) {
|
if (FMT_NORMAL == opt_format) {
|
||||||
snprintf(buf, FMAP_SIGNATURE_SIZE+1, "%s", fmh->fmap_signature);
|
snprintf(buf, FMAP_SIGNATURE_SIZE + 1, "%s",
|
||||||
printf("fmap_signature %s\n", buf);
|
fmh->fmap_signature);
|
||||||
printf("fmap_version: %d.%d\n",
|
printf("fmap_signature %s\n", buf);
|
||||||
fmh->fmap_ver_major, fmh->fmap_ver_minor);
|
printf("fmap_version: %d.%d\n",
|
||||||
printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base);
|
fmh->fmap_ver_major, fmh->fmap_ver_minor);
|
||||||
printf("fmap_size: 0x%08x (%d)\n", fmh->fmap_size, fmh->fmap_size);
|
printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base);
|
||||||
snprintf(buf, FMAP_NAMELEN+1, "%s", fmh->fmap_name);
|
printf("fmap_size: 0x%08x (%d)\n", fmh->fmap_size,
|
||||||
printf("fmap_name: %s\n", buf);
|
fmh->fmap_size);
|
||||||
printf("fmap_nareas: %d\n", fmh->fmap_nareas);
|
snprintf(buf, FMAP_NAMELEN + 1, "%s", fmh->fmap_name);
|
||||||
}
|
printf("fmap_name: %s\n", buf);
|
||||||
|
printf("fmap_nareas: %d\n", fmh->fmap_nareas);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < fmh->fmap_nareas; i++, ah++) {
|
for (i = 0; i < fmh->fmap_nareas; i++, ah++) {
|
||||||
snprintf(buf, FMAP_NAMELEN+1, "%s", ah->area_name);
|
snprintf(buf, FMAP_NAMELEN + 1, "%s", ah->area_name);
|
||||||
|
|
||||||
if (argc) {
|
if (argc) {
|
||||||
int j, found=0;
|
int j, found = 0;
|
||||||
for (j = 0; j < argc; j++)
|
for (j = 0; j < argc; j++)
|
||||||
if (!strcmp(argv[j], buf)) {
|
if (!strcmp(argv[j], buf)) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (opt_format) {
|
switch (opt_format) {
|
||||||
case FMT_PRETTY:
|
case FMT_PRETTY:
|
||||||
printf("%s %d %d\n", buf, ah->area_offset, ah->area_size);
|
printf("%s %d %d\n", buf, ah->area_offset,
|
||||||
break;
|
ah->area_size);
|
||||||
case FMT_FLASHROM:
|
break;
|
||||||
if (ah->area_size)
|
case FMT_FLASHROM:
|
||||||
printf("0x%08x:0x%08x %s\n", ah->area_offset,
|
if (ah->area_size)
|
||||||
ah->area_offset + ah->area_size - 1, buf);
|
printf("0x%08x:0x%08x %s\n", ah->area_offset,
|
||||||
break;
|
ah->area_offset + ah->area_size - 1,
|
||||||
default:
|
buf);
|
||||||
printf("area: %d\n", i+1);
|
break;
|
||||||
printf("area_offset: 0x%08x\n", ah->area_offset);
|
default:
|
||||||
printf("area_size: 0x%08x (%d)\n", ah->area_size, ah->area_size);
|
printf("area: %d\n", i + 1);
|
||||||
printf("area_name: %s\n", buf);
|
printf("area_offset: 0x%08x\n", ah->area_offset);
|
||||||
}
|
printf("area_size: 0x%08x (%d)\n", ah->area_size,
|
||||||
|
ah->area_size);
|
||||||
|
printf("area_name: %s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
if (opt_extract) {
|
if (opt_extract) {
|
||||||
char *s;
|
char *s;
|
||||||
for (s = buf; *s; s++)
|
for (s = buf; *s; s++)
|
||||||
if (*s == ' ')
|
if (*s == ' ')
|
||||||
*s = '_';
|
*s = '_';
|
||||||
FILE *fp = fopen(buf,"wb");
|
FILE *fp = fopen(buf, "wb");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
fprintf(stderr, "%s: can't open %s: %s\n",
|
fprintf(stderr, "%s: can't open %s: %s\n",
|
||||||
progname, buf, strerror(errno));
|
progname, buf, strerror(errno));
|
||||||
retval = 1;
|
retval = 1;
|
||||||
} else if (!ah->area_size) {
|
} else if (!ah->area_size) {
|
||||||
fprintf(stderr, "%s: section %s has zero size\n", progname, buf);
|
fprintf(stderr,
|
||||||
} else if (ah->area_offset + ah->area_size > size_of_rom) {
|
"%s: section %s has zero size\n",
|
||||||
fprintf(stderr, "%s: section %s is larger than the image\n",
|
progname, buf);
|
||||||
progname, buf);
|
} else if (ah->area_offset + ah->area_size >
|
||||||
retval = 1;
|
size_of_rom) {
|
||||||
} else if (1 != fwrite(base_of_rom + ah->area_offset,
|
fprintf(stderr, "%s: section %s is larger"
|
||||||
ah->area_size, 1, fp)) {
|
" than the image\n", progname, buf);
|
||||||
fprintf(stderr, "%s: can't write %s: %s\n",
|
retval = 1;
|
||||||
progname, buf, strerror(errno));
|
} else if (1 != fwrite(base_of_rom + ah->area_offset,
|
||||||
retval = 1;
|
ah->area_size, 1, fp)) {
|
||||||
} else {
|
fprintf(stderr, "%s: can't write %s: %s\n",
|
||||||
if (FMT_NORMAL == opt_format)
|
progname, buf, strerror(errno));
|
||||||
printf("saved as \"%s\"\n", buf);
|
retval = 1;
|
||||||
}
|
} else {
|
||||||
fclose(fp);
|
if (FMT_NORMAL == opt_format)
|
||||||
}
|
printf("saved as \"%s\"\n", buf);
|
||||||
}
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* Stuff for human-readable form */
|
/* Stuff for human-readable form */
|
||||||
|
|
||||||
typedef struct dup_s {
|
typedef struct dup_s {
|
||||||
char *name;
|
char *name;
|
||||||
struct dup_s *next;
|
struct dup_s *next;
|
||||||
} dupe_t;
|
} dupe_t;
|
||||||
|
|
||||||
typedef struct node_s {
|
typedef struct node_s {
|
||||||
char *name;
|
char *name;
|
||||||
uint32_t start;
|
uint32_t start;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t end;
|
uint32_t end;
|
||||||
struct node_s *parent;
|
struct node_s *parent;
|
||||||
int num_children;
|
int num_children;
|
||||||
struct node_s **child;
|
struct node_s **child;
|
||||||
dupe_t *alias;
|
dupe_t *alias;
|
||||||
} node_t;
|
} node_t;
|
||||||
|
|
||||||
static node_t *all_nodes;
|
static node_t *all_nodes;
|
||||||
|
|
||||||
static void sort_nodes(int num, node_t *ary[])
|
static void sort_nodes(int num, node_t * ary[])
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
node_t *tmp;
|
node_t *tmp;
|
||||||
|
|
||||||
/* bubble-sort is quick enough with only a few entries */
|
/* bubble-sort is quick enough with only a few entries */
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
for (j = i + 1; j < num; j++) {
|
for (j = i + 1; j < num; j++) {
|
||||||
if (ary[j]->start > ary[i]->start) {
|
if (ary[j]->start > ary[i]->start) {
|
||||||
tmp = ary[i];
|
tmp = ary[i];
|
||||||
ary[i] = ary[j];
|
ary[i] = ary[j];
|
||||||
ary[j] = tmp;
|
ary[j] = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void line(int indent, char *name,
|
static void line(int indent, char *name,
|
||||||
uint32_t start, uint32_t end, uint32_t size, char *append)
|
uint32_t start, uint32_t end, uint32_t size, char *append)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
printf("%-25s %08x %08x %08x%s\n", name, start, end, size,
|
printf("%-25s %08x %08x %08x%s\n", name, start, end, size,
|
||||||
append ? append : "");
|
append ? append : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gapcount;
|
static int gapcount;
|
||||||
static void empty(int indent, uint32_t start, uint32_t end, char *name)
|
static void empty(int indent, uint32_t start, uint32_t end, char *name)
|
||||||
{
|
{
|
||||||
char buf[80];
|
char buf[80];
|
||||||
if (opt_gaps) {
|
if (opt_gaps) {
|
||||||
sprintf(buf, " // gap in %s", name);
|
sprintf(buf, " // gap in %s", name);
|
||||||
line(indent + 1, "", start, end, end - start, buf);
|
line(indent + 1, "", start, end, end - start, buf);
|
||||||
}
|
}
|
||||||
gapcount++;
|
gapcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show(node_t *p, int indent, int show_first)
|
static void show(node_t * p, int indent, int show_first)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
dupe_t *alias;
|
dupe_t *alias;
|
||||||
if (show_first) {
|
if (show_first) {
|
||||||
line(indent, p->name, p->start, p->end, p->size, 0);
|
line(indent, p->name, p->start, p->end, p->size, 0);
|
||||||
for (alias = p->alias; alias; alias = alias->next)
|
for (alias = p->alias; alias; alias = alias->next)
|
||||||
line(indent, alias->name, p->start, p->end, p->size, " // DUPLICATE");
|
line(indent, alias->name, p->start, p->end, p->size,
|
||||||
}
|
" // DUPLICATE");
|
||||||
sort_nodes(p->num_children, p->child);
|
}
|
||||||
for (i = 0; i < p->num_children; i++) {
|
sort_nodes(p->num_children, p->child);
|
||||||
if (i == 0 && p->end != p->child[i]->end)
|
for (i = 0; i < p->num_children; i++) {
|
||||||
empty(indent, p->child[i]->end, p->end, p->name);
|
if (i == 0 && p->end != p->child[i]->end)
|
||||||
show(p->child[i], indent + show_first, 1);
|
empty(indent, p->child[i]->end, p->end, p->name);
|
||||||
if (i < p->num_children - 1 && p->child[i]->start != p->child[i+1]->end)
|
show(p->child[i], indent + show_first, 1);
|
||||||
empty(indent, p->child[i+1]->end, p->child[i]->start, p->name);
|
if (i < p->num_children - 1
|
||||||
if (i == p->num_children - 1 && p->child[i]->start != p->start)
|
&& p->child[i]->start != p->child[i + 1]->end)
|
||||||
empty(indent, p->start, p->child[i]->start, p->name);
|
empty(indent, p->child[i + 1]->end, p->child[i]->start,
|
||||||
}
|
p->name);
|
||||||
|
if (i == p->num_children - 1 && p->child[i]->start != p->start)
|
||||||
|
empty(indent, p->start, p->child[i]->start, p->name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int overlaps(int i, int j)
|
static int overlaps(int i, int j)
|
||||||
{
|
{
|
||||||
node_t *a = all_nodes + i;
|
node_t *a = all_nodes + i;
|
||||||
node_t *b = all_nodes + j;
|
node_t *b = all_nodes + j;
|
||||||
|
|
||||||
return ((a->start < b->start) && (b->start < a->end) &&
|
return ((a->start < b->start) && (b->start < a->end) &&
|
||||||
(b->start < a->end) && (a->end < b->end));
|
(b->start < a->end) && (a->end < b->end));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int encloses(int i, int j)
|
static int encloses(int i, int j)
|
||||||
{
|
{
|
||||||
node_t *a = all_nodes + i;
|
node_t *a = all_nodes + i;
|
||||||
node_t *b = all_nodes + j;
|
node_t *b = all_nodes + j;
|
||||||
|
|
||||||
return ((a->start <= b->start) &&
|
return ((a->start <= b->start) && (a->end >= b->end));
|
||||||
(a->end >= b->end));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int duplicates(int i, int j)
|
static int duplicates(int i, int j)
|
||||||
{
|
{
|
||||||
node_t *a = all_nodes + i;
|
node_t *a = all_nodes + i;
|
||||||
node_t *b = all_nodes + j;
|
node_t *b = all_nodes + j;
|
||||||
|
|
||||||
return ((a->start == b->start) &&
|
return ((a->start == b->start) && (a->end == b->end));
|
||||||
(a->end == b->end));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_dupe(int i, int j, int numnodes)
|
static void add_dupe(int i, int j, int numnodes)
|
||||||
{
|
{
|
||||||
int k;
|
int k;
|
||||||
dupe_t *alias;
|
dupe_t *alias;
|
||||||
|
|
||||||
alias = (dupe_t *)malloc(sizeof(dupe_t));
|
alias = (dupe_t *) malloc(sizeof(dupe_t));
|
||||||
alias->name = all_nodes[j].name;
|
alias->name = all_nodes[j].name;
|
||||||
alias->next = all_nodes[i].alias;
|
alias->next = all_nodes[i].alias;
|
||||||
all_nodes[i].alias = alias;
|
all_nodes[i].alias = alias;
|
||||||
for (k = j; k < numnodes; k++ )
|
for (k = j; k < numnodes; k++)
|
||||||
all_nodes[k] = all_nodes[k + 1];
|
all_nodes[k] = all_nodes[k + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_child(node_t *p, int n)
|
static void add_child(node_t * p, int n)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
if (p->num_children && !p->child) {
|
if (p->num_children && !p->child) {
|
||||||
p->child = (struct node_s **)calloc(p->num_children, sizeof(node_t *));
|
p->child =
|
||||||
if (!p->child) {
|
(struct node_s **)calloc(p->num_children, sizeof(node_t *));
|
||||||
perror("calloc failed");
|
if (!p->child) {
|
||||||
exit(1);
|
perror("calloc failed");
|
||||||
}
|
exit(1);
|
||||||
}
|
}
|
||||||
for (i = 0; i < p->num_children; i++)
|
}
|
||||||
if (!p->child[i]) {
|
for (i = 0; i < p->num_children; i++)
|
||||||
p->child[i] = all_nodes + n;
|
if (!p->child[i]) {
|
||||||
return;
|
p->child[i] = all_nodes + n;
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int human_fmap(void *p)
|
static int human_fmap(void *p)
|
||||||
{
|
{
|
||||||
FmapHeader *fmh;
|
FmapHeader *fmh;
|
||||||
FmapAreaHeader *ah;
|
FmapAreaHeader *ah;
|
||||||
int i, j, errorcnt=0;
|
int i, j, errorcnt = 0;
|
||||||
int numnodes;
|
int numnodes;
|
||||||
|
|
||||||
fmh = (FmapHeader *)p;
|
fmh = (FmapHeader *) p;
|
||||||
ah = (FmapAreaHeader *)(fmh + 1);
|
ah = (FmapAreaHeader *) (fmh + 1);
|
||||||
|
|
||||||
/* The challenge here is to generate a directed graph from the
|
/* The challenge here is to generate a directed graph from the
|
||||||
* arbitrarily-ordered FMAP entries, and then to prune it until it's as
|
* arbitrarily-ordered FMAP entries, and then to prune it until it's as
|
||||||
* simple (and deep) as possible. Overlapping regions are not allowed.
|
* simple (and deep) as possible. Overlapping regions are not allowed.
|
||||||
* Duplicate regions are okay, but may require special handling. */
|
* Duplicate regions are okay, but may require special handling. */
|
||||||
|
|
||||||
/* Convert the FMAP info into our format. */
|
/* Convert the FMAP info into our format. */
|
||||||
numnodes = fmh->fmap_nareas;
|
numnodes = fmh->fmap_nareas;
|
||||||
|
|
||||||
/* plus one for the all-enclosing "root" */
|
/* plus one for the all-enclosing "root" */
|
||||||
all_nodes = (node_t *)calloc(numnodes+1, sizeof(node_t));
|
all_nodes = (node_t *) calloc(numnodes + 1, sizeof(node_t));
|
||||||
if (!all_nodes) {
|
if (!all_nodes) {
|
||||||
perror("calloc failed");
|
perror("calloc failed");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
for (i = 0; i < numnodes; i++) {
|
for (i = 0; i < numnodes; i++) {
|
||||||
char buf[FMAP_NAMELEN+1];
|
char buf[FMAP_NAMELEN + 1];
|
||||||
strncpy(buf, ah[i].area_name, FMAP_NAMELEN);
|
strncpy(buf, ah[i].area_name, FMAP_NAMELEN);
|
||||||
buf[FMAP_NAMELEN] = '\0';
|
buf[FMAP_NAMELEN] = '\0';
|
||||||
if (!(all_nodes[i].name = strdup(buf))) {
|
if (!(all_nodes[i].name = strdup(buf))) {
|
||||||
perror("strdup failed");
|
perror("strdup failed");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
all_nodes[i].start = ah[i].area_offset;
|
all_nodes[i].start = ah[i].area_offset;
|
||||||
all_nodes[i].size = ah[i].area_size;
|
all_nodes[i].size = ah[i].area_size;
|
||||||
all_nodes[i].end = ah[i].area_offset + ah[i].area_size;
|
all_nodes[i].end = ah[i].area_offset + ah[i].area_size;
|
||||||
}
|
}
|
||||||
/* Now add the root node */
|
/* Now add the root node */
|
||||||
all_nodes[numnodes].name = strdup("-entire flash-");
|
all_nodes[numnodes].name = strdup("-entire flash-");
|
||||||
all_nodes[numnodes].start = fmh->fmap_base;
|
all_nodes[numnodes].start = fmh->fmap_base;
|
||||||
all_nodes[numnodes].size = fmh->fmap_size;
|
all_nodes[numnodes].size = fmh->fmap_size;
|
||||||
all_nodes[numnodes].end = fmh->fmap_base + fmh->fmap_size;
|
all_nodes[numnodes].end = fmh->fmap_base + fmh->fmap_size;
|
||||||
|
|
||||||
|
/* First, coalesce any duplicates */
|
||||||
|
for (i = 0; i < numnodes; i++) {
|
||||||
|
for (j = i + 1; j < numnodes; j++) {
|
||||||
|
if (duplicates(i, j)) {
|
||||||
|
add_dupe(i, j, numnodes);
|
||||||
|
numnodes--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* First, coalesce any duplicates */
|
/* Each node should have at most one parent, which is the smallest
|
||||||
for (i = 0; i < numnodes; i++) {
|
* enclosing node. Duplicate nodes "enclose" each other, but if there's
|
||||||
for (j = i + 1; j < numnodes; j++) {
|
* already a relationship in one direction, we won't create another.
|
||||||
if (duplicates(i, j)) {
|
*/
|
||||||
add_dupe(i, j, numnodes);
|
for (i = 0; i < numnodes; i++) {
|
||||||
numnodes--;
|
/* Find the smallest parent, which might be the root node. */
|
||||||
}
|
int k = numnodes;
|
||||||
}
|
for (j = 0; j < numnodes; j++) { /* full O(N^2) comparison */
|
||||||
}
|
if (i == j)
|
||||||
|
continue;
|
||||||
|
if (overlaps(i, j)) {
|
||||||
|
printf("ERROR: %s and %s overlap\n",
|
||||||
|
all_nodes[i].name, all_nodes[j].name);
|
||||||
|
printf(" %s: 0x%x - 0x%x\n", all_nodes[i].name,
|
||||||
|
all_nodes[i].start, all_nodes[i].end);
|
||||||
|
printf(" %s: 0x%x - 0x%x\n", all_nodes[j].name,
|
||||||
|
all_nodes[j].start, all_nodes[j].end);
|
||||||
|
if (opt_overlap < 2) {
|
||||||
|
printf("Use more -h args to ignore"
|
||||||
|
" this error\n");
|
||||||
|
errorcnt++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (encloses(j, i)
|
||||||
|
&& all_nodes[j].size < all_nodes[k].size)
|
||||||
|
k = j;
|
||||||
|
}
|
||||||
|
all_nodes[i].parent = all_nodes + k;
|
||||||
|
}
|
||||||
|
if (errorcnt)
|
||||||
|
return 1;
|
||||||
|
|
||||||
/* Each node should have at most one parent, which is the smallest enclosing
|
/* Force those deadbeat parents to recognize their children */
|
||||||
* node. Duplicate nodes "enclose" each other, but if there's already a
|
for (i = 0; i < numnodes; i++) /* how many */
|
||||||
* relationship in one direction, we won't create another. */
|
if (all_nodes[i].parent)
|
||||||
for (i = 0; i < numnodes; i++) {
|
all_nodes[i].parent->num_children++;
|
||||||
/* Find the smallest parent, which might be the root node. */
|
for (i = 0; i < numnodes; i++) /* here they are */
|
||||||
int k = numnodes;
|
if (all_nodes[i].parent)
|
||||||
for (j = 0; j < numnodes; j++) { /* full O(N^2), not triangular */
|
add_child(all_nodes[i].parent, i);
|
||||||
if (i == j)
|
|
||||||
continue;
|
|
||||||
if (overlaps(i, j)) {
|
|
||||||
printf("ERROR: %s and %s overlap\n",
|
|
||||||
all_nodes[i].name, all_nodes[j].name);
|
|
||||||
printf(" %s: 0x%x - 0x%x\n", all_nodes[i].name,
|
|
||||||
all_nodes[i].start, all_nodes[i].end);
|
|
||||||
printf(" %s: 0x%x - 0x%x\n", all_nodes[j].name,
|
|
||||||
all_nodes[j].start, all_nodes[j].end);
|
|
||||||
if (opt_overlap < 2) {
|
|
||||||
printf("Use more -h args to ignore this error\n");
|
|
||||||
errorcnt++;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (encloses(j, i) && all_nodes[j].size < all_nodes[k].size)
|
|
||||||
k = j;
|
|
||||||
}
|
|
||||||
all_nodes[i].parent = all_nodes + k;
|
|
||||||
}
|
|
||||||
if (errorcnt)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* Force those deadbeat parents to recognize their children */
|
/* Ready to go */
|
||||||
for (i = 0; i < numnodes; i++) /* how many */
|
printf("# name start end size\n");
|
||||||
if (all_nodes[i].parent)
|
show(all_nodes + numnodes, 0, opt_gaps);
|
||||||
all_nodes[i].parent->num_children++;
|
|
||||||
for (i = 0; i < numnodes; i++) /* here they are */
|
|
||||||
if (all_nodes[i].parent)
|
|
||||||
add_child(all_nodes[i].parent, i);
|
|
||||||
|
|
||||||
/* Ready to go */
|
if (gapcount && !opt_gaps)
|
||||||
printf("# name start end size\n");
|
printf("\nWARNING: unused regions found. Use -H to see them\n");
|
||||||
show(all_nodes + numnodes, 0, opt_gaps);
|
|
||||||
|
|
||||||
if (gapcount && !opt_gaps)
|
return 0;
|
||||||
printf("\nWARNING: unused regions found. Use -H to see them\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End of human-reable stuff */
|
/* End of human-reable stuff */
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static const char usage[] =
|
||||||
|
"\nUsage: %s [-x] [-p|-f|-h] FLASHIMAGE [NAME...]\n\n"
|
||||||
|
"Display (and extract with -x) the FMAP components from a BIOS image.\n"
|
||||||
|
"The -p option makes the output easier to parse by scripts.\n"
|
||||||
|
"The -f option emits the FMAP in the format used by flashrom.\n"
|
||||||
|
"\n"
|
||||||
|
"Specify one or more NAMEs to only print sections that exactly match.\n"
|
||||||
|
"\n"
|
||||||
|
"The -h option shows the whole FMAP in human-readable form.\n"
|
||||||
|
" Use -H to also display any gaps.\n"
|
||||||
|
"\n";
|
||||||
|
|
||||||
static int do_dump_fmap(int argc, char *argv[])
|
static int do_dump_fmap(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
int errorcnt = 0;
|
int errorcnt = 0;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
int fd;
|
int fd;
|
||||||
const char *fmap;
|
const char *fmap;
|
||||||
int retval = 1;
|
int retval = 1;
|
||||||
|
|
||||||
progname = strrchr(argv[0], '/');
|
progname = strrchr(argv[0], '/');
|
||||||
if (progname)
|
if (progname)
|
||||||
progname++;
|
progname++;
|
||||||
else
|
else
|
||||||
progname = argv[0];
|
progname = argv[0];
|
||||||
|
|
||||||
opterr = 0; /* quiet, you */
|
opterr = 0; /* quiet, you */
|
||||||
while ((c = getopt(argc, argv, ":xpfhH")) != -1) {
|
while ((c = getopt(argc, argv, ":xpfhH")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'x':
|
case 'x':
|
||||||
opt_extract = 1;
|
opt_extract = 1;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
opt_format = FMT_PRETTY;
|
opt_format = FMT_PRETTY;
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
opt_format = FMT_FLASHROM;
|
opt_format = FMT_FLASHROM;
|
||||||
break;
|
break;
|
||||||
case 'H':
|
case 'H':
|
||||||
opt_gaps = 1;
|
opt_gaps = 1;
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case 'h':
|
case 'h':
|
||||||
opt_format = FMT_HUMAN;
|
opt_format = FMT_HUMAN;
|
||||||
opt_overlap++;
|
opt_overlap++;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
fprintf(stderr, "%s: unrecognized switch: -%c\n",
|
fprintf(stderr, "%s: unrecognized switch: -%c\n",
|
||||||
progname, optopt);
|
progname, optopt);
|
||||||
errorcnt++;
|
errorcnt++;
|
||||||
break;
|
break;
|
||||||
case ':':
|
case ':':
|
||||||
fprintf(stderr, "%s: missing argument to -%c\n",
|
fprintf(stderr, "%s: missing argument to -%c\n",
|
||||||
progname, optopt);
|
progname, optopt);
|
||||||
errorcnt++;
|
errorcnt++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errorcnt++;
|
errorcnt++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorcnt || optind >= argc) {
|
if (errorcnt || optind >= argc) {
|
||||||
fprintf(stderr,
|
fprintf(stderr, usage, progname);
|
||||||
"\nUsage: %s [-x] [-p|-f|-h] FLASHIMAGE [NAME...]\n\n"
|
return 1;
|
||||||
"Display (and extract with -x) the FMAP components from a BIOS image.\n"
|
}
|
||||||
"The -p option makes the output easier to parse by scripts.\n"
|
|
||||||
"The -f option emits the FMAP in the format used by flashrom.\n"
|
|
||||||
"\n"
|
|
||||||
"Specify one or more NAMEs to only print sections that exactly match.\n"
|
|
||||||
"\n"
|
|
||||||
"The -h option shows the whole FMAP in human-readable form.\n"
|
|
||||||
" Use -H to also display any gaps.\n"
|
|
||||||
"\n",
|
|
||||||
progname);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != stat(argv[optind], &sb)) {
|
if (0 != stat(argv[optind], &sb)) {
|
||||||
fprintf(stderr, "%s: can't stat %s: %s\n",
|
fprintf(stderr, "%s: can't stat %s: %s\n",
|
||||||
progname,
|
progname, argv[optind], strerror(errno));
|
||||||
argv[optind],
|
return 1;
|
||||||
strerror(errno));
|
}
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = open(argv[optind], O_RDONLY);
|
fd = open(argv[optind], O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
fprintf(stderr, "%s: can't open %s: %s\n",
|
fprintf(stderr, "%s: can't open %s: %s\n",
|
||||||
progname,
|
progname, argv[optind], strerror(errno));
|
||||||
argv[optind],
|
return 1;
|
||||||
strerror(errno));
|
}
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
base_of_rom = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
|
base_of_rom =
|
||||||
if (base_of_rom == (char*)-1) {
|
mmap(0, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||||
fprintf(stderr, "%s: can't mmap %s: %s\n",
|
if (base_of_rom == (char *)-1) {
|
||||||
progname,
|
fprintf(stderr, "%s: can't mmap %s: %s\n",
|
||||||
argv[optind],
|
progname, argv[optind], strerror(errno));
|
||||||
strerror(errno));
|
close(fd);
|
||||||
close(fd);
|
return 1;
|
||||||
return 1;
|
}
|
||||||
}
|
close(fd); /* done with this now */
|
||||||
close(fd); /* done with this now */
|
size_of_rom = sb.st_size;
|
||||||
size_of_rom = sb.st_size;
|
|
||||||
|
|
||||||
fmap = FmapFind((char*) base_of_rom, size_of_rom);
|
fmap = FmapFind((char *)base_of_rom, size_of_rom);
|
||||||
if (fmap) {
|
if (fmap) {
|
||||||
switch (opt_format) {
|
switch (opt_format) {
|
||||||
case FMT_HUMAN:
|
case FMT_HUMAN:
|
||||||
retval = human_fmap((void *)fmap);
|
retval = human_fmap((void *)fmap);
|
||||||
break;
|
break;
|
||||||
case FMT_NORMAL:
|
case FMT_NORMAL:
|
||||||
printf("hit at 0x%08x\n", (uint32_t) (fmap - (char*) base_of_rom));
|
printf("hit at 0x%08x\n",
|
||||||
/* fallthrough */
|
(uint32_t) (fmap - (char *)base_of_rom));
|
||||||
default:
|
/* fallthrough */
|
||||||
retval = dump_fmap(fmap, argc-optind-1, argv+optind+1);
|
default:
|
||||||
}
|
retval =
|
||||||
}
|
dump_fmap(fmap, argc - optind - 1,
|
||||||
|
argv + optind + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (0 != munmap(base_of_rom, sb.st_size)) {
|
if (0 != munmap(base_of_rom, sb.st_size)) {
|
||||||
fprintf(stderr, "%s: can't munmap %s: %s\n",
|
fprintf(stderr, "%s: can't munmap %s: %s\n",
|
||||||
progname,
|
progname, argv[optind], strerror(errno));
|
||||||
argv[optind],
|
return 1;
|
||||||
strerror(errno));
|
}
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_FUTIL_COMMAND(dump_fmap, do_dump_fmap,
|
DECLARE_FUTIL_COMMAND(dump_fmap, do_dump_fmap,
|
||||||
"Display FMAP contents from a firmware image");
|
"Display FMAP contents from a firmware image");
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
* Exports the kernel commandline from a given partition/image.
|
* Exports the kernel commandline from a given partition/image.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
@@ -15,78 +14,78 @@
|
|||||||
#include "vboot_host.h"
|
#include "vboot_host.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
OPT_KLOADADDR = 1000,
|
OPT_KLOADADDR = 1000,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option long_opts[] = {
|
static const struct option long_opts[] = {
|
||||||
{ "kloadaddr", 1, NULL, OPT_KLOADADDR },
|
{"kloadaddr", 1, NULL, OPT_KLOADADDR},
|
||||||
{ NULL, 0, NULL, 0 }
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Print help and return error */
|
/* Print help and return error */
|
||||||
static int PrintHelp(void) {
|
static int PrintHelp(void)
|
||||||
puts("dump_kernel_config - Prints the kernel command line\n"
|
{
|
||||||
"\n"
|
puts("dump_kernel_config - Prints the kernel command line\n"
|
||||||
"Usage: dump_kernel_config [--kloadaddr <ADDRESS>] "
|
"\n"
|
||||||
"<image/blockdevice>\n"
|
"Usage: dump_kernel_config [--kloadaddr <ADDRESS>] "
|
||||||
"\n"
|
"<image/blockdevice>\n" "\n" "");
|
||||||
"");
|
return 1;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_dump_kernel_config(int argc, char* argv[]) {
|
static int do_dump_kernel_config(int argc, char *argv[])
|
||||||
char *infile = NULL;
|
{
|
||||||
char *config = NULL;
|
char *infile = NULL;
|
||||||
uint64_t kernel_body_load_address = USE_PREAMBLE_LOAD_ADDR;
|
char *config = NULL;
|
||||||
int parse_error = 0;
|
uint64_t kernel_body_load_address = USE_PREAMBLE_LOAD_ADDR;
|
||||||
char *e;
|
int parse_error = 0;
|
||||||
int i;
|
char *e;
|
||||||
|
int i;
|
||||||
|
|
||||||
while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
|
while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
|
||||||
!parse_error) {
|
!parse_error) {
|
||||||
switch (i) {
|
switch (i) {
|
||||||
default:
|
default:
|
||||||
case '?':
|
case '?':
|
||||||
/* Unhandled option */
|
/* Unhandled option */
|
||||||
parse_error = 1;
|
parse_error = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
/* silently handled option */
|
/* silently handled option */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_KLOADADDR:
|
case OPT_KLOADADDR:
|
||||||
kernel_body_load_address = strtoul(optarg, &e, 0);
|
kernel_body_load_address = strtoul(optarg, &e, 0);
|
||||||
if (!*optarg || (e && *e)) {
|
if (!*optarg || (e && *e)) {
|
||||||
fprintf(stderr, "Invalid --kloadaddr\n");
|
fprintf(stderr, "Invalid --kloadaddr\n");
|
||||||
parse_error = 1;
|
parse_error = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optind >= argc) {
|
if (optind >= argc) {
|
||||||
fprintf(stderr, "Expected argument after options\n");
|
fprintf(stderr, "Expected argument after options\n");
|
||||||
parse_error = 1;
|
parse_error = 1;
|
||||||
} else
|
} else
|
||||||
infile = argv[optind];
|
infile = argv[optind];
|
||||||
|
|
||||||
if (parse_error)
|
if (parse_error)
|
||||||
return PrintHelp();
|
return PrintHelp();
|
||||||
|
|
||||||
if (!infile || !*infile) {
|
if (!infile || !*infile) {
|
||||||
fprintf(stderr, "Must specify filename\n");
|
fprintf(stderr, "Must specify filename\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
config = FindKernelConfig(infile, kernel_body_load_address);
|
config = FindKernelConfig(infile, kernel_body_load_address);
|
||||||
if (!config)
|
if (!config)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
printf("%s", config);
|
printf("%s", config);
|
||||||
|
|
||||||
free(config);
|
free(config);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_FUTIL_COMMAND(dump_kernel_config, do_dump_kernel_config,
|
DECLARE_FUTIL_COMMAND(dump_kernel_config, do_dump_kernel_config,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <inttypes.h> /* For PRIu64 */
|
#include <inttypes.h> /* For PRIu64 */
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -19,358 +19,368 @@
|
|||||||
#include "util_misc.h"
|
#include "util_misc.h"
|
||||||
#include "vboot_common.h"
|
#include "vboot_common.h"
|
||||||
|
|
||||||
|
|
||||||
/* Command line options */
|
/* Command line options */
|
||||||
enum {
|
enum {
|
||||||
OPT_MODE_VBLOCK = 1000,
|
OPT_MODE_VBLOCK = 1000,
|
||||||
OPT_MODE_VERIFY,
|
OPT_MODE_VERIFY,
|
||||||
OPT_KEYBLOCK,
|
OPT_KEYBLOCK,
|
||||||
OPT_SIGNPUBKEY,
|
OPT_SIGNPUBKEY,
|
||||||
OPT_SIGNPRIVATE,
|
OPT_SIGNPRIVATE,
|
||||||
OPT_VERSION,
|
OPT_VERSION,
|
||||||
OPT_FV,
|
OPT_FV,
|
||||||
OPT_KERNELKEY,
|
OPT_KERNELKEY,
|
||||||
OPT_FLAGS,
|
OPT_FLAGS,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option long_opts[] = {
|
static const struct option long_opts[] = {
|
||||||
{"vblock", 1, 0, OPT_MODE_VBLOCK },
|
{"vblock", 1, 0, OPT_MODE_VBLOCK},
|
||||||
{"verify", 1, 0, OPT_MODE_VERIFY },
|
{"verify", 1, 0, OPT_MODE_VERIFY},
|
||||||
{"keyblock", 1, 0, OPT_KEYBLOCK },
|
{"keyblock", 1, 0, OPT_KEYBLOCK},
|
||||||
{"signpubkey", 1, 0, OPT_SIGNPUBKEY },
|
{"signpubkey", 1, 0, OPT_SIGNPUBKEY},
|
||||||
{"signprivate", 1, 0, OPT_SIGNPRIVATE },
|
{"signprivate", 1, 0, OPT_SIGNPRIVATE},
|
||||||
{"version", 1, 0, OPT_VERSION },
|
{"version", 1, 0, OPT_VERSION},
|
||||||
{"fv", 1, 0, OPT_FV },
|
{"fv", 1, 0, OPT_FV},
|
||||||
{"kernelkey", 1, 0, OPT_KERNELKEY },
|
{"kernelkey", 1, 0, OPT_KERNELKEY},
|
||||||
{"flags", 1, 0, OPT_FLAGS },
|
{"flags", 1, 0, OPT_FLAGS},
|
||||||
{NULL, 0, 0, 0}
|
{NULL, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Print help and return error */
|
/* Print help and return error */
|
||||||
static int PrintHelp(void) {
|
static int PrintHelp(void)
|
||||||
|
{
|
||||||
|
|
||||||
puts("vbutil_firmware - Verified boot key block utility\n"
|
puts("vbutil_firmware - Verified boot key block utility\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Usage: vbutil_firmware <--vblock|--verify> <file> [OPTIONS]\n"
|
"Usage: vbutil_firmware <--vblock|--verify> <file> [OPTIONS]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"For '--vblock <file>', required OPTIONS are:\n"
|
"For '--vblock <file>', required OPTIONS are:\n"
|
||||||
" --keyblock <file> Key block in .keyblock format\n"
|
" --keyblock <file> Key block in .keyblock format\n"
|
||||||
" --signprivate <file> Signing private key in .vbprivk format\n"
|
" --signprivate <file>"
|
||||||
" --version <number> Firmware version\n"
|
" Signing private key in .vbprivk format\n"
|
||||||
" --fv <file> Firmware volume to sign\n"
|
" --version <number> Firmware version\n"
|
||||||
" --kernelkey <file> Kernel subkey in .vbpubk format\n"
|
" --fv <file> Firmware volume to sign\n"
|
||||||
"optional OPTIONS are:\n"
|
" --kernelkey <file> Kernel subkey in .vbpubk format\n"
|
||||||
" --flags <number> Preamble flags (defaults to 0)\n"
|
"optional OPTIONS are:\n"
|
||||||
"\n"
|
" --flags <number> Preamble flags (defaults to 0)\n"
|
||||||
"For '--verify <file>', required OPTIONS are:\n"
|
"\n"
|
||||||
" --signpubkey <file> Signing public key in .vbpubk format\n"
|
"For '--verify <file>', required OPTIONS are:\n"
|
||||||
" --fv <file> Firmware volume to verify\n"
|
" --signpubkey <file>"
|
||||||
"\n"
|
" Signing public key in .vbpubk format\n"
|
||||||
"For '--verify <file>', optional OPTIONS are:\n"
|
" --fv <file> Firmware volume to verify\n"
|
||||||
" --kernelkey <file> Write the kernel subkey to this file\n"
|
"\n"
|
||||||
"");
|
"For '--verify <file>', optional OPTIONS are:\n"
|
||||||
return 1;
|
" --kernelkey <file>"
|
||||||
|
" Write the kernel subkey to this file\n"
|
||||||
|
"");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Create a firmware .vblock */
|
/* Create a firmware .vblock */
|
||||||
static int Vblock(const char* outfile, const char* keyblock_file,
|
static int Vblock(const char *outfile, const char *keyblock_file,
|
||||||
const char* signprivate, uint64_t version,
|
const char *signprivate, uint64_t version,
|
||||||
const char* fv_file, const char* kernelkey_file,
|
const char *fv_file, const char *kernelkey_file,
|
||||||
uint32_t preamble_flags) {
|
uint32_t preamble_flags)
|
||||||
|
{
|
||||||
|
|
||||||
VbPrivateKey* signing_key;
|
VbPrivateKey *signing_key;
|
||||||
VbPublicKey* kernel_subkey;
|
VbPublicKey *kernel_subkey;
|
||||||
VbSignature* body_sig;
|
VbSignature *body_sig;
|
||||||
VbFirmwarePreambleHeader* preamble;
|
VbFirmwarePreambleHeader *preamble;
|
||||||
VbKeyBlockHeader* key_block;
|
VbKeyBlockHeader *key_block;
|
||||||
uint64_t key_block_size;
|
uint64_t key_block_size;
|
||||||
uint8_t* fv_data;
|
uint8_t *fv_data;
|
||||||
uint64_t fv_size;
|
uint64_t fv_size;
|
||||||
FILE* f;
|
FILE *f;
|
||||||
uint64_t i;
|
uint64_t i;
|
||||||
|
|
||||||
if (!outfile) {
|
if (!outfile) {
|
||||||
VbExError("Must specify output filename\n");
|
VbExError("Must specify output filename\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!keyblock_file || !signprivate || !kernelkey_file) {
|
if (!keyblock_file || !signprivate || !kernelkey_file) {
|
||||||
VbExError("Must specify all keys\n");
|
VbExError("Must specify all keys\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!fv_file) {
|
if (!fv_file) {
|
||||||
VbExError("Must specify firmware volume\n");
|
VbExError("Must specify firmware volume\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the key block and keys */
|
/* Read the key block and keys */
|
||||||
key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
|
key_block =
|
||||||
if (!key_block) {
|
(VbKeyBlockHeader *) ReadFile(keyblock_file, &key_block_size);
|
||||||
VbExError("Error reading key block.\n");
|
if (!key_block) {
|
||||||
return 1;
|
VbExError("Error reading key block.\n");
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
signing_key = PrivateKeyRead(signprivate);
|
signing_key = PrivateKeyRead(signprivate);
|
||||||
if (!signing_key) {
|
if (!signing_key) {
|
||||||
VbExError("Error reading signing key.\n");
|
VbExError("Error reading signing key.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel_subkey = PublicKeyRead(kernelkey_file);
|
kernel_subkey = PublicKeyRead(kernelkey_file);
|
||||||
if (!kernel_subkey) {
|
if (!kernel_subkey) {
|
||||||
VbExError("Error reading kernel subkey.\n");
|
VbExError("Error reading kernel subkey.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read and sign the firmware volume */
|
/* Read and sign the firmware volume */
|
||||||
fv_data = ReadFile(fv_file, &fv_size);
|
fv_data = ReadFile(fv_file, &fv_size);
|
||||||
if (!fv_data)
|
if (!fv_data)
|
||||||
return 1;
|
return 1;
|
||||||
if (!fv_size) {
|
if (!fv_size) {
|
||||||
VbExError("Empty firmware volume file\n");
|
VbExError("Empty firmware volume file\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
body_sig = CalculateSignature(fv_data, fv_size, signing_key);
|
body_sig = CalculateSignature(fv_data, fv_size, signing_key);
|
||||||
if (!body_sig) {
|
if (!body_sig) {
|
||||||
VbExError("Error calculating body signature\n");
|
VbExError("Error calculating body signature\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
free(fv_data);
|
free(fv_data);
|
||||||
|
|
||||||
/* Create preamble */
|
/* Create preamble */
|
||||||
preamble = CreateFirmwarePreamble(version,
|
preamble = CreateFirmwarePreamble(version,
|
||||||
kernel_subkey,
|
kernel_subkey,
|
||||||
body_sig,
|
body_sig,
|
||||||
signing_key,
|
signing_key, preamble_flags);
|
||||||
preamble_flags);
|
if (!preamble) {
|
||||||
if (!preamble) {
|
VbExError("Error creating preamble.\n");
|
||||||
VbExError("Error creating preamble.\n");
|
return 1;
|
||||||
return 1;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the output file */
|
/* Write the output file */
|
||||||
f = fopen(outfile, "wb");
|
f = fopen(outfile, "wb");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
VbExError("Can't open output file %s\n", outfile);
|
VbExError("Can't open output file %s\n", outfile);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
|
i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
|
||||||
(1 != fwrite(preamble, preamble->preamble_size, 1, f)));
|
(1 != fwrite(preamble, preamble->preamble_size, 1, f)));
|
||||||
fclose(f);
|
fclose(f);
|
||||||
if (i) {
|
if (i) {
|
||||||
VbExError("Can't write output file %s\n", outfile);
|
VbExError("Can't write output file %s\n", outfile);
|
||||||
unlink(outfile);
|
unlink(outfile);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Success */
|
/* Success */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Verify(const char* infile, const char* signpubkey,
|
static int Verify(const char *infile, const char *signpubkey,
|
||||||
const char* fv_file, const char* kernelkey_file) {
|
const char *fv_file, const char *kernelkey_file)
|
||||||
|
{
|
||||||
|
|
||||||
VbKeyBlockHeader* key_block;
|
VbKeyBlockHeader *key_block;
|
||||||
VbFirmwarePreambleHeader* preamble;
|
VbFirmwarePreambleHeader *preamble;
|
||||||
VbPublicKey* data_key;
|
VbPublicKey *data_key;
|
||||||
VbPublicKey* sign_key;
|
VbPublicKey *sign_key;
|
||||||
VbPublicKey* kernel_subkey;
|
VbPublicKey *kernel_subkey;
|
||||||
RSAPublicKey* rsa;
|
RSAPublicKey *rsa;
|
||||||
uint8_t* blob;
|
uint8_t *blob;
|
||||||
uint64_t blob_size;
|
uint64_t blob_size;
|
||||||
uint8_t* fv_data;
|
uint8_t *fv_data;
|
||||||
uint64_t fv_size;
|
uint64_t fv_size;
|
||||||
uint64_t now = 0;
|
uint64_t now = 0;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
|
||||||
if (!infile || !signpubkey || !fv_file) {
|
if (!infile || !signpubkey || !fv_file) {
|
||||||
VbExError("Must specify filename, signpubkey, and fv\n");
|
VbExError("Must specify filename, signpubkey, and fv\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read public signing key */
|
/* Read public signing key */
|
||||||
sign_key = PublicKeyRead(signpubkey);
|
sign_key = PublicKeyRead(signpubkey);
|
||||||
if (!sign_key) {
|
if (!sign_key) {
|
||||||
VbExError("Error reading signpubkey.\n");
|
VbExError("Error reading signpubkey.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read blob */
|
/* Read blob */
|
||||||
blob = ReadFile(infile, &blob_size);
|
blob = ReadFile(infile, &blob_size);
|
||||||
if (!blob) {
|
if (!blob) {
|
||||||
VbExError("Error reading input file\n");
|
VbExError("Error reading input file\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read firmware volume */
|
/* Read firmware volume */
|
||||||
fv_data = ReadFile(fv_file, &fv_size);
|
fv_data = ReadFile(fv_file, &fv_size);
|
||||||
if (!fv_data) {
|
if (!fv_data) {
|
||||||
VbExError("Error reading firmware volume\n");
|
VbExError("Error reading firmware volume\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify key block */
|
/* Verify key block */
|
||||||
key_block = (VbKeyBlockHeader*)blob;
|
key_block = (VbKeyBlockHeader *) blob;
|
||||||
if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) {
|
if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) {
|
||||||
VbExError("Error verifying key block.\n");
|
VbExError("Error verifying key block.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
free(sign_key);
|
free(sign_key);
|
||||||
now += key_block->key_block_size;
|
now += key_block->key_block_size;
|
||||||
|
|
||||||
printf("Key block:\n");
|
printf("Key block:\n");
|
||||||
data_key = &key_block->data_key;
|
data_key = &key_block->data_key;
|
||||||
printf(" Size: %" PRIu64 "\n", key_block->key_block_size);
|
printf(" Size: %" PRIu64 "\n",
|
||||||
printf(" Flags: %" PRIu64 " (ignored)\n",
|
key_block->key_block_size);
|
||||||
key_block->key_block_flags);
|
printf(" Flags: %" PRIu64 " (ignored)\n",
|
||||||
printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
|
key_block->key_block_flags);
|
||||||
(data_key->algorithm < kNumAlgorithms ?
|
printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
|
||||||
algo_strings[data_key->algorithm] : "(invalid)"));
|
(data_key->algorithm <
|
||||||
printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
|
kNumAlgorithms ? algo_strings[data_key->
|
||||||
printf(" Data key sha1sum: ");
|
algorithm] : "(invalid)"));
|
||||||
PrintPubKeySha1Sum(data_key);
|
printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
|
||||||
printf("\n");
|
printf(" Data key sha1sum: ");
|
||||||
|
PrintPubKeySha1Sum(data_key);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
rsa = PublicKeyToRSA(&key_block->data_key);
|
rsa = PublicKeyToRSA(&key_block->data_key);
|
||||||
if (!rsa) {
|
if (!rsa) {
|
||||||
VbExError("Error parsing data key.\n");
|
VbExError("Error parsing data key.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify preamble */
|
/* Verify preamble */
|
||||||
preamble = (VbFirmwarePreambleHeader*)(blob + now);
|
preamble = (VbFirmwarePreambleHeader *) (blob + now);
|
||||||
if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) {
|
if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) {
|
||||||
VbExError("Error verifying preamble.\n");
|
VbExError("Error verifying preamble.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
now += preamble->preamble_size;
|
now += preamble->preamble_size;
|
||||||
|
|
||||||
flags = VbGetFirmwarePreambleFlags(preamble);
|
flags = VbGetFirmwarePreambleFlags(preamble);
|
||||||
printf("Preamble:\n");
|
printf("Preamble:\n");
|
||||||
printf(" Size: %" PRIu64 "\n", preamble->preamble_size);
|
printf(" Size: %" PRIu64 "\n",
|
||||||
printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
|
preamble->preamble_size);
|
||||||
preamble->header_version_major, preamble->header_version_minor);
|
printf(" Header version: %" PRIu32 ".%" PRIu32 "\n",
|
||||||
printf(" Firmware version: %" PRIu64 "\n", preamble->firmware_version);
|
preamble->header_version_major, preamble->header_version_minor);
|
||||||
kernel_subkey = &preamble->kernel_subkey;
|
printf(" Firmware version: %" PRIu64 "\n",
|
||||||
printf(" Kernel key algorithm: %" PRIu64 " %s\n",
|
preamble->firmware_version);
|
||||||
kernel_subkey->algorithm,
|
kernel_subkey = &preamble->kernel_subkey;
|
||||||
(kernel_subkey->algorithm < kNumAlgorithms ?
|
printf(" Kernel key algorithm: %" PRIu64 " %s\n",
|
||||||
algo_strings[kernel_subkey->algorithm] : "(invalid)"));
|
kernel_subkey->algorithm,
|
||||||
printf(" Kernel key version: %" PRIu64 "\n",
|
(kernel_subkey->algorithm < kNumAlgorithms ?
|
||||||
kernel_subkey->key_version);
|
algo_strings[kernel_subkey->algorithm] : "(invalid)"));
|
||||||
printf(" Kernel key sha1sum: ");
|
printf(" Kernel key version: %" PRIu64 "\n",
|
||||||
PrintPubKeySha1Sum(kernel_subkey);
|
kernel_subkey->key_version);
|
||||||
printf("\n");
|
printf(" Kernel key sha1sum: ");
|
||||||
printf(" Firmware body size: %" PRIu64 "\n",
|
PrintPubKeySha1Sum(kernel_subkey);
|
||||||
preamble->body_signature.data_size);
|
printf("\n");
|
||||||
printf(" Preamble flags: %" PRIu32 "\n", flags);
|
printf(" Firmware body size: %" PRIu64 "\n",
|
||||||
|
preamble->body_signature.data_size);
|
||||||
|
printf(" Preamble flags: %" PRIu32 "\n", flags);
|
||||||
|
|
||||||
/* TODO: verify body size same as signature size */
|
/* TODO: verify body size same as signature size */
|
||||||
|
|
||||||
/* Verify body */
|
/* Verify body */
|
||||||
if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
|
if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
|
||||||
printf("Preamble requests USE_RO_NORMAL; skipping body verification.\n");
|
printf
|
||||||
} else {
|
("Preamble requests USE_RO_NORMAL;"
|
||||||
if (0 != VerifyData(fv_data, fv_size, &preamble->body_signature, rsa)) {
|
" skipping body verification.\n");
|
||||||
VbExError("Error verifying firmware body.\n");
|
} else {
|
||||||
return 1;
|
if (0 !=
|
||||||
}
|
VerifyData(fv_data, fv_size, &preamble->body_signature,
|
||||||
printf("Body verification succeeded.\n");
|
rsa)) {
|
||||||
}
|
VbExError("Error verifying firmware body.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("Body verification succeeded.\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (kernelkey_file) {
|
if (kernelkey_file) {
|
||||||
if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) {
|
if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) {
|
||||||
fprintf(stderr,
|
VbExError("Unable to write kernel subkey\n");
|
||||||
"vbutil_firmware: unable to write kernel subkey\n");
|
return 1;
|
||||||
return 1;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_vbutil_firmware(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
|
||||||
static int do_vbutil_firmware(int argc, char* argv[]) {
|
char *filename = NULL;
|
||||||
|
char *key_block_file = NULL;
|
||||||
|
char *signpubkey = NULL;
|
||||||
|
char *signprivate = NULL;
|
||||||
|
uint64_t version = 0;
|
||||||
|
char *fv_file = NULL;
|
||||||
|
char *kernelkey_file = NULL;
|
||||||
|
uint32_t preamble_flags = 0;
|
||||||
|
int mode = 0;
|
||||||
|
int parse_error = 0;
|
||||||
|
char *e;
|
||||||
|
int i;
|
||||||
|
|
||||||
char* filename = NULL;
|
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
|
||||||
char* key_block_file = NULL;
|
switch (i) {
|
||||||
char* signpubkey = NULL;
|
case '?':
|
||||||
char* signprivate = NULL;
|
/* Unhandled option */
|
||||||
uint64_t version = 0;
|
printf("Unknown option\n");
|
||||||
char* fv_file = NULL;
|
parse_error = 1;
|
||||||
char* kernelkey_file = NULL;
|
break;
|
||||||
uint32_t preamble_flags = 0;
|
|
||||||
int mode = 0;
|
|
||||||
int parse_error = 0;
|
|
||||||
char* e;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
|
case OPT_MODE_VBLOCK:
|
||||||
switch (i) {
|
case OPT_MODE_VERIFY:
|
||||||
case '?':
|
mode = i;
|
||||||
/* Unhandled option */
|
filename = optarg;
|
||||||
printf("Unknown option\n");
|
break;
|
||||||
parse_error = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPT_MODE_VBLOCK:
|
case OPT_KEYBLOCK:
|
||||||
case OPT_MODE_VERIFY:
|
key_block_file = optarg;
|
||||||
mode = i;
|
break;
|
||||||
filename = optarg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPT_KEYBLOCK:
|
case OPT_SIGNPUBKEY:
|
||||||
key_block_file = optarg;
|
signpubkey = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_SIGNPUBKEY:
|
case OPT_SIGNPRIVATE:
|
||||||
signpubkey = optarg;
|
signprivate = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_SIGNPRIVATE:
|
case OPT_FV:
|
||||||
signprivate = optarg;
|
fv_file = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_FV:
|
case OPT_KERNELKEY:
|
||||||
fv_file = optarg;
|
kernelkey_file = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_KERNELKEY:
|
case OPT_VERSION:
|
||||||
kernelkey_file = optarg;
|
version = strtoul(optarg, &e, 0);
|
||||||
break;
|
if (!*optarg || (e && *e)) {
|
||||||
|
printf("Invalid --version\n");
|
||||||
|
parse_error = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OPT_VERSION:
|
case OPT_FLAGS:
|
||||||
version = strtoul(optarg, &e, 0);
|
preamble_flags = strtoul(optarg, &e, 0);
|
||||||
if (!*optarg || (e && *e)) {
|
if (!*optarg || (e && *e)) {
|
||||||
printf("Invalid --version\n");
|
printf("Invalid --flags\n");
|
||||||
parse_error = 1;
|
parse_error = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case OPT_FLAGS:
|
if (parse_error)
|
||||||
preamble_flags = strtoul(optarg, &e, 0);
|
return PrintHelp();
|
||||||
if (!*optarg || (e && *e)) {
|
|
||||||
printf("Invalid --flags\n");
|
|
||||||
parse_error = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parse_error)
|
switch (mode) {
|
||||||
return PrintHelp();
|
case OPT_MODE_VBLOCK:
|
||||||
|
return Vblock(filename, key_block_file, signprivate, version,
|
||||||
switch(mode) {
|
fv_file, kernelkey_file, preamble_flags);
|
||||||
case OPT_MODE_VBLOCK:
|
case OPT_MODE_VERIFY:
|
||||||
return Vblock(filename, key_block_file, signprivate, version, fv_file,
|
return Verify(filename, signpubkey, fv_file, kernelkey_file);
|
||||||
kernelkey_file, preamble_flags);
|
default:
|
||||||
case OPT_MODE_VERIFY:
|
printf("Must specify a mode.\n");
|
||||||
return Verify(filename, signpubkey, fv_file, kernelkey_file);
|
return PrintHelp();
|
||||||
default:
|
}
|
||||||
printf("Must specify a mode.\n");
|
|
||||||
return PrintHelp();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware,
|
DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <inttypes.h> /* For PRIu64 */
|
#include <inttypes.h> /* For PRIu64 */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -18,224 +18,227 @@
|
|||||||
#include "util_misc.h"
|
#include "util_misc.h"
|
||||||
#include "vboot_common.h"
|
#include "vboot_common.h"
|
||||||
|
|
||||||
|
|
||||||
/* Command line options */
|
/* Command line options */
|
||||||
enum {
|
enum {
|
||||||
OPT_INKEY = 1000,
|
OPT_INKEY = 1000,
|
||||||
OPT_KEY_VERSION,
|
OPT_KEY_VERSION,
|
||||||
OPT_ALGORITHM,
|
OPT_ALGORITHM,
|
||||||
OPT_MODE_PACK,
|
OPT_MODE_PACK,
|
||||||
OPT_MODE_UNPACK,
|
OPT_MODE_UNPACK,
|
||||||
OPT_COPYTO,
|
OPT_COPYTO,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option long_opts[] = {
|
static const struct option long_opts[] = {
|
||||||
{"key", 1, 0, OPT_INKEY },
|
{"key", 1, 0, OPT_INKEY},
|
||||||
{"version", 1, 0, OPT_KEY_VERSION },
|
{"version", 1, 0, OPT_KEY_VERSION},
|
||||||
{"algorithm", 1, 0, OPT_ALGORITHM },
|
{"algorithm", 1, 0, OPT_ALGORITHM},
|
||||||
{"pack", 1, 0, OPT_MODE_PACK },
|
{"pack", 1, 0, OPT_MODE_PACK},
|
||||||
{"unpack", 1, 0, OPT_MODE_UNPACK },
|
{"unpack", 1, 0, OPT_MODE_UNPACK},
|
||||||
{"copyto", 1, 0, OPT_COPYTO },
|
{"copyto", 1, 0, OPT_COPYTO},
|
||||||
{NULL, 0, 0, 0}
|
{NULL, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Print help and return error */
|
/* Print help and return error */
|
||||||
static int PrintHelp(char *progname) {
|
static int PrintHelp(char *progname)
|
||||||
int i;
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"This program wraps RSA keys with verified boot headers\n");
|
"This program wraps RSA keys with verified boot headers\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"\n"
|
"\n"
|
||||||
"Usage: %s --pack <outfile> [PARAMETERS]\n"
|
"Usage: %s --pack <outfile> [PARAMETERS]\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Required parameters:\n"
|
" Required parameters:\n"
|
||||||
" --key <infile> RSA key file (.keyb or .pem)\n"
|
" --key <infile> RSA key file (.keyb or .pem)\n"
|
||||||
" --version <number> Key version number "
|
" --version <number> Key version number "
|
||||||
"(required for .keyb,\n"
|
"(required for .keyb,\n"
|
||||||
" ignored for .pem)\n"
|
" ignored for .pem)\n"
|
||||||
" --algorithm <number> "
|
" --algorithm <number> "
|
||||||
"Signing algorithm to use with key:\n",
|
"Signing algorithm to use with key:\n", progname);
|
||||||
progname);
|
|
||||||
|
|
||||||
for (i = 0; i < kNumAlgorithms; i++) {
|
for (i = 0; i < kNumAlgorithms; i++) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" %d = (%s)\n",
|
" %d = (%s)\n",
|
||||||
i, algo_strings[i]);
|
i, algo_strings[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"\nOR\n\n"
|
"\nOR\n\n"
|
||||||
"Usage: %s --unpack <infile>\n"
|
"Usage: %s --unpack <infile>\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Optional parameters:\n"
|
" Optional parameters:\n"
|
||||||
" --copyto <file> "
|
" --copyto <file> "
|
||||||
"Write a copy of the key to this file.\n"
|
"Write a copy of the key to this file.\n" "\n", progname);
|
||||||
"\n",
|
|
||||||
progname);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pack a .keyb file into a .vbpubk, or a .pem into a .vbprivk */
|
/* Pack a .keyb file into a .vbpubk, or a .pem into a .vbprivk */
|
||||||
static int Pack(const char *infile, const char *outfile, uint64_t algorithm,
|
static int Pack(const char *infile, const char *outfile, uint64_t algorithm,
|
||||||
uint64_t version) {
|
uint64_t version)
|
||||||
VbPublicKey* pubkey;
|
{
|
||||||
VbPrivateKey* privkey;
|
VbPublicKey *pubkey;
|
||||||
|
VbPrivateKey *privkey;
|
||||||
|
|
||||||
if (!infile || !outfile) {
|
if (!infile || !outfile) {
|
||||||
fprintf(stderr, "vbutil_key: Must specify --in and --out\n");
|
fprintf(stderr, "vbutil_key: Must specify --in and --out\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pubkey = PublicKeyReadKeyb(infile, algorithm, version))) {
|
if ((pubkey = PublicKeyReadKeyb(infile, algorithm, version))) {
|
||||||
if (0 != PublicKeyWrite(outfile, pubkey)) {
|
if (0 != PublicKeyWrite(outfile, pubkey)) {
|
||||||
fprintf(stderr, "vbutil_key: Error writing key.\n");
|
fprintf(stderr, "vbutil_key: Error writing key.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
free(pubkey);
|
free(pubkey);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((privkey = PrivateKeyReadPem(infile, algorithm))) {
|
if ((privkey = PrivateKeyReadPem(infile, algorithm))) {
|
||||||
if (0 != PrivateKeyWrite(outfile, privkey)) {
|
if (0 != PrivateKeyWrite(outfile, privkey)) {
|
||||||
fprintf(stderr, "vbutil_key: Error writing key.\n");
|
fprintf(stderr, "vbutil_key: Error writing key.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
free(privkey);
|
free(privkey);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
VbExError("Unable to parse either .keyb or .pem from %s\n", infile);
|
VbExError("Unable to parse either .keyb or .pem from %s\n", infile);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Unpack a .vbpubk or .vbprivk */
|
/* Unpack a .vbpubk or .vbprivk */
|
||||||
static int Unpack(const char *infile, const char *outfile) {
|
static int Unpack(const char *infile, const char *outfile)
|
||||||
VbPublicKey* pubkey;
|
{
|
||||||
VbPrivateKey* privkey;
|
VbPublicKey *pubkey;
|
||||||
|
VbPrivateKey *privkey;
|
||||||
|
|
||||||
if (!infile) {
|
if (!infile) {
|
||||||
fprintf(stderr, "Need file to unpack\n");
|
fprintf(stderr, "Need file to unpack\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pubkey = PublicKeyRead(infile))) {
|
if ((pubkey = PublicKeyRead(infile))) {
|
||||||
printf("Public Key file: %s\n", infile);
|
printf("Public Key file: %s\n", infile);
|
||||||
printf("Algorithm: %" PRIu64 " %s\n", pubkey->algorithm,
|
printf("Algorithm: %" PRIu64 " %s\n", pubkey->algorithm,
|
||||||
(pubkey->algorithm < kNumAlgorithms ?
|
(pubkey->algorithm < kNumAlgorithms ?
|
||||||
algo_strings[pubkey->algorithm] : "(invalid)"));
|
algo_strings[pubkey->algorithm] : "(invalid)"));
|
||||||
printf("Key Version: %" PRIu64 "\n", pubkey->key_version);
|
printf("Key Version: %" PRIu64 "\n", pubkey->key_version);
|
||||||
printf("Key sha1sum: ");
|
printf("Key sha1sum: ");
|
||||||
PrintPubKeySha1Sum(pubkey);
|
PrintPubKeySha1Sum(pubkey);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
if (outfile) {
|
if (outfile) {
|
||||||
if (0 != PublicKeyWrite(outfile, pubkey)) {
|
if (0 != PublicKeyWrite(outfile, pubkey)) {
|
||||||
fprintf(stderr, "vbutil_key: Error writing key copy.\n");
|
fprintf(stderr,
|
||||||
free(pubkey);
|
"vbutil_key: Error writing key copy\n");
|
||||||
return 1;
|
free(pubkey);
|
||||||
}
|
return 1;
|
||||||
}
|
}
|
||||||
free(pubkey);
|
}
|
||||||
return 0;
|
free(pubkey);
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((privkey = PrivateKeyRead(infile))) {
|
if ((privkey = PrivateKeyRead(infile))) {
|
||||||
printf("Private Key file: %s\n", infile);
|
printf("Private Key file: %s\n", infile);
|
||||||
printf("Algorithm: %" PRIu64 " %s\n", privkey->algorithm,
|
printf("Algorithm: %" PRIu64 " %s\n",
|
||||||
(privkey->algorithm < kNumAlgorithms ?
|
privkey->algorithm,
|
||||||
algo_strings[privkey->algorithm] : "(invalid)"));
|
(privkey->algorithm <
|
||||||
if (outfile) {
|
kNumAlgorithms ? algo_strings[privkey->
|
||||||
if (0 != PrivateKeyWrite(outfile, privkey)) {
|
algorithm] :
|
||||||
fprintf(stderr, "vbutil_key: Error writing key copy.\n");
|
"(invalid)"));
|
||||||
free(privkey);
|
if (outfile) {
|
||||||
return 1;
|
if (0 != PrivateKeyWrite(outfile, privkey)) {
|
||||||
}
|
fprintf(stderr,
|
||||||
}
|
"vbutil_key: Error writing key copy\n");
|
||||||
free(privkey);
|
free(privkey);
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
free(privkey);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
VbExError("Unable to parse either .vbpubk or vbprivk from %s\n", infile);
|
VbExError("Unable to parse either .vbpubk or vbprivk from %s\n",
|
||||||
return 1;
|
infile);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_vbutil_key(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
|
||||||
static int do_vbutil_key(int argc, char* argv[]) {
|
char *infile = NULL;
|
||||||
|
char *outfile = NULL;
|
||||||
|
int mode = 0;
|
||||||
|
int parse_error = 0;
|
||||||
|
uint64_t version = 1;
|
||||||
|
uint64_t algorithm = kNumAlgorithms;
|
||||||
|
char *e;
|
||||||
|
int i;
|
||||||
|
|
||||||
char *infile = NULL;
|
char *progname = strrchr(argv[0], '/');
|
||||||
char *outfile = NULL;
|
if (progname)
|
||||||
int mode = 0;
|
progname++;
|
||||||
int parse_error = 0;
|
else
|
||||||
uint64_t version = 1;
|
progname = argv[0];
|
||||||
uint64_t algorithm = kNumAlgorithms;
|
|
||||||
char* e;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
char *progname = strrchr(argv[0], '/');
|
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
|
||||||
if (progname)
|
switch (i) {
|
||||||
progname++;
|
case '?':
|
||||||
else
|
/* Unhandled option */
|
||||||
progname = argv[0];
|
VbExError("Unknown option\n");
|
||||||
|
parse_error = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
|
case OPT_INKEY:
|
||||||
switch (i) {
|
infile = optarg;
|
||||||
case '?':
|
break;
|
||||||
/* Unhandled option */
|
|
||||||
VbExError("Unknown option\n");
|
|
||||||
parse_error = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPT_INKEY:
|
case OPT_KEY_VERSION:
|
||||||
infile = optarg;
|
version = strtoul(optarg, &e, 0);
|
||||||
break;
|
if (!*optarg || (e && *e)) {
|
||||||
|
VbExError("Invalid --version\n");
|
||||||
|
parse_error = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OPT_KEY_VERSION:
|
case OPT_ALGORITHM:
|
||||||
version = strtoul(optarg, &e, 0);
|
algorithm = strtoul(optarg, &e, 0);
|
||||||
if (!*optarg || (e && *e)) {
|
if (!*optarg || (e && *e)) {
|
||||||
VbExError("Invalid --version\n");
|
VbExError("Invalid --algorithm\n");
|
||||||
parse_error = 1;
|
parse_error = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_ALGORITHM:
|
case OPT_MODE_PACK:
|
||||||
algorithm = strtoul(optarg, &e, 0);
|
mode = i;
|
||||||
if (!*optarg || (e && *e)) {
|
outfile = optarg;
|
||||||
VbExError("Invalid --algorithm\n");
|
break;
|
||||||
parse_error = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPT_MODE_PACK:
|
case OPT_MODE_UNPACK:
|
||||||
mode = i;
|
mode = i;
|
||||||
outfile = optarg;
|
infile = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_MODE_UNPACK:
|
case OPT_COPYTO:
|
||||||
mode = i;
|
outfile = optarg;
|
||||||
infile = optarg;
|
break;
|
||||||
break;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case OPT_COPYTO:
|
if (parse_error)
|
||||||
outfile = optarg;
|
return PrintHelp(progname);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parse_error)
|
switch (mode) {
|
||||||
return PrintHelp(progname);
|
case OPT_MODE_PACK:
|
||||||
|
return Pack(infile, outfile, algorithm, version);
|
||||||
switch(mode) {
|
case OPT_MODE_UNPACK:
|
||||||
case OPT_MODE_PACK:
|
return Unpack(infile, outfile);
|
||||||
return Pack(infile, outfile, algorithm, version);
|
default:
|
||||||
case OPT_MODE_UNPACK:
|
printf("Must specify a mode.\n");
|
||||||
return Unpack(infile, outfile);
|
return PrintHelp(progname);
|
||||||
default:
|
}
|
||||||
printf("Must specify a mode.\n");
|
|
||||||
return PrintHelp(progname);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_FUTIL_COMMAND(vbutil_key, do_vbutil_key,
|
DECLARE_FUTIL_COMMAND(vbutil_key, do_vbutil_key,
|
||||||
|
|||||||
@@ -17,312 +17,324 @@
|
|||||||
#include "util_misc.h"
|
#include "util_misc.h"
|
||||||
#include "vboot_common.h"
|
#include "vboot_common.h"
|
||||||
|
|
||||||
|
|
||||||
/* Command line options */
|
/* Command line options */
|
||||||
enum {
|
enum {
|
||||||
OPT_MODE_PACK = 1000,
|
OPT_MODE_PACK = 1000,
|
||||||
OPT_MODE_UNPACK,
|
OPT_MODE_UNPACK,
|
||||||
OPT_DATAPUBKEY,
|
OPT_DATAPUBKEY,
|
||||||
OPT_SIGNPUBKEY,
|
OPT_SIGNPUBKEY,
|
||||||
OPT_SIGNPRIVATE,
|
OPT_SIGNPRIVATE,
|
||||||
OPT_SIGNPRIVATE_PEM,
|
OPT_SIGNPRIVATE_PEM,
|
||||||
OPT_PEM_ALGORITHM,
|
OPT_PEM_ALGORITHM,
|
||||||
OPT_EXTERNAL_SIGNER,
|
OPT_EXTERNAL_SIGNER,
|
||||||
OPT_FLAGS,
|
OPT_FLAGS,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option long_opts[] = {
|
static const struct option long_opts[] = {
|
||||||
{"pack", 1, 0, OPT_MODE_PACK },
|
{"pack", 1, 0, OPT_MODE_PACK},
|
||||||
{"unpack", 1, 0, OPT_MODE_UNPACK },
|
{"unpack", 1, 0, OPT_MODE_UNPACK},
|
||||||
{"datapubkey", 1, 0, OPT_DATAPUBKEY },
|
{"datapubkey", 1, 0, OPT_DATAPUBKEY},
|
||||||
{"signpubkey", 1, 0, OPT_SIGNPUBKEY },
|
{"signpubkey", 1, 0, OPT_SIGNPUBKEY},
|
||||||
{"signprivate", 1, 0, OPT_SIGNPRIVATE },
|
{"signprivate", 1, 0, OPT_SIGNPRIVATE},
|
||||||
{"signprivate_pem", 1, 0, OPT_SIGNPRIVATE_PEM },
|
{"signprivate_pem", 1, 0, OPT_SIGNPRIVATE_PEM},
|
||||||
{"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM },
|
{"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM},
|
||||||
{"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER },
|
{"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER},
|
||||||
{"flags", 1, 0, OPT_FLAGS },
|
{"flags", 1, 0, OPT_FLAGS},
|
||||||
{NULL, 0, 0, 0}
|
{NULL, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char usage[] =
|
||||||
|
"Verified boot key block utility\n"
|
||||||
|
"\n"
|
||||||
|
"Usage: %s <--pack|--unpack> <file> [OPTIONS]\n"
|
||||||
|
"\n"
|
||||||
|
"For '--pack <file>', required OPTIONS are:\n"
|
||||||
|
" --datapubkey <file> Data public key in .vbpubk format\n"
|
||||||
|
"\n"
|
||||||
|
"Optional OPTIONS are:\n"
|
||||||
|
" --signprivate <file>"
|
||||||
|
" Signing private key in .vbprivk format.\n"
|
||||||
|
"OR\n"
|
||||||
|
" --signprivate_pem <file>\n"
|
||||||
|
" --pem_algorithm <algo>\n"
|
||||||
|
" Signing private key in .pem format and algorithm id.\n"
|
||||||
|
"(If one of the above arguments is not specified, the keyblock will\n"
|
||||||
|
"not be signed.)\n"
|
||||||
|
"\n"
|
||||||
|
" --flags <number> Specifies allowed use conditions.\n"
|
||||||
|
" --externalsigner \"cmd\""
|
||||||
|
" Use an external program cmd to calculate the signatures.\n"
|
||||||
|
"\n"
|
||||||
|
"For '--unpack <file>', optional OPTIONS are:\n"
|
||||||
|
" --signpubkey <file>"
|
||||||
|
" Signing public key in .vbpubk format. This is required to\n"
|
||||||
|
" verify a signed keyblock.\n"
|
||||||
|
" --datapubkey <file>"
|
||||||
|
" Write the data public key to this file.\n";
|
||||||
|
|
||||||
/* Print help and return error */
|
/* Print help and return error */
|
||||||
static int PrintHelp(char *progname) {
|
static int PrintHelp(char *progname)
|
||||||
fprintf(stderr,
|
{
|
||||||
"Verified boot key block utility\n"
|
fprintf(stderr, usage, progname);
|
||||||
"\n"
|
return 1;
|
||||||
"Usage: %s <--pack|--unpack> <file> [OPTIONS]\n"
|
|
||||||
"\n"
|
|
||||||
"For '--pack <file>', required OPTIONS are:\n"
|
|
||||||
" --datapubkey <file> Data public key in .vbpubk format\n"
|
|
||||||
"\n"
|
|
||||||
"Optional OPTIONS are:\n"
|
|
||||||
" --signprivate <file>"
|
|
||||||
" Signing private key in .vbprivk format.\n"
|
|
||||||
"OR\n"
|
|
||||||
" --signprivate_pem <file>\n"
|
|
||||||
" --pem_algorithm <algo>\n"
|
|
||||||
" Signing private key in .pem format and algorithm id.\n"
|
|
||||||
"(If one of the above arguments is not specified, the keyblock will\n"
|
|
||||||
"not be signed.)\n"
|
|
||||||
"\n"
|
|
||||||
" --flags <number> Specifies allowed use conditions.\n"
|
|
||||||
" --externalsigner \"cmd\""
|
|
||||||
" Use an external program cmd to calculate the signatures.\n"
|
|
||||||
"\n"
|
|
||||||
"For '--unpack <file>', optional OPTIONS are:\n"
|
|
||||||
" --signpubkey <file>"
|
|
||||||
" Signing public key in .vbpubk format. This is required to\n"
|
|
||||||
" verify a signed keyblock.\n"
|
|
||||||
" --datapubkey <file>"
|
|
||||||
" Write the data public key to this file.\n",
|
|
||||||
progname);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pack a .keyblock */
|
/* Pack a .keyblock */
|
||||||
static int Pack(const char* outfile, const char* datapubkey,
|
static int Pack(const char *outfile, const char *datapubkey,
|
||||||
const char* signprivate,
|
const char *signprivate,
|
||||||
const char* signprivate_pem, uint64_t pem_algorithm,
|
const char *signprivate_pem, uint64_t pem_algorithm,
|
||||||
uint64_t flags,
|
uint64_t flags, const char *external_signer)
|
||||||
const char* external_signer) {
|
{
|
||||||
VbPublicKey* data_key;
|
VbPublicKey *data_key;
|
||||||
VbPrivateKey* signing_key = NULL;
|
VbPrivateKey *signing_key = NULL;
|
||||||
VbKeyBlockHeader* block;
|
VbKeyBlockHeader *block;
|
||||||
|
|
||||||
if (!outfile) {
|
if (!outfile) {
|
||||||
fprintf(stderr, "vbutil_keyblock: Must specify output filename.\n");
|
fprintf(stderr,
|
||||||
return 1;
|
"vbutil_keyblock: Must specify output filename.\n");
|
||||||
}
|
return 1;
|
||||||
if (!datapubkey) {
|
}
|
||||||
fprintf(stderr, "vbutil_keyblock: Must specify data public key.\n");
|
if (!datapubkey) {
|
||||||
return 1;
|
fprintf(stderr,
|
||||||
}
|
"vbutil_keyblock: Must specify data public key.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
data_key = PublicKeyRead(datapubkey);
|
data_key = PublicKeyRead(datapubkey);
|
||||||
if (!data_key) {
|
if (!data_key) {
|
||||||
fprintf(stderr, "vbutil_keyblock: Error reading data key.\n");
|
fprintf(stderr, "vbutil_keyblock: Error reading data key.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signprivate_pem) {
|
if (signprivate_pem) {
|
||||||
if (pem_algorithm >= kNumAlgorithms) {
|
if (pem_algorithm >= kNumAlgorithms) {
|
||||||
fprintf(stderr, "vbutil_keyblock: Invalid --pem_algorithm %" PRIu64 "\n",
|
fprintf(stderr,
|
||||||
pem_algorithm);
|
"vbutil_keyblock: Invalid --pem_algorithm %"
|
||||||
return 1;
|
PRIu64 "\n", pem_algorithm);
|
||||||
}
|
return 1;
|
||||||
if (external_signer) {
|
}
|
||||||
/* External signing uses the PEM file directly. */
|
if (external_signer) {
|
||||||
block = KeyBlockCreate_external(data_key,
|
/* External signing uses the PEM file directly. */
|
||||||
signprivate_pem, pem_algorithm,
|
block = KeyBlockCreate_external(data_key,
|
||||||
flags,
|
signprivate_pem,
|
||||||
external_signer);
|
pem_algorithm, flags,
|
||||||
} else {
|
external_signer);
|
||||||
signing_key = PrivateKeyReadPem(signprivate_pem, pem_algorithm);
|
} else {
|
||||||
if (!signing_key) {
|
signing_key =
|
||||||
fprintf(stderr, "vbutil_keyblock: Error reading signing key.\n");
|
PrivateKeyReadPem(signprivate_pem, pem_algorithm);
|
||||||
return 1;
|
if (!signing_key) {
|
||||||
}
|
fprintf(stderr, "vbutil_keyblock:"
|
||||||
block = KeyBlockCreate(data_key, signing_key, flags);
|
" Error reading signing key.\n");
|
||||||
}
|
return 1;
|
||||||
} else {
|
}
|
||||||
if (signprivate) {
|
block = KeyBlockCreate(data_key, signing_key, flags);
|
||||||
signing_key = PrivateKeyRead(signprivate);
|
}
|
||||||
if (!signing_key) {
|
} else {
|
||||||
fprintf(stderr, "vbutil_keyblock: Error reading signing key.\n");
|
if (signprivate) {
|
||||||
return 1;
|
signing_key = PrivateKeyRead(signprivate);
|
||||||
}
|
if (!signing_key) {
|
||||||
}
|
fprintf(stderr, "vbutil_keyblock:"
|
||||||
block = KeyBlockCreate(data_key, signing_key, flags);
|
" Error reading signing key.\n");
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block = KeyBlockCreate(data_key, signing_key, flags);
|
||||||
|
}
|
||||||
|
|
||||||
free(data_key);
|
free(data_key);
|
||||||
if (signing_key)
|
if (signing_key)
|
||||||
free(signing_key);
|
free(signing_key);
|
||||||
|
|
||||||
if (0 != KeyBlockWrite(outfile, block)) {
|
if (0 != KeyBlockWrite(outfile, block)) {
|
||||||
fprintf(stderr, "vbutil_keyblock: Error writing key block.\n");
|
fprintf(stderr, "vbutil_keyblock: Error writing key block.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
free(block);
|
free(block);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Unpack(const char* infile, const char* datapubkey,
|
static int Unpack(const char *infile, const char *datapubkey,
|
||||||
const char* signpubkey) {
|
const char *signpubkey)
|
||||||
VbPublicKey* data_key;
|
{
|
||||||
VbPublicKey* sign_key = NULL;
|
VbPublicKey *data_key;
|
||||||
VbKeyBlockHeader* block;
|
VbPublicKey *sign_key = NULL;
|
||||||
|
VbKeyBlockHeader *block;
|
||||||
|
|
||||||
if (!infile) {
|
if (!infile) {
|
||||||
fprintf(stderr, "vbutil_keyblock: Must specify filename\n");
|
fprintf(stderr, "vbutil_keyblock: Must specify filename\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
block = KeyBlockRead(infile);
|
block = KeyBlockRead(infile);
|
||||||
if (!block) {
|
if (!block) {
|
||||||
fprintf(stderr, "vbutil_keyblock: Error reading key block.\n");
|
fprintf(stderr, "vbutil_keyblock: Error reading key block.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the block is signed, then verify it with the signing public key, since
|
/* If the block is signed, then verify it with the signing public key,
|
||||||
KeyBlockRead() only verified the hash. */
|
* since KeyBlockRead() only verified the hash. */
|
||||||
if (block->key_block_signature.sig_size && signpubkey) {
|
if (block->key_block_signature.sig_size && signpubkey) {
|
||||||
sign_key = PublicKeyRead(signpubkey);
|
sign_key = PublicKeyRead(signpubkey);
|
||||||
if (!sign_key) {
|
if (!sign_key) {
|
||||||
fprintf(stderr, "vbutil_keyblock: Error reading signpubkey.\n");
|
fprintf(stderr,
|
||||||
return 1;
|
"vbutil_keyblock: Error reading signpubkey.\n");
|
||||||
}
|
return 1;
|
||||||
if (0 != KeyBlockVerify(block, block->key_block_size, sign_key, 0)) {
|
}
|
||||||
fprintf(stderr, "vbutil_keyblock: Error verifying key block.\n");
|
if (0 !=
|
||||||
return 1;
|
KeyBlockVerify(block, block->key_block_size, sign_key, 0)) {
|
||||||
}
|
fprintf(stderr, "vbutil_keyblock:"
|
||||||
free(sign_key);
|
" Error verifying key block.\n");
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
|
free(sign_key);
|
||||||
|
}
|
||||||
|
|
||||||
printf("Key block file: %s\n", infile);
|
printf("Key block file: %s\n", infile);
|
||||||
printf("Signature %s\n", sign_key ? "valid" : "ignored");
|
printf("Signature %s\n", sign_key ? "valid" : "ignored");
|
||||||
printf("Flags: %" PRIu64 " ", block->key_block_flags);
|
printf("Flags: %" PRIu64 " ", block->key_block_flags);
|
||||||
if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
|
if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
|
||||||
printf(" !DEV");
|
printf(" !DEV");
|
||||||
if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
|
if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
|
||||||
printf(" DEV");
|
printf(" DEV");
|
||||||
if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
|
if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
|
||||||
printf(" !REC");
|
printf(" !REC");
|
||||||
if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
|
if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
|
||||||
printf(" REC");
|
printf(" REC");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
data_key = &block->data_key;
|
data_key = &block->data_key;
|
||||||
printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
|
printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
|
||||||
(data_key->algorithm < kNumAlgorithms ?
|
(data_key->algorithm < kNumAlgorithms ?
|
||||||
algo_strings[data_key->algorithm] : "(invalid)"));
|
algo_strings[data_key->algorithm] : "(invalid)"));
|
||||||
printf("Data key version: %" PRIu64 "\n", data_key->key_version);
|
printf("Data key version: %" PRIu64 "\n", data_key->key_version);
|
||||||
printf("Data key sha1sum: ");
|
printf("Data key sha1sum: ");
|
||||||
PrintPubKeySha1Sum(data_key);
|
PrintPubKeySha1Sum(data_key);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
if (datapubkey) {
|
if (datapubkey) {
|
||||||
if (0 != PublicKeyWrite(datapubkey, data_key)) {
|
if (0 != PublicKeyWrite(datapubkey, data_key)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr, "vbutil_keyblock:"
|
||||||
"vbutil_keyblock: unable to write public key\n");
|
" unable to write public key\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(block);
|
free(block);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_vbutil_keyblock(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
|
||||||
static int do_vbutil_keyblock(int argc, char* argv[]) {
|
char *filename = NULL;
|
||||||
|
char *datapubkey = NULL;
|
||||||
|
char *signpubkey = NULL;
|
||||||
|
char *signprivate = NULL;
|
||||||
|
char *signprivate_pem = NULL;
|
||||||
|
char *external_signer = NULL;
|
||||||
|
uint64_t flags = 0;
|
||||||
|
uint64_t pem_algorithm = 0;
|
||||||
|
int is_pem_algorithm = 0;
|
||||||
|
int mode = 0;
|
||||||
|
int parse_error = 0;
|
||||||
|
char *e;
|
||||||
|
int i;
|
||||||
|
|
||||||
char* filename = NULL;
|
char *progname = strrchr(argv[0], '/');
|
||||||
char* datapubkey = NULL;
|
if (progname)
|
||||||
char* signpubkey = NULL;
|
progname++;
|
||||||
char* signprivate = NULL;
|
else
|
||||||
char* signprivate_pem = NULL;
|
progname = argv[0];
|
||||||
char* external_signer = NULL;
|
|
||||||
uint64_t flags = 0;
|
|
||||||
uint64_t pem_algorithm = 0;
|
|
||||||
int is_pem_algorithm = 0;
|
|
||||||
int mode = 0;
|
|
||||||
int parse_error = 0;
|
|
||||||
char* e;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
char *progname = strrchr(argv[0], '/');
|
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
|
||||||
if (progname)
|
switch (i) {
|
||||||
progname++;
|
case '?':
|
||||||
else
|
/* Unhandled option */
|
||||||
progname = argv[0];
|
printf("Unknown option\n");
|
||||||
|
parse_error = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
|
case OPT_MODE_PACK:
|
||||||
switch (i) {
|
case OPT_MODE_UNPACK:
|
||||||
case '?':
|
mode = i;
|
||||||
/* Unhandled option */
|
filename = optarg;
|
||||||
printf("Unknown option\n");
|
break;
|
||||||
parse_error = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPT_MODE_PACK:
|
case OPT_DATAPUBKEY:
|
||||||
case OPT_MODE_UNPACK:
|
datapubkey = optarg;
|
||||||
mode = i;
|
break;
|
||||||
filename = optarg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPT_DATAPUBKEY:
|
case OPT_SIGNPUBKEY:
|
||||||
datapubkey = optarg;
|
signpubkey = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_SIGNPUBKEY:
|
case OPT_SIGNPRIVATE:
|
||||||
signpubkey = optarg;
|
signprivate = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_SIGNPRIVATE:
|
case OPT_SIGNPRIVATE_PEM:
|
||||||
signprivate = optarg;
|
signprivate_pem = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_SIGNPRIVATE_PEM:
|
case OPT_PEM_ALGORITHM:
|
||||||
signprivate_pem = optarg;
|
pem_algorithm = strtoul(optarg, &e, 0);
|
||||||
break;
|
if (!*optarg || (e && *e)) {
|
||||||
|
fprintf(stderr, "Invalid --pem_algorithm\n");
|
||||||
|
parse_error = 1;
|
||||||
|
} else {
|
||||||
|
is_pem_algorithm = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OPT_PEM_ALGORITHM:
|
case OPT_EXTERNAL_SIGNER:
|
||||||
pem_algorithm = strtoul(optarg, &e, 0);
|
external_signer = optarg;
|
||||||
if (!*optarg || (e && *e)) {
|
break;
|
||||||
fprintf(stderr, "Invalid --pem_algorithm\n");
|
|
||||||
parse_error = 1;
|
|
||||||
} else {
|
|
||||||
is_pem_algorithm = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPT_EXTERNAL_SIGNER:
|
case OPT_FLAGS:
|
||||||
external_signer = optarg;
|
flags = strtoul(optarg, &e, 0);
|
||||||
break;
|
if (!*optarg || (e && *e)) {
|
||||||
|
fprintf(stderr, "Invalid --flags\n");
|
||||||
|
parse_error = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case OPT_FLAGS:
|
/* Check if the right combination of options was provided. */
|
||||||
flags = strtoul(optarg, &e, 0);
|
if (signprivate && signprivate_pem) {
|
||||||
if (!*optarg || (e && *e)) {
|
fprintf(stderr,
|
||||||
fprintf(stderr, "Invalid --flags\n");
|
"Only one of --signprivate or --signprivate_pem must"
|
||||||
parse_error = 1;
|
" be specified\n");
|
||||||
}
|
parse_error = 1;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the right combination of options was provided. */
|
if (signprivate_pem && !is_pem_algorithm) {
|
||||||
if (signprivate && signprivate_pem) {
|
fprintf(stderr, "--pem_algorithm must be used with"
|
||||||
fprintf(stderr, "Only one of --signprivate or --signprivate_pem must"
|
" --signprivate_pem\n");
|
||||||
" be specified\n");
|
parse_error = 1;
|
||||||
parse_error = 1;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (signprivate_pem && !is_pem_algorithm) {
|
if (external_signer && !signprivate_pem) {
|
||||||
fprintf(stderr, "--pem_algorithm must be used with --signprivate_pem\n");
|
fprintf(stderr,
|
||||||
parse_error = 1;
|
"--externalsigner must be used with --signprivate_pem"
|
||||||
}
|
"\n");
|
||||||
|
parse_error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (external_signer && !signprivate_pem) {
|
if (parse_error)
|
||||||
fprintf(stderr, "--externalsigner must be used with --signprivate_pem"
|
return PrintHelp(progname);
|
||||||
"\n");
|
|
||||||
parse_error = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parse_error)
|
switch (mode) {
|
||||||
return PrintHelp(progname);
|
case OPT_MODE_PACK:
|
||||||
|
return Pack(filename, datapubkey, signprivate,
|
||||||
switch(mode) {
|
signprivate_pem, pem_algorithm,
|
||||||
case OPT_MODE_PACK:
|
flags, external_signer);
|
||||||
return Pack(filename, datapubkey, signprivate,
|
case OPT_MODE_UNPACK:
|
||||||
signprivate_pem, pem_algorithm,
|
return Unpack(filename, datapubkey, signpubkey);
|
||||||
flags,
|
default:
|
||||||
external_signer);
|
printf("Must specify a mode.\n");
|
||||||
case OPT_MODE_UNPACK:
|
return PrintHelp(progname);
|
||||||
return Unpack(filename, datapubkey, signpubkey);
|
}
|
||||||
default:
|
|
||||||
printf("Must specify a mode.\n");
|
|
||||||
return PrintHelp(progname);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock,
|
DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock,
|
||||||
|
|||||||
@@ -14,106 +14,109 @@
|
|||||||
#include "vboot_api.h"
|
#include "vboot_api.h"
|
||||||
#include "vboot_host.h"
|
#include "vboot_host.h"
|
||||||
|
|
||||||
static uint8_t* GetKernelConfig(uint8_t* blob, size_t blob_size,
|
static uint8_t *GetKernelConfig(uint8_t * blob, size_t blob_size,
|
||||||
uint64_t kernel_body_load_address) {
|
uint64_t kernel_body_load_address)
|
||||||
|
{
|
||||||
|
|
||||||
VbKeyBlockHeader* key_block;
|
VbKeyBlockHeader *key_block;
|
||||||
VbKernelPreambleHeader* preamble;
|
VbKernelPreambleHeader *preamble;
|
||||||
uint32_t now = 0;
|
uint32_t now = 0;
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
|
|
||||||
/* Skip the key block */
|
/* Skip the key block */
|
||||||
key_block = (VbKeyBlockHeader*)blob;
|
key_block = (VbKeyBlockHeader *) blob;
|
||||||
now += key_block->key_block_size;
|
now += key_block->key_block_size;
|
||||||
if (now + blob > blob + blob_size) {
|
if (now + blob > blob + blob_size) {
|
||||||
VbExError("key_block_size advances past the end of the blob\n");
|
VbExError("key_block_size advances past the end of the blob\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open up the preamble */
|
/* Open up the preamble */
|
||||||
preamble = (VbKernelPreambleHeader*)(blob + now);
|
preamble = (VbKernelPreambleHeader *) (blob + now);
|
||||||
now += preamble->preamble_size;
|
now += preamble->preamble_size;
|
||||||
if (now + blob > blob + blob_size) {
|
if (now + blob > blob + blob_size) {
|
||||||
VbExError("preamble_size advances past the end of the blob\n");
|
VbExError("preamble_size advances past the end of the blob\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read body_load_address from preamble if no kernel_body_load_address */
|
/* Read body_load_address from preamble if no
|
||||||
if (kernel_body_load_address == USE_PREAMBLE_LOAD_ADDR)
|
* kernel_body_load_address */
|
||||||
kernel_body_load_address = preamble->body_load_address;
|
if (kernel_body_load_address == USE_PREAMBLE_LOAD_ADDR)
|
||||||
|
kernel_body_load_address = preamble->body_load_address;
|
||||||
|
|
||||||
/* The x86 kernels have a pointer to the kernel commandline in the zeropage
|
/* The x86 kernels have a pointer to the kernel commandline in the
|
||||||
* table, but that's irrelevant for ARM. Both types keep the config blob in
|
* zeropage table, but that's irrelevant for ARM. Both types keep the
|
||||||
* the same place, so just go find it. */
|
* config blob in the same place, so just go find it. */
|
||||||
offset = preamble->bootloader_address -
|
offset = preamble->bootloader_address -
|
||||||
(kernel_body_load_address + CROS_PARAMS_SIZE +
|
(kernel_body_load_address + CROS_PARAMS_SIZE +
|
||||||
CROS_CONFIG_SIZE) + now;
|
CROS_CONFIG_SIZE) + now;
|
||||||
if (offset > blob_size) {
|
if (offset > blob_size) {
|
||||||
VbExError("params are outside of the memory blob: %x\n", offset);
|
VbExError("params are outside of the memory blob: %x\n",
|
||||||
return NULL;
|
offset);
|
||||||
}
|
return NULL;
|
||||||
return blob + offset;
|
}
|
||||||
|
return blob + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* MMapFile(const char* filename, size_t *size) {
|
static void *MMapFile(const char *filename, size_t * size)
|
||||||
FILE* f;
|
{
|
||||||
uint8_t* buf;
|
FILE *f;
|
||||||
long file_size = 0;
|
uint8_t *buf;
|
||||||
|
long file_size = 0;
|
||||||
|
|
||||||
f = fopen(filename, "rb");
|
f = fopen(filename, "rb");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
VBDEBUG(("Unable to open file %s\n", filename));
|
VBDEBUG(("Unable to open file %s\n", filename));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
file_size = ftell(f);
|
file_size = ftell(f);
|
||||||
rewind(f);
|
rewind(f);
|
||||||
|
|
||||||
if (file_size <= 0) {
|
if (file_size <= 0) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*size = (size_t) file_size;
|
*size = (size_t) file_size;
|
||||||
|
|
||||||
/* Uses a host primitive as this is not meant for firmware use. */
|
/* Uses a host primitive as this is not meant for firmware use. */
|
||||||
buf = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, fileno(f), 0);
|
buf = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, fileno(f), 0);
|
||||||
if (buf == MAP_FAILED) {
|
if (buf == MAP_FAILED) {
|
||||||
VbExError("Failed to mmap the file %s\n", filename);
|
VbExError("Failed to mmap the file %s\n", filename);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char *FindKernelConfig(const char *infile, uint64_t kernel_body_load_address)
|
char *FindKernelConfig(const char *infile, uint64_t kernel_body_load_address)
|
||||||
{
|
{
|
||||||
uint8_t* blob;
|
uint8_t *blob;
|
||||||
size_t blob_size;
|
size_t blob_size;
|
||||||
uint8_t *config = NULL;
|
uint8_t *config = NULL;
|
||||||
char *newstr = NULL;
|
char *newstr = NULL;
|
||||||
|
|
||||||
blob = MMapFile(infile, &blob_size);
|
blob = MMapFile(infile, &blob_size);
|
||||||
if (!blob) {
|
if (!blob) {
|
||||||
VbExError("Error reading input file\n");
|
VbExError("Error reading input file\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
config = GetKernelConfig(blob, blob_size, kernel_body_load_address);
|
config = GetKernelConfig(blob, blob_size, kernel_body_load_address);
|
||||||
if (!config) {
|
if (!config) {
|
||||||
VbExError("Error parsing input file\n");
|
VbExError("Error parsing input file\n");
|
||||||
munmap(blob, blob_size);
|
munmap(blob, blob_size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
newstr = strndup((char *)config, CROS_CONFIG_SIZE);
|
newstr = strndup((char *)config, CROS_CONFIG_SIZE);
|
||||||
if (!newstr)
|
if (!newstr)
|
||||||
VbExError("Can't allocate new string\n");
|
VbExError("Can't allocate new string\n");
|
||||||
|
|
||||||
munmap(blob, blob_size);
|
munmap(blob, blob_size);
|
||||||
|
|
||||||
return newstr;
|
return newstr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
static const char * const usage= "\n\
|
static const char *const usage = "\n\
|
||||||
Usage: " MYNAME " PROGRAM|COMMAND [args...]\n\
|
Usage: " MYNAME " PROGRAM|COMMAND [args...]\n\
|
||||||
\n\
|
\n\
|
||||||
This is the unified firmware utility, which will eventually replace\n\
|
This is the unified firmware utility, which will eventually replace\n\
|
||||||
@@ -45,25 +45,26 @@ In either case it will append some usage information to " LOGFILE "\n\
|
|||||||
|
|
||||||
static int do_help(int argc, char *argv[])
|
static int do_help(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
const struct futil_cmd_t * const *cmd;
|
const struct futil_cmd_t *const *cmd;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
fputs(usage, stdout);
|
fputs(usage, stdout);
|
||||||
|
|
||||||
printf("The following commands are built-in:\n\n");
|
printf("The following commands are built-in:\n\n");
|
||||||
|
|
||||||
for (cmd = futil_cmds; *cmd; cmd++)
|
for (cmd = futil_cmds; *cmd; cmd++)
|
||||||
printf(" %-20s %s\n", (*cmd)->name, (*cmd)->shorthelp);
|
printf(" %-20s %s\n", (*cmd)->name, (*cmd)->shorthelp);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
if (argc) {
|
if (argc) {
|
||||||
printf("FYI, you added these args that I'm ignoring:\n");
|
printf("FYI, you added these args that I'm ignoring:\n");
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
printf("argv[%d] = %s\n", i, argv[i]);
|
printf("argv[%d] = %s\n", i, argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_FUTIL_COMMAND(help, do_help,
|
DECLARE_FUTIL_COMMAND(help, do_help,
|
||||||
"Show a bit of help (you're looking at it)");
|
"Show a bit of help (you're looking at it)");
|
||||||
|
|
||||||
@@ -71,11 +72,11 @@ DECLARE_FUTIL_COMMAND(help, do_help,
|
|||||||
* These are built-in functions that we'd like to abandon completely someday.
|
* These are built-in functions that we'd like to abandon completely someday.
|
||||||
* TODO: If no one complains, get rid of them.
|
* TODO: If no one complains, get rid of them.
|
||||||
*/
|
*/
|
||||||
static const char * const dep_cmds[] = {
|
static const char *const dep_cmds[] = {
|
||||||
"dev_sign_file",
|
"dev_sign_file",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const dep_usage= "\n\
|
static const char *const dep_usage = "\n\
|
||||||
The program \"%s\" is deprecated and may go away soon.\n\
|
The program \"%s\" is deprecated and may go away soon.\n\
|
||||||
\n\
|
\n\
|
||||||
If you feel this is in error, please open a bug at\n\
|
If you feel this is in error, please open a bug at\n\
|
||||||
@@ -89,8 +90,8 @@ In the meantime, you may continue to use the program by invoking it as\n\
|
|||||||
|
|
||||||
static void deprecated(const char *depname)
|
static void deprecated(const char *depname)
|
||||||
{
|
{
|
||||||
fprintf(stderr, dep_usage, depname, depname);
|
fprintf(stderr, dep_usage, depname, depname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -101,188 +102,187 @@ static int log_fd = -1;
|
|||||||
/* Write the string and a newline. Silently give up on errors */
|
/* Write the string and a newline. Silently give up on errors */
|
||||||
static void log_str(char *str)
|
static void log_str(char *str)
|
||||||
{
|
{
|
||||||
int len, done, n;
|
int len, done, n;
|
||||||
|
|
||||||
if (log_fd < 0)
|
if (log_fd < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!str)
|
if (!str)
|
||||||
str = "(NULL)";
|
str = "(NULL)";
|
||||||
|
|
||||||
len = strlen(str);
|
len = strlen(str);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
str = "(EMPTY)";
|
str = "(EMPTY)";
|
||||||
len = strlen(str);
|
len = strlen(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (done = 0; done < len; done += n) {
|
for (done = 0; done < len; done += n) {
|
||||||
n = write(log_fd, str + done, len - done);
|
n = write(log_fd, str + done, len - done);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write(log_fd, "\n", 1) < 0)
|
if (write(log_fd, "\n", 1) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_close(void)
|
static void log_close(void)
|
||||||
{
|
{
|
||||||
struct flock lock;
|
struct flock lock;
|
||||||
|
|
||||||
if (log_fd >= 0) {
|
if (log_fd >= 0) {
|
||||||
memset(&lock, 0, sizeof(lock));
|
memset(&lock, 0, sizeof(lock));
|
||||||
lock.l_type = F_UNLCK;
|
lock.l_type = F_UNLCK;
|
||||||
lock.l_whence = SEEK_SET;
|
lock.l_whence = SEEK_SET;
|
||||||
if (fcntl(log_fd, F_SETLKW, &lock))
|
if (fcntl(log_fd, F_SETLKW, &lock))
|
||||||
perror("Unable to unlock log file");
|
perror("Unable to unlock log file");
|
||||||
|
|
||||||
close(log_fd);
|
close(log_fd);
|
||||||
log_fd = -1;
|
log_fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_open(void)
|
static void log_open(void)
|
||||||
{
|
{
|
||||||
struct flock lock;
|
struct flock lock;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
#ifdef FORCE_LOGGING_ON
|
#ifdef FORCE_LOGGING_ON
|
||||||
log_fd = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666);
|
log_fd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666);
|
||||||
#else
|
#else
|
||||||
log_fd = open(LOGFILE, O_WRONLY|O_APPEND);
|
log_fd = open(LOGFILE, O_WRONLY | O_APPEND);
|
||||||
#endif
|
#endif
|
||||||
if (log_fd < 0) {
|
if (log_fd < 0) {
|
||||||
|
|
||||||
if (errno != EACCES)
|
if (errno != EACCES)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Permission problems should improve shortly ... */
|
/* Permission problems should improve shortly ... */
|
||||||
sleep(1);
|
sleep(1);
|
||||||
log_fd = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666);
|
log_fd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666);
|
||||||
if (log_fd < 0) /* Nope, they didn't */
|
if (log_fd < 0) /* Nope, they didn't */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Let anyone have a turn */
|
/* Let anyone have a turn */
|
||||||
fchmod(log_fd, 0666);
|
fchmod(log_fd, 0666);
|
||||||
|
|
||||||
/* But only one at a time */
|
/* But only one at a time */
|
||||||
memset(&lock, 0, sizeof(lock));
|
memset(&lock, 0, sizeof(lock));
|
||||||
lock.l_type = F_WRLCK;
|
lock.l_type = F_WRLCK;
|
||||||
lock.l_whence = SEEK_END;
|
lock.l_whence = SEEK_END;
|
||||||
|
|
||||||
ret = fcntl(log_fd, F_SETLKW, &lock); /* this blocks */
|
ret = fcntl(log_fd, F_SETLKW, &lock); /* this blocks */
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
log_close();
|
log_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CALLER_PREFIX "CALLER:"
|
#define CALLER_PREFIX "CALLER:"
|
||||||
static void log_args(int argc, char *argv[])
|
static void log_args(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
ssize_t r;
|
ssize_t r;
|
||||||
pid_t parent;
|
pid_t parent;
|
||||||
char buf[80];
|
char buf[80];
|
||||||
char str_caller[PATH_MAX + sizeof(CALLER_PREFIX)] = CALLER_PREFIX;
|
char str_caller[PATH_MAX + sizeof(CALLER_PREFIX)] = CALLER_PREFIX;
|
||||||
char *truename = str_caller + sizeof(CALLER_PREFIX) - 1;
|
char *truename = str_caller + sizeof(CALLER_PREFIX) - 1;
|
||||||
/* Note: truename starts on the \0 from CALLER_PREFIX, so we can write
|
/* Note: truename starts on the \0 from CALLER_PREFIX, so we can write
|
||||||
* PATH_MAX chars into truename and still append a \0 at the end. */
|
* PATH_MAX chars into truename and still append a \0 at the end. */
|
||||||
|
|
||||||
log_open();
|
log_open();
|
||||||
|
|
||||||
/* delimiter */
|
/* delimiter */
|
||||||
log_str("##### HEY #####");
|
log_str("##### HEY #####");
|
||||||
|
|
||||||
/* Can we tell who called us? */
|
/* Can we tell who called us? */
|
||||||
parent = getppid();
|
parent = getppid();
|
||||||
snprintf(buf, sizeof(buf), "/proc/%d/exe", parent);
|
snprintf(buf, sizeof(buf), "/proc/%d/exe", parent);
|
||||||
r = readlink(buf, truename, PATH_MAX);
|
r = readlink(buf, truename, PATH_MAX);
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
truename[r] = '\0';
|
truename[r] = '\0';
|
||||||
log_str(str_caller);
|
log_str(str_caller);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now log the stuff about ourselves */
|
/* Now log the stuff about ourselves */
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
log_str(argv[i]);
|
log_str(argv[i]);
|
||||||
|
|
||||||
log_close();
|
log_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Here we go */
|
/* Here we go */
|
||||||
|
|
||||||
int main(int argc, char *argv[], char *envp[])
|
int main(int argc, char *argv[], char *envp[])
|
||||||
{
|
{
|
||||||
char *fullname, *progname;
|
char *fullname, *progname;
|
||||||
char truename[PATH_MAX];
|
char truename[PATH_MAX];
|
||||||
char buf[80];
|
char buf[80];
|
||||||
pid_t myproc;
|
pid_t myproc;
|
||||||
ssize_t r;
|
ssize_t r;
|
||||||
const struct futil_cmd_t * const *cmd;
|
const struct futil_cmd_t *const *cmd;
|
||||||
int i;
|
int i;
|
||||||
int via_symlink = 0;
|
int via_symlink = 0;
|
||||||
|
|
||||||
log_args(argc, argv);
|
log_args(argc, argv);
|
||||||
|
|
||||||
/* How were we invoked? */
|
/* How were we invoked? */
|
||||||
fullname = strdup(argv[0]);
|
fullname = strdup(argv[0]);
|
||||||
progname = strrchr(argv[0], '/');
|
progname = strrchr(argv[0], '/');
|
||||||
if (progname)
|
if (progname)
|
||||||
progname++;
|
progname++;
|
||||||
else
|
else
|
||||||
progname = argv[0];
|
progname = argv[0];
|
||||||
|
|
||||||
/* Invoked directly by name */
|
/* Invoked directly by name */
|
||||||
if (0 == strcmp(progname, MYNAME) || 0 == strcmp(progname, MYNAME_S)) {
|
if (0 == strcmp(progname, MYNAME) || 0 == strcmp(progname, MYNAME_S)) {
|
||||||
if (argc < 2) { /* must have an argument */
|
if (argc < 2) { /* must have an argument */
|
||||||
do_help(0, 0);
|
do_help(0, 0);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can just pass the rest along, then */
|
/* We can just pass the rest along, then */
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
|
|
||||||
/* So now what function do we want to invoke? */
|
/* So now what function do we want to invoke? */
|
||||||
progname = strrchr(argv[0], '/');
|
progname = strrchr(argv[0], '/');
|
||||||
if (progname)
|
if (progname)
|
||||||
progname++;
|
progname++;
|
||||||
else
|
else
|
||||||
progname = argv[0];
|
progname = argv[0];
|
||||||
} else { /* Invoked by symlink */
|
} else { /* Invoked by symlink */
|
||||||
via_symlink = 1;
|
via_symlink = 1;
|
||||||
/* Block any deprecated functions. */
|
/* Block any deprecated functions. */
|
||||||
for (i = 0; i < ARRAY_SIZE(dep_cmds); i++)
|
for (i = 0; i < ARRAY_SIZE(dep_cmds); i++)
|
||||||
if (0 == strcmp(dep_cmds[i], progname))
|
if (0 == strcmp(dep_cmds[i], progname))
|
||||||
deprecated(progname);
|
deprecated(progname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if it's asking for something we know how to do ourselves */
|
/* See if it's asking for something we know how to do ourselves */
|
||||||
for (cmd = futil_cmds; *cmd; cmd++)
|
for (cmd = futil_cmds; *cmd; cmd++)
|
||||||
if (0 == strcmp((*cmd)->name, progname))
|
if (0 == strcmp((*cmd)->name, progname))
|
||||||
return (*cmd)->handler(argc, argv);
|
return (*cmd)->handler(argc, argv);
|
||||||
|
|
||||||
/* Nope */
|
/* Nope */
|
||||||
if (!via_symlink) {
|
if (!via_symlink) {
|
||||||
do_help(0, 0);
|
do_help(0, 0);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Complain about bogus symlink */
|
/* Complain about bogus symlink */
|
||||||
|
|
||||||
myproc = getpid();
|
myproc = getpid();
|
||||||
snprintf(buf, sizeof(buf), "/proc/%d/exe", myproc);
|
snprintf(buf, sizeof(buf), "/proc/%d/exe", myproc);
|
||||||
r = readlink(buf, truename, PATH_MAX - 1);
|
r = readlink(buf, truename, PATH_MAX - 1);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf(stderr, "%s is lost: %s => %s: %s\n", MYNAME, argv[0],
|
fprintf(stderr, "%s is lost: %s => %s: %s\n", MYNAME, argv[0],
|
||||||
buf, strerror(errno));
|
buf, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
truename[r] = '\0';
|
truename[r] = '\0';
|
||||||
|
|
||||||
fprintf(stderr, "\n\
|
fprintf(stderr, "\n\
|
||||||
The program\n\n %s\n\nis a symlink to\n\n %s\n\
|
The program\n\n %s\n\nis a symlink to\n\n %s\n\
|
||||||
\n\
|
\n\
|
||||||
However, " MYNAME " doesn't know how to implement that function.\n\
|
However, " MYNAME " doesn't know how to implement that function.\n\
|
||||||
@@ -292,5 +292,5 @@ after a fresh checkout/build/install, please open a bug at\n\
|
|||||||
\n\
|
\n\
|
||||||
http://dev.chromium.org/for-testers/bug-reporting-guidelines\n\
|
http://dev.chromium.org/for-testers/bug-reporting-guidelines\n\
|
||||||
\n", fullname, truename);
|
\n", fullname, truename);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
/* Here's a structure to define the commands that futility implements. */
|
/* Here's a structure to define the commands that futility implements. */
|
||||||
struct futil_cmd_t {
|
struct futil_cmd_t {
|
||||||
const char * const name;
|
const char *const name;
|
||||||
int (*const handler)(int argc, char **argv);
|
int (*const handler) (int argc, char **argv);
|
||||||
const char * const shorthelp;
|
const char *const shorthelp;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -33,7 +33,7 @@ struct futil_cmd_t {
|
|||||||
= &__cmd_##NAME
|
= &__cmd_##NAME
|
||||||
|
|
||||||
/* This is the list of pointers to all commands. */
|
/* This is the list of pointers to all commands. */
|
||||||
extern const struct futil_cmd_t * const futil_cmds[];
|
extern const struct futil_cmd_t *const futil_cmds[];
|
||||||
|
|
||||||
/* Size of an array */
|
/* Size of an array */
|
||||||
#ifndef ARRAY_SIZE
|
#ifndef ARRAY_SIZE
|
||||||
|
|||||||
@@ -1,65 +1,62 @@
|
|||||||
// Copyright 2010 The Chromium OS Authors. All rights reserved.
|
/* Copyright 2010 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
//
|
*
|
||||||
// Constants describing the kernel blob content.
|
* Constants describing the kernel blob content.
|
||||||
|
*/
|
||||||
#ifndef VBOOT_REFERENCE_KERNEL_BLOB_H_
|
#ifndef VBOOT_REFERENCE_KERNEL_BLOB_H_
|
||||||
#define VBOOT_REFERENCE_KERNEL_BLOB_H_
|
#define VBOOT_REFERENCE_KERNEL_BLOB_H_
|
||||||
|
|
||||||
|
/* Maximum kernel command-line size */
|
||||||
// Maximum kernel command-line size
|
|
||||||
#define CROS_CONFIG_SIZE 4096
|
#define CROS_CONFIG_SIZE 4096
|
||||||
|
|
||||||
// Size of the x86 zeropage table
|
/* Size of the x86 zeropage table */
|
||||||
#define CROS_PARAMS_SIZE 4096
|
#define CROS_PARAMS_SIZE 4096
|
||||||
|
|
||||||
// Alignment of various chunks within the kernel blob
|
/* Alignment of various chunks within the kernel blob */
|
||||||
#define CROS_ALIGN 4096
|
#define CROS_ALIGN 4096
|
||||||
|
|
||||||
// Sentinel RAM address indicating that no entry address is specified
|
/* Sentinel RAM address indicating that no entry address is specified */
|
||||||
#define CROS_NO_ENTRY_ADDR (~0)
|
#define CROS_NO_ENTRY_ADDR (~0)
|
||||||
|
|
||||||
// RAM address where the 32-bit kernel expects to be started
|
/* RAM address where the 32-bit kernel expects to be started */
|
||||||
#define CROS_32BIT_ENTRY_ADDR 0x100000
|
#define CROS_32BIT_ENTRY_ADDR 0x100000
|
||||||
|
|
||||||
// Simplified version of x86 kernel e820 memory map entries
|
/* Simplified version of x86 kernel e820 memory map entries */
|
||||||
#define E820_ENTRY_MAX 128
|
#define E820_ENTRY_MAX 128
|
||||||
#define E820_TYPE_RAM 1
|
#define E820_TYPE_RAM 1
|
||||||
#define E820_TYPE_RESERVED 2
|
#define E820_TYPE_RESERVED 2
|
||||||
|
|
||||||
struct linux_kernel_e820entry {
|
struct linux_kernel_e820entry {
|
||||||
uint64_t start_addr;
|
uint64_t start_addr;
|
||||||
uint64_t segment_size;
|
uint64_t segment_size;
|
||||||
uint32_t segment_type;
|
uint32_t segment_type;
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
// Simplified version of the x86 kernel zeropage table
|
|
||||||
struct linux_kernel_params
|
|
||||||
{
|
|
||||||
uint8_t pad0[0x1e8 - 0x0];
|
|
||||||
uint8_t n_e820_entry; // 1e8
|
|
||||||
uint8_t pad1[0x1f1 - 0x1e9];
|
|
||||||
uint8_t setup_sects; // 1f1
|
|
||||||
uint8_t pad2[0x1fe - 0x1f2];
|
|
||||||
uint16_t boot_flag; // 1fe
|
|
||||||
uint16_t jump; // 200
|
|
||||||
uint32_t header; // 202
|
|
||||||
uint16_t version; // 206
|
|
||||||
uint8_t pad3[0x210 - 0x208];
|
|
||||||
uint8_t type_of_loader; // 210
|
|
||||||
uint8_t pad4[0x218 - 0x211];
|
|
||||||
uint32_t ramdisk_image; // 218
|
|
||||||
uint32_t ramdisk_size; // 21c
|
|
||||||
uint8_t pad5[0x228 - 0x220];
|
|
||||||
uint32_t cmd_line_ptr; // 228
|
|
||||||
uint32_t ramdisk_max; // 22c
|
|
||||||
uint32_t kernel_alignment; // 230
|
|
||||||
uint8_t relocatable_kernel; // 234
|
|
||||||
uint8_t min_alignment; // 235
|
|
||||||
uint8_t pad6[0x2d0 - 0x236];
|
|
||||||
struct linux_kernel_e820entry e820_entries[E820_ENTRY_MAX]; // 2d0 - cd0
|
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
/* Simplified version of the x86 kernel zeropage table */
|
||||||
|
struct linux_kernel_params {
|
||||||
|
uint8_t pad0[0x1e8 - 0x0];
|
||||||
|
uint8_t n_e820_entry; /* 1e8 */
|
||||||
|
uint8_t pad1[0x1f1 - 0x1e9];
|
||||||
|
uint8_t setup_sects; /* 1f1 */
|
||||||
|
uint8_t pad2[0x1fe - 0x1f2];
|
||||||
|
uint16_t boot_flag; /* 1fe */
|
||||||
|
uint16_t jump; /* 200 */
|
||||||
|
uint32_t header; /* 202 */
|
||||||
|
uint16_t version; /* 206 */
|
||||||
|
uint8_t pad3[0x210 - 0x208];
|
||||||
|
uint8_t type_of_loader; /* 210 */
|
||||||
|
uint8_t pad4[0x218 - 0x211];
|
||||||
|
uint32_t ramdisk_image; /* 218 */
|
||||||
|
uint32_t ramdisk_size; /* 21c */
|
||||||
|
uint8_t pad5[0x228 - 0x220];
|
||||||
|
uint32_t cmd_line_ptr; /* 228 */
|
||||||
|
uint32_t ramdisk_max; /* 22c */
|
||||||
|
uint32_t kernel_alignment; /* 230 */
|
||||||
|
uint8_t relocatable_kernel; /* 234 */
|
||||||
|
uint8_t min_alignment; /* 235 */
|
||||||
|
uint8_t pad6[0x2d0 - 0x236];
|
||||||
|
struct linux_kernel_e820entry e820_entries[E820_ENTRY_MAX]; /* 2d0-cd0 */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
#endif // VBOOT_REFERENCE_KERNEL_BLOB_H_
|
#endif /* VBOOT_REFERENCE_KERNEL_BLOB_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user