mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 18:25:10 +00:00
vboot: Add flag to vbutil_kernel for reconstruction of vmlinuz image
Adding functionality to allow for rebuilding of vmlinuz after it
has been processed into vblock and header stripped. Basically appends
the 16-bit header of a vmlinuz image onto the end of the vblock.
BUG=chromium:438302
BRANCH=none
TEST=Successfully ran "make runalltests".
Also, ran:
1. Repack kernel block (so that 16-bit header is included):
"vbutil_kernel --pack kern_0 ..."
2. Verify kernel: "vbutil_kernel --verify kern_0 ... ". This should
be done before booting into kernel, but not necessary for it to work.
3. Rebuild vmlinuz image:
"vbutil_kernel --get-vmlinuz kern_0 --vmlinuz-out vm.out"
4. Set up kexec with vmlinuz (this should complete with no errors):
"kexec -l vm.out (other kernel cmd line args)"
5. Boot into kernel:
"kexec -e"
Change-Id: Iaa1582a1aedf70b43cdb3a56cde1fb248f1793d4
Signed-off-by: Shelley Chen <shchen@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/232750
Reviewed-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
committed by
ChromeOS Commit Bot
parent
f242ad0f6f
commit
f1f53b3732
@@ -180,9 +180,9 @@ typedef struct VbFirmwarePreambleHeader {
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
#define KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2
|
#define KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2
|
||||||
#define KERNEL_PREAMBLE_HEADER_VERSION_MINOR 0
|
#define KERNEL_PREAMBLE_HEADER_VERSION_MINOR 1
|
||||||
|
|
||||||
/* Preamble block for kernel
|
/* Preamble block for kernel, version 2.0
|
||||||
*
|
*
|
||||||
* This should be followed by:
|
* This should be followed by:
|
||||||
* 1) The signature data for the kernel body, pointed to by
|
* 1) The signature data for the kernel body, pointed to by
|
||||||
@@ -190,7 +190,7 @@ typedef struct VbFirmwarePreambleHeader {
|
|||||||
* 2) The signature data for (VBFirmwarePreambleHeader + body signature
|
* 2) The signature data for (VBFirmwarePreambleHeader + body signature
|
||||||
* data), pointed to by preamble_signature.sig_offset.
|
* data), pointed to by preamble_signature.sig_offset.
|
||||||
*/
|
*/
|
||||||
typedef struct VbKernelPreambleHeader {
|
typedef struct VbKernelPreambleHeader2_0 {
|
||||||
/*
|
/*
|
||||||
* Size of this preamble, including keys, signatures, and padding, in
|
* Size of this preamble, including keys, signatures, and padding, in
|
||||||
* bytes
|
* bytes
|
||||||
@@ -213,9 +213,56 @@ typedef struct VbKernelPreambleHeader {
|
|||||||
uint64_t bootloader_size;
|
uint64_t bootloader_size;
|
||||||
/* Signature for the kernel body */
|
/* Signature for the kernel body */
|
||||||
VbSignature body_signature;
|
VbSignature body_signature;
|
||||||
|
} __attribute__((packed)) VbKernelPreambleHeader2_0;
|
||||||
|
|
||||||
|
#define EXPECTED_VBKERNELPREAMBLEHEADER2_0_SIZE 96
|
||||||
|
|
||||||
|
/* Preamble block for kernel, version 2.1
|
||||||
|
*
|
||||||
|
* This should be followed by:
|
||||||
|
* 1) The signature data for the kernel body, pointed to by
|
||||||
|
* body_signature.sig_offset.
|
||||||
|
* 2) The signature data for (VBFirmwarePreambleHeader + body signature
|
||||||
|
* data), pointed to by preamble_signature.sig_offset.
|
||||||
|
* 3) The 16-bit vmlinuz header, which is used for reconstruction of
|
||||||
|
* vmlinuz image.
|
||||||
|
*/
|
||||||
|
typedef struct VbKernelPreambleHeader {
|
||||||
|
/*
|
||||||
|
* Size of this preamble, including keys, signatures, vmlinuz header,
|
||||||
|
* and padding, in bytes
|
||||||
|
*/
|
||||||
|
uint64_t preamble_size;
|
||||||
|
/* Signature for this preamble (header + body signature) */
|
||||||
|
VbSignature preamble_signature;
|
||||||
|
/* Version of this header format */
|
||||||
|
uint32_t header_version_major;
|
||||||
|
/* Version of this header format */
|
||||||
|
uint32_t header_version_minor;
|
||||||
|
|
||||||
|
/* Kernel version */
|
||||||
|
uint64_t kernel_version;
|
||||||
|
/* Load address for kernel body */
|
||||||
|
uint64_t body_load_address;
|
||||||
|
/* Address of bootloader, after body is loaded at body_load_address */
|
||||||
|
uint64_t bootloader_address;
|
||||||
|
/* Size of bootloader in bytes */
|
||||||
|
uint64_t bootloader_size;
|
||||||
|
/* Signature for the kernel body */
|
||||||
|
VbSignature body_signature;
|
||||||
|
/*
|
||||||
|
* Fields added in header version 2.1. You must verify the header
|
||||||
|
* version before reading these fields!
|
||||||
|
*/
|
||||||
|
/* Address of 16-bit header for vmlinuz reassembly. Readers should
|
||||||
|
return 0 for header version < 2.1 */
|
||||||
|
uint64_t vmlinuz_header_address;
|
||||||
|
/* Size of 16-bit header for vmlinuz in bytes. Readers should return 0
|
||||||
|
for header version < 2.1 */
|
||||||
|
uint64_t vmlinuz_header_size;
|
||||||
} __attribute__((packed)) VbKernelPreambleHeader;
|
} __attribute__((packed)) VbKernelPreambleHeader;
|
||||||
|
|
||||||
#define EXPECTED_VBKERNELPREAMBLEHEADER_SIZE 96
|
#define EXPECTED_VBKERNELPREAMBLEHEADER2_1_SIZE 112
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,25 @@ int VerifyKernelPreamble(const VbKernelPreambleHeader *preamble,
|
|||||||
uint64_t size, const RSAPublicKey *key);
|
uint64_t size, const RSAPublicKey *key);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the 16-bit vmlinuz header address and size from the kernel preamble
|
||||||
|
* if there is one. These are only available in Kernel Preamble Header version
|
||||||
|
* >= 2.1. If given a header 2.0 or lower, will set address and size to 0 (this
|
||||||
|
* is not considered an error).
|
||||||
|
*
|
||||||
|
* Returns VBOOT_SUCCESS if successful.
|
||||||
|
*/
|
||||||
|
int VbGetKernelVmlinuzHeader(const VbKernelPreambleHeader *preamble,
|
||||||
|
uint64_t *vmlinuz_header_address,
|
||||||
|
uint64_t *vmlinuz_header_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that the Vmlinuz Header is contained inside of the kernel blob.
|
||||||
|
*
|
||||||
|
* Returns VBOOT_SUCCESS or VBOOT_PREAMBLE_INVALID on error
|
||||||
|
*/
|
||||||
|
int VerifyVmlinuzInsideKBlob(uint64_t kblob, uint64_t kblob_size,
|
||||||
|
uint64_t header, uint64_t header_size);
|
||||||
/**
|
/**
|
||||||
* Initialize a verified boot shared data structure.
|
* Initialize a verified boot shared data structure.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -435,10 +435,54 @@ int VerifyKernelPreamble(const VbKernelPreambleHeader *preamble,
|
|||||||
return VBOOT_PREAMBLE_INVALID;
|
return VBOOT_PREAMBLE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the preamble header version is at least 2.1, verify we have space
|
||||||
|
* for the added fields from 2.1.
|
||||||
|
*/
|
||||||
|
if (preamble->header_version_minor >= 1) {
|
||||||
|
if(size < EXPECTED_VBKERNELPREAMBLEHEADER2_1_SIZE) {
|
||||||
|
VBDEBUG(("Not enough data for preamble header 2.1.\n"));
|
||||||
|
return VBOOT_PREAMBLE_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Success */
|
/* Success */
|
||||||
return VBOOT_SUCCESS;
|
return VBOOT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VbGetKernelVmlinuzHeader(const VbKernelPreambleHeader *preamble,
|
||||||
|
uint64_t *vmlinuz_header_address,
|
||||||
|
uint64_t *vmlinuz_header_size)
|
||||||
|
{
|
||||||
|
*vmlinuz_header_address = 0;
|
||||||
|
*vmlinuz_header_size = 0;
|
||||||
|
if (preamble->header_version_minor > 0) {
|
||||||
|
/*
|
||||||
|
* Set header and size only if the preamble header version is >
|
||||||
|
* 2.1 as they don't exist in version 2.0 (Note that we don't
|
||||||
|
* need to check header_version_major; if that's not 2 then
|
||||||
|
* VerifyKernelPreamble() would have already failed.
|
||||||
|
*/
|
||||||
|
*vmlinuz_header_address = preamble->vmlinuz_header_address;
|
||||||
|
*vmlinuz_header_size = preamble->vmlinuz_header_size;
|
||||||
|
}
|
||||||
|
return VBOOT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VerifyVmlinuzInsideKBlob(uint64_t kblob, uint64_t kblob_size,
|
||||||
|
uint64_t header, uint64_t header_size)
|
||||||
|
{
|
||||||
|
uint64_t end = header-kblob;
|
||||||
|
if (end > kblob_size)
|
||||||
|
return VBOOT_PREAMBLE_INVALID;
|
||||||
|
if (UINT64_MAX - end < header_size)
|
||||||
|
return VBOOT_PREAMBLE_INVALID;
|
||||||
|
if (end + header_size > kblob_size)
|
||||||
|
return VBOOT_PREAMBLE_INVALID;
|
||||||
|
|
||||||
|
return VBOOT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t VbSharedDataReserve(VbSharedDataHeader *header, uint64_t size)
|
uint64_t VbSharedDataReserve(VbSharedDataHeader *header, uint64_t size)
|
||||||
{
|
{
|
||||||
uint64_t offs = header->data_used;
|
uint64_t offs = header->data_used;
|
||||||
|
|||||||
@@ -385,6 +385,8 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
|
|||||||
uint64_t kernel_size = 0;
|
uint64_t kernel_size = 0;
|
||||||
int good_sig = 0;
|
int good_sig = 0;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
uint64_t vmlinuz_header_size = 0;
|
||||||
|
uint64_t vmlinuz_header_address = 0;
|
||||||
|
|
||||||
/* Check the hash... */
|
/* Check the hash... */
|
||||||
if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
|
if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
|
||||||
@@ -435,6 +437,19 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
|
|||||||
printf(" Bootloader size: 0x%" PRIx64 "\n",
|
printf(" Bootloader size: 0x%" PRIx64 "\n",
|
||||||
preamble->bootloader_size);
|
preamble->bootloader_size);
|
||||||
|
|
||||||
|
if (VbGetKernelVmlinuzHeader(preamble,
|
||||||
|
&vmlinuz_header_address,
|
||||||
|
&vmlinuz_header_size)
|
||||||
|
!= VBOOT_SUCCESS) {
|
||||||
|
fprintf(stderr, "Unable to retrieve Vmlinuz Header!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (vmlinuz_header_size) {
|
||||||
|
printf(" Vmlinuz_header address: 0x%" PRIx64 "\n",
|
||||||
|
vmlinuz_header_address);
|
||||||
|
printf(" Vmlinuz header size: 0x%" PRIx64 "\n",
|
||||||
|
vmlinuz_header_size);
|
||||||
|
}
|
||||||
|
|
||||||
/* Verify kernel body */
|
/* Verify kernel body */
|
||||||
if (option.fv) {
|
if (option.fv) {
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ enum {
|
|||||||
OPT_MODE_PACK = 1000,
|
OPT_MODE_PACK = 1000,
|
||||||
OPT_MODE_REPACK,
|
OPT_MODE_REPACK,
|
||||||
OPT_MODE_VERIFY,
|
OPT_MODE_VERIFY,
|
||||||
|
OPT_MODE_GET_VMLINUZ,
|
||||||
OPT_ARCH,
|
OPT_ARCH,
|
||||||
OPT_OLDBLOB,
|
OPT_OLDBLOB,
|
||||||
OPT_KLOADADDR,
|
OPT_KLOADADDR,
|
||||||
@@ -57,12 +58,14 @@ enum {
|
|||||||
OPT_PAD,
|
OPT_PAD,
|
||||||
OPT_VERBOSE,
|
OPT_VERBOSE,
|
||||||
OPT_MINVERSION,
|
OPT_MINVERSION,
|
||||||
|
OPT_VMLINUZ_OUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option long_opts[] = {
|
static const struct option long_opts[] = {
|
||||||
{"pack", 1, 0, OPT_MODE_PACK},
|
{"pack", 1, 0, OPT_MODE_PACK},
|
||||||
{"repack", 1, 0, OPT_MODE_REPACK},
|
{"repack", 1, 0, OPT_MODE_REPACK},
|
||||||
{"verify", 1, 0, OPT_MODE_VERIFY},
|
{"verify", 1, 0, OPT_MODE_VERIFY},
|
||||||
|
{"get-vmlinuz", 1, 0, OPT_MODE_GET_VMLINUZ},
|
||||||
{"arch", 1, 0, OPT_ARCH},
|
{"arch", 1, 0, OPT_ARCH},
|
||||||
{"oldblob", 1, 0, OPT_OLDBLOB},
|
{"oldblob", 1, 0, OPT_OLDBLOB},
|
||||||
{"kloadaddr", 1, 0, OPT_KLOADADDR},
|
{"kloadaddr", 1, 0, OPT_KLOADADDR},
|
||||||
@@ -78,6 +81,7 @@ static const struct option long_opts[] = {
|
|||||||
{"pad", 1, 0, OPT_PAD},
|
{"pad", 1, 0, OPT_PAD},
|
||||||
{"verbose", 0, &opt_verbose, 1},
|
{"verbose", 0, &opt_verbose, 1},
|
||||||
{"debug", 0, &debugging_enabled, 1},
|
{"debug", 0, &debugging_enabled, 1},
|
||||||
|
{"vmlinuz-out", 1, 0, OPT_VMLINUZ_OUT},
|
||||||
{NULL, 0, 0, 0}
|
{NULL, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -129,14 +133,18 @@ static const char usage[] =
|
|||||||
" in .keyblock format\n"
|
" in .keyblock format\n"
|
||||||
" --pad <number> Verification padding size in bytes\n"
|
" --pad <number> Verification padding size in bytes\n"
|
||||||
" --minversion <number> Minimum combined kernel key version\n"
|
" --minversion <number> Minimum combined kernel key version\n"
|
||||||
" and kernel version\n"
|
"\nOR\n\n"
|
||||||
|
"Usage: " MYNAME " %s --get-vmlinuz <file> [PARAMETERS]\n"
|
||||||
|
"\n"
|
||||||
|
" Required parameters:\n"
|
||||||
|
" --vmlinuz-out <file> vmlinuz image output file\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
|
|
||||||
/* Print help and return error */
|
/* Print help and return error */
|
||||||
static void print_help(const char *progname)
|
static void print_help(const char *progname)
|
||||||
{
|
{
|
||||||
printf(usage, progname, progname, progname);
|
printf(usage, progname, progname, progname, progname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -209,13 +217,14 @@ static int do_vbutil_kernel(int argc, char *argv[])
|
|||||||
char *vmlinuz_file = NULL;
|
char *vmlinuz_file = NULL;
|
||||||
char *bootloader_file = NULL;
|
char *bootloader_file = NULL;
|
||||||
char *config_file = NULL;
|
char *config_file = NULL;
|
||||||
|
char *vmlinuz_out_file = NULL;
|
||||||
enum arch_t arch = ARCH_X86;
|
enum arch_t arch = ARCH_X86;
|
||||||
uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
|
uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
|
||||||
int mode = 0;
|
int mode = 0;
|
||||||
int parse_error = 0;
|
int parse_error = 0;
|
||||||
uint64_t min_version = 0;
|
uint64_t min_version = 0;
|
||||||
char *e;
|
char *e;
|
||||||
int i;
|
int i = 0;
|
||||||
int rv;
|
int rv;
|
||||||
VbKeyBlockHeader *keyblock = NULL;
|
VbKeyBlockHeader *keyblock = NULL;
|
||||||
VbKeyBlockHeader *t_keyblock = NULL;
|
VbKeyBlockHeader *t_keyblock = NULL;
|
||||||
@@ -229,11 +238,14 @@ static int do_vbutil_kernel(int argc, char *argv[])
|
|||||||
uint64_t t_config_size;
|
uint64_t t_config_size;
|
||||||
uint8_t *t_bootloader_data;
|
uint8_t *t_bootloader_data;
|
||||||
uint64_t t_bootloader_size;
|
uint64_t t_bootloader_size;
|
||||||
|
uint64_t vmlinuz_header_size = 0;
|
||||||
|
uint64_t vmlinuz_header_address = 0;
|
||||||
VbKernelPreambleHeader *preamble = NULL;
|
VbKernelPreambleHeader *preamble = NULL;
|
||||||
uint8_t *kblob_data = NULL;
|
uint8_t *kblob_data = NULL;
|
||||||
uint64_t kblob_size = 0;
|
uint64_t kblob_size = 0;
|
||||||
uint8_t *vblock_data = NULL;
|
uint8_t *vblock_data = NULL;
|
||||||
uint64_t vblock_size = 0;
|
uint64_t vblock_size = 0;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
|
while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
|
||||||
!parse_error) {
|
!parse_error) {
|
||||||
@@ -251,6 +263,7 @@ static int do_vbutil_kernel(int argc, char *argv[])
|
|||||||
case OPT_MODE_PACK:
|
case OPT_MODE_PACK:
|
||||||
case OPT_MODE_REPACK:
|
case OPT_MODE_REPACK:
|
||||||
case OPT_MODE_VERIFY:
|
case OPT_MODE_VERIFY:
|
||||||
|
case OPT_MODE_GET_VMLINUZ:
|
||||||
if (mode && (mode != i)) {
|
if (mode && (mode != i)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Only one mode can be specified\n");
|
"Only one mode can be specified\n");
|
||||||
@@ -343,6 +356,8 @@ static int do_vbutil_kernel(int argc, char *argv[])
|
|||||||
parse_error = 1;
|
parse_error = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case OPT_VMLINUZ_OUT:
|
||||||
|
vmlinuz_out_file = optarg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,10 +534,79 @@ static int do_vbutil_kernel(int argc, char *argv[])
|
|||||||
signpub_key, keyblock_file, min_version);
|
signpub_key, keyblock_file, min_version);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
|
case OPT_MODE_GET_VMLINUZ:
|
||||||
|
|
||||||
|
if (!vmlinuz_out_file) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"USE: vbutil_kernel --get-vmlinuz <file> "
|
||||||
|
"--vmlinuz-out <file>\n");
|
||||||
|
print_help(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size);
|
||||||
|
|
||||||
|
kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
|
||||||
|
&keyblock, &preamble, &kblob_size);
|
||||||
|
|
||||||
|
if (!kblob_data)
|
||||||
|
Fatal("Unable to unpack kernel partition\n");
|
||||||
|
|
||||||
|
f = fopen(vmlinuz_out_file, "wb");
|
||||||
|
if (!f) {
|
||||||
|
VbExError("Can't open output file %s\n",
|
||||||
|
vmlinuz_out_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now stick 16-bit header followed by kernel block into
|
||||||
|
output */
|
||||||
|
if (VbGetKernelVmlinuzHeader(preamble,
|
||||||
|
&vmlinuz_header_address,
|
||||||
|
&vmlinuz_header_size)
|
||||||
|
!= VBOOT_SUCCESS) {
|
||||||
|
Fatal("Unable to retrieve Vmlinuz Header!");
|
||||||
|
}
|
||||||
|
if (vmlinuz_header_size) {
|
||||||
|
// verify that the 16-bit header is included in the
|
||||||
|
// kblob (to make sure that it's included in the
|
||||||
|
// signature)
|
||||||
|
if (VerifyVmlinuzInsideKBlob(preamble->body_load_address,
|
||||||
|
kblob_size,
|
||||||
|
vmlinuz_header_address,
|
||||||
|
vmlinuz_header_size)) {
|
||||||
|
VbExError("Vmlinuz header not signed!\n");
|
||||||
|
fclose(f);
|
||||||
|
unlink(vmlinuz_out_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = (1 != fwrite((void*)(uintptr_t)
|
||||||
|
vmlinuz_header_address,
|
||||||
|
vmlinuz_header_size,
|
||||||
|
1,
|
||||||
|
f));
|
||||||
|
}
|
||||||
|
i = i || (1 != fwrite(kblob_data,
|
||||||
|
kblob_size,
|
||||||
|
1,
|
||||||
|
f));
|
||||||
|
if (i) {
|
||||||
|
VbExError("Can't write output file %s\n",
|
||||||
|
vmlinuz_out_file);
|
||||||
|
fclose(f);
|
||||||
|
unlink(vmlinuz_out_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"You must specify a mode: --pack, --repack or --verify\n");
|
"You must specify a mode: "
|
||||||
|
"--pack, --repack, --verify, or --get-vmlinuz\n");
|
||||||
print_help(argv[0]);
|
print_help(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,8 @@
|
|||||||
/* Here are globals containing all the bits & pieces I'm working on.
|
/* Here are globals containing all the bits & pieces I'm working on.
|
||||||
*
|
*
|
||||||
* kernel vblock = keyblock + kernel preamble + padding to 64K (or whatever)
|
* kernel vblock = keyblock + kernel preamble + padding to 64K (or whatever)
|
||||||
* kernel blob = 32-bit kernel + config file + params + bootloader stub
|
* kernel blob = 32-bit kernel + config file + params + bootloader stub +
|
||||||
|
* vmlinuz_header
|
||||||
* kernel partition = kernel vblock + kernel blob
|
* kernel partition = kernel vblock + kernel blob
|
||||||
*
|
*
|
||||||
* The VbKernelPreambleHeader.preamble_size includes the padding.
|
* The VbKernelPreambleHeader.preamble_size includes the padding.
|
||||||
@@ -41,8 +42,11 @@ static uint8_t *g_param_data;
|
|||||||
static uint64_t g_param_size;
|
static uint64_t g_param_size;
|
||||||
static uint8_t *g_bootloader_data;
|
static uint8_t *g_bootloader_data;
|
||||||
static uint64_t g_bootloader_size;
|
static uint64_t g_bootloader_size;
|
||||||
|
static uint8_t *g_vmlinuz_header_data;
|
||||||
|
static uint64_t g_vmlinuz_header_size;
|
||||||
|
|
||||||
static uint64_t g_ondisk_bootloader_addr;
|
static uint64_t g_ondisk_bootloader_addr;
|
||||||
|
static uint64_t g_ondisk_vmlinuz_header_addr;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -163,6 +167,9 @@ static int PickApartVmlinuz(uint8_t *kernel_buf, uint64_t kernel_size,
|
|||||||
}
|
}
|
||||||
kernel32_size = kernel_size - kernel32_start;
|
kernel32_size = kernel_size - kernel32_start;
|
||||||
|
|
||||||
|
Debug(" kernel16_start=0x%" PRIx64 "\n", 0);
|
||||||
|
Debug(" kernel16_size=0x%" PRIx64 "\n", kernel32_start);
|
||||||
|
|
||||||
/* Copy the original zeropage data from kernel_buf into
|
/* Copy the original zeropage data from kernel_buf into
|
||||||
* g_param_data, then tweak a few fields for our purposes */
|
* g_param_data, then tweak a few fields for our purposes */
|
||||||
params = (struct linux_kernel_params *)(g_param_data);
|
params = (struct linux_kernel_params *)(g_param_data);
|
||||||
@@ -206,14 +213,34 @@ static int PickApartVmlinuz(uint8_t *kernel_buf, uint64_t kernel_size,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Split a kernel blob into separate g_kernel, g_param, g_config, and
|
/* Split a kernel blob into separate g_kernel, g_param, g_config,
|
||||||
* g_bootloader parts. */
|
* g_bootloader, and g_vmlinuz_header parts. */
|
||||||
static void UnpackKernelBlob(uint8_t *kernel_blob_data)
|
static void UnpackKernelBlob(uint8_t *kernel_blob_data)
|
||||||
{
|
{
|
||||||
uint64_t now;
|
uint64_t now;
|
||||||
|
uint64_t vmlinuz_header_size = 0;
|
||||||
|
uint64_t vmlinuz_header_address = 0;
|
||||||
|
|
||||||
/* We have to work backwards from the end, because the preamble
|
/* We have to work backwards from the end, because the preamble
|
||||||
only describes the bootloader stub. */
|
only describes the bootloader and vmlinuz stubs. */
|
||||||
|
|
||||||
|
/* Vmlinuz Header is at the end */
|
||||||
|
if (VbGetKernelVmlinuzHeader(g_preamble,
|
||||||
|
&vmlinuz_header_address,
|
||||||
|
&vmlinuz_header_size)
|
||||||
|
!= VBOOT_SUCCESS) {
|
||||||
|
fprintf(stderr, "Unable to retrieve Vmlinuz Header!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (vmlinuz_header_size) {
|
||||||
|
now = vmlinuz_header_address - g_preamble->body_load_address;
|
||||||
|
g_vmlinuz_header_size = vmlinuz_header_size;
|
||||||
|
g_vmlinuz_header_data = kernel_blob_data + now;
|
||||||
|
|
||||||
|
Debug("vmlinuz_header_size = 0x%" PRIx64 "\n",
|
||||||
|
g_vmlinuz_header_size);
|
||||||
|
Debug("vmlinuz_header_ofs = 0x%" PRIx64 "\n", now);
|
||||||
|
}
|
||||||
|
|
||||||
/* Where does the bootloader stub begin? */
|
/* Where does the bootloader stub begin? */
|
||||||
now = g_preamble->bootloader_address - g_preamble->body_load_address;
|
now = g_preamble->bootloader_address - g_preamble->body_load_address;
|
||||||
@@ -273,6 +300,8 @@ uint8_t *UnpackKPart(uint8_t *kpart_data, uint64_t kpart_size,
|
|||||||
{
|
{
|
||||||
VbKeyBlockHeader *keyblock;
|
VbKeyBlockHeader *keyblock;
|
||||||
VbKernelPreambleHeader *preamble;
|
VbKernelPreambleHeader *preamble;
|
||||||
|
uint64_t vmlinuz_header_size = 0;
|
||||||
|
uint64_t vmlinuz_header_address = 0;
|
||||||
uint64_t now = 0;
|
uint64_t now = 0;
|
||||||
|
|
||||||
/* Sanity-check the keyblock */
|
/* Sanity-check the keyblock */
|
||||||
@@ -319,6 +348,21 @@ uint8_t *UnpackKPart(uint8_t *kpart_data, uint64_t kpart_size,
|
|||||||
g_preamble = preamble;
|
g_preamble = preamble;
|
||||||
g_ondisk_bootloader_addr = g_preamble->bootloader_address;
|
g_ondisk_bootloader_addr = g_preamble->bootloader_address;
|
||||||
|
|
||||||
|
if (VbGetKernelVmlinuzHeader(preamble,
|
||||||
|
&vmlinuz_header_address,
|
||||||
|
&vmlinuz_header_size)
|
||||||
|
!= VBOOT_SUCCESS) {
|
||||||
|
fprintf(stderr, "Unable to retrieve Vmlinuz Header!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (vmlinuz_header_size) {
|
||||||
|
Debug(" vmlinuz_header_address = 0x%" PRIx64 "\n",
|
||||||
|
vmlinuz_header_address);
|
||||||
|
Debug(" vmlinuz_header_size = 0x%" PRIx64 "\n",
|
||||||
|
vmlinuz_header_size);
|
||||||
|
g_ondisk_vmlinuz_header_addr = vmlinuz_header_address;
|
||||||
|
}
|
||||||
|
|
||||||
Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
|
Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
|
||||||
g_kernel_blob_data = kpart_data + now;
|
g_kernel_blob_data = kpart_data + now;
|
||||||
g_kernel_blob_size = preamble->body_signature.data_size;
|
g_kernel_blob_size = preamble->body_signature.data_size;
|
||||||
@@ -367,7 +411,10 @@ uint8_t *SignKernelBlob(uint8_t *kernel_blob, uint64_t kernel_size,
|
|||||||
kernel_body_load_address,
|
kernel_body_load_address,
|
||||||
g_ondisk_bootloader_addr,
|
g_ondisk_bootloader_addr,
|
||||||
g_bootloader_size,
|
g_bootloader_size,
|
||||||
body_sig, min_size,
|
body_sig,
|
||||||
|
g_ondisk_vmlinuz_header_addr,
|
||||||
|
g_vmlinuz_header_size,
|
||||||
|
min_size,
|
||||||
signpriv_key);
|
signpriv_key);
|
||||||
if (!preamble) {
|
if (!preamble) {
|
||||||
fprintf(stderr, "Error creating preamble.\n");
|
fprintf(stderr, "Error creating preamble.\n");
|
||||||
@@ -440,6 +487,8 @@ int VerifyKernelBlob(uint8_t *kernel_blob,
|
|||||||
VbPublicKey *data_key;
|
VbPublicKey *data_key;
|
||||||
RSAPublicKey *rsa;
|
RSAPublicKey *rsa;
|
||||||
int rv = -1;
|
int rv = -1;
|
||||||
|
uint64_t vmlinuz_header_size = 0;
|
||||||
|
uint64_t vmlinuz_header_address = 0;
|
||||||
|
|
||||||
if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
|
if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
|
||||||
signpub_key, (0 == signpub_key))) {
|
signpub_key, (0 == signpub_key))) {
|
||||||
@@ -526,6 +575,20 @@ int VerifyKernelBlob(uint8_t *kernel_blob,
|
|||||||
printf(" Bootloader size: 0x%" PRIx64 "\n",
|
printf(" Bootloader size: 0x%" PRIx64 "\n",
|
||||||
g_preamble->bootloader_size);
|
g_preamble->bootloader_size);
|
||||||
|
|
||||||
|
if (VbGetKernelVmlinuzHeader(g_preamble,
|
||||||
|
&vmlinuz_header_address,
|
||||||
|
&vmlinuz_header_size)
|
||||||
|
!= VBOOT_SUCCESS) {
|
||||||
|
fprintf(stderr, "Unable to retrieve Vmlinuz Header!");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (vmlinuz_header_size) {
|
||||||
|
printf(" Vmlinuz header address: 0x%" PRIx64 "\n",
|
||||||
|
vmlinuz_header_address);
|
||||||
|
printf(" Vmlinuz header size: 0x%" PRIx64 "\n",
|
||||||
|
vmlinuz_header_size);
|
||||||
|
}
|
||||||
|
|
||||||
if (g_preamble->kernel_version < (min_version & 0xFFFF)) {
|
if (g_preamble->kernel_version < (min_version & 0xFFFF)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Kernel version %" PRIu64 " is lower than minimum %"
|
"Kernel version %" PRIu64 " is lower than minimum %"
|
||||||
@@ -567,8 +630,13 @@ uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size,
|
|||||||
g_config_size = CROS_CONFIG_SIZE;
|
g_config_size = CROS_CONFIG_SIZE;
|
||||||
g_param_size = CROS_PARAMS_SIZE;
|
g_param_size = CROS_PARAMS_SIZE;
|
||||||
g_bootloader_size = roundup(bootloader_size, CROS_ALIGN);
|
g_bootloader_size = roundup(bootloader_size, CROS_ALIGN);
|
||||||
g_kernel_blob_size = roundup(g_kernel_size, CROS_ALIGN) +
|
g_vmlinuz_header_size = vmlinuz_size-g_kernel_size;
|
||||||
g_config_size + g_param_size + g_bootloader_size;
|
g_kernel_blob_size =
|
||||||
|
roundup(g_kernel_size, CROS_ALIGN) +
|
||||||
|
g_config_size +
|
||||||
|
g_param_size +
|
||||||
|
g_bootloader_size +
|
||||||
|
g_vmlinuz_header_size;
|
||||||
Debug("g_kernel_blob_size 0x%" PRIx64 "\n", g_kernel_blob_size);
|
Debug("g_kernel_blob_size 0x%" PRIx64 "\n", g_kernel_blob_size);
|
||||||
|
|
||||||
/* Allocate space for the blob. */
|
/* Allocate space for the blob. */
|
||||||
@@ -597,6 +665,18 @@ uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size,
|
|||||||
g_ondisk_bootloader_addr = kernel_body_load_address + now;
|
g_ondisk_bootloader_addr = kernel_body_load_address + now;
|
||||||
Debug("g_ondisk_bootloader_addr 0x%" PRIx64 "\n",
|
Debug("g_ondisk_bootloader_addr 0x%" PRIx64 "\n",
|
||||||
g_ondisk_bootloader_addr);
|
g_ondisk_bootloader_addr);
|
||||||
|
now += g_bootloader_size;
|
||||||
|
|
||||||
|
if (g_vmlinuz_header_size) {
|
||||||
|
g_vmlinuz_header_data = g_kernel_blob_data + now;
|
||||||
|
Debug("g_vmlinuz_header_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n",
|
||||||
|
g_vmlinuz_header_size, now);
|
||||||
|
g_ondisk_vmlinuz_header_addr = kernel_body_load_address + now;
|
||||||
|
Debug("g_ondisk_vmlinuz_header_addr 0x%" PRIx64 "\n",
|
||||||
|
g_ondisk_vmlinuz_header_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now);
|
||||||
|
|
||||||
/* Copy the kernel and params bits into the correct places */
|
/* Copy the kernel and params bits into the correct places */
|
||||||
if (0 != PickApartVmlinuz(vmlinuz_buf, vmlinuz_size,
|
if (0 != PickApartVmlinuz(vmlinuz_buf, vmlinuz_size,
|
||||||
@@ -611,6 +691,11 @@ uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size,
|
|||||||
/* Copy the other bits too */
|
/* Copy the other bits too */
|
||||||
Memcpy(g_config_data, config_data, config_size);
|
Memcpy(g_config_data, config_data, config_size);
|
||||||
Memcpy(g_bootloader_data, bootloader_data, bootloader_size);
|
Memcpy(g_bootloader_data, bootloader_data, bootloader_size);
|
||||||
|
if (g_vmlinuz_header_size) {
|
||||||
|
Memcpy(g_vmlinuz_header_data,
|
||||||
|
vmlinuz_buf,
|
||||||
|
g_vmlinuz_header_size);
|
||||||
|
}
|
||||||
|
|
||||||
if (blob_size_ptr)
|
if (blob_size_ptr)
|
||||||
*blob_size_ptr = g_kernel_blob_size;
|
*blob_size_ptr = g_kernel_blob_size;
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ VbKernelPreambleHeader *CreateKernelPreamble(
|
|||||||
uint64_t bootloader_address,
|
uint64_t bootloader_address,
|
||||||
uint64_t bootloader_size,
|
uint64_t bootloader_size,
|
||||||
const VbSignature *body_signature,
|
const VbSignature *body_signature,
|
||||||
|
uint64_t vmlinuz_header_address,
|
||||||
|
uint64_t vmlinuz_header_size,
|
||||||
uint64_t desired_size,
|
uint64_t desired_size,
|
||||||
const VbPrivateKey *signing_key)
|
const VbPrivateKey *signing_key)
|
||||||
{
|
{
|
||||||
@@ -107,6 +109,8 @@ VbKernelPreambleHeader *CreateKernelPreamble(
|
|||||||
h->body_load_address = body_load_address;
|
h->body_load_address = body_load_address;
|
||||||
h->bootloader_address = bootloader_address;
|
h->bootloader_address = bootloader_address;
|
||||||
h->bootloader_size = bootloader_size;
|
h->bootloader_size = bootloader_size;
|
||||||
|
h->vmlinuz_header_address = vmlinuz_header_address;
|
||||||
|
h->vmlinuz_header_size = vmlinuz_header_size;
|
||||||
|
|
||||||
/* Copy body signature */
|
/* Copy body signature */
|
||||||
SignatureInit(&h->body_signature, body_sig_dest,
|
SignatureInit(&h->body_signature, body_sig_dest,
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ VbKernelPreambleHeader *CreateKernelPreamble(
|
|||||||
uint64_t bootloader_address,
|
uint64_t bootloader_address,
|
||||||
uint64_t bootloader_size,
|
uint64_t bootloader_size,
|
||||||
const VbSignature *body_signature,
|
const VbSignature *body_signature,
|
||||||
|
uint64_t vmlinuz_header_address,
|
||||||
|
uint64_t vmlinuz_header_size,
|
||||||
uint64_t desired_size,
|
uint64_t desired_size,
|
||||||
const VbPrivateKey *signing_key);
|
const VbPrivateKey *signing_key);
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ int main(void)
|
|||||||
|
|
||||||
/* host_common.h */
|
/* host_common.h */
|
||||||
CreateFirmwarePreamble(0, 0, 0, 0, 0);
|
CreateFirmwarePreamble(0, 0, 0, 0, 0);
|
||||||
CreateKernelPreamble(0, 0, 0, 0, 0, 0, 0);
|
CreateKernelPreamble(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
/* file_keys.h */
|
/* file_keys.h */
|
||||||
BufferFromFile(0, 0);
|
BufferFromFile(0, 0);
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ static void VerifyKernelPreambleTest(const VbPublicKey *public_key,
|
|||||||
|
|
||||||
rsa = PublicKeyToRSA(public_key);
|
rsa = PublicKeyToRSA(public_key);
|
||||||
hdr = CreateKernelPreamble(0x1234, 0x100000, 0x300000, 0x4000, body_sig,
|
hdr = CreateKernelPreamble(0x1234, 0x100000, 0x300000, 0x4000, body_sig,
|
||||||
0, private_key);
|
0, 0, 0, private_key);
|
||||||
TEST_NEQ(hdr && rsa, 0, "VerifyKernelPreamble() prerequisites");
|
TEST_NEQ(hdr && rsa, 0, "VerifyKernelPreamble() prerequisites");
|
||||||
if (!hdr)
|
if (!hdr)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ static void StructPackingTest(void)
|
|||||||
TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE,
|
TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE,
|
||||||
sizeof(VbFirmwarePreambleHeader),
|
sizeof(VbFirmwarePreambleHeader),
|
||||||
"sizeof(VbFirmwarePreambleHeader)");
|
"sizeof(VbFirmwarePreambleHeader)");
|
||||||
TEST_EQ(EXPECTED_VBKERNELPREAMBLEHEADER_SIZE,
|
TEST_EQ(EXPECTED_VBKERNELPREAMBLEHEADER2_1_SIZE,
|
||||||
sizeof(VbKernelPreambleHeader),
|
sizeof(VbKernelPreambleHeader),
|
||||||
"sizeof(VbKernelPreambleHeader)");
|
"sizeof(VbKernelPreambleHeader)");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user