kernel flags: Add flags field to kernel preamble.

1. Increase kernel preamble revision from 2.1 to 2.2.
2. Add flags field to kernel preamble.
3. Update futility to accept flags parameter for vbutil_kernel and
cmd_sign for kernel.
4. Pass in an extra flags field to SignKernelBlob and
CreateKernelPreamble.

BUG=chrome-os-partner:35861
BRANCH=None
TEST=1) "make runalltests" completes successfully. 2) vboot_reference
compiles successfully for ryu. 3) Verified flags field in header using
futility show.

Change-Id: If9f06f98778a7339194c77090cbef4807d5e34e2
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://chromium-review.googlesource.com/245950
Tested-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Commit-Queue: Furquan Shaikh <furquan@chromium.org>
This commit is contained in:
Furquan Shaikh
2015-02-03 15:34:29 -08:00
committed by ChromeOS Commit Bot
parent 623d6c4744
commit 80e779d50b
13 changed files with 89 additions and 13 deletions

View File

@@ -180,7 +180,7 @@ typedef struct VbFirmwarePreambleHeader {
/****************************************************************************/ /****************************************************************************/
#define KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2 #define KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2
#define KERNEL_PREAMBLE_HEADER_VERSION_MINOR 1 #define KERNEL_PREAMBLE_HEADER_VERSION_MINOR 2
/* Preamble block for kernel, version 2.0 /* Preamble block for kernel, version 2.0
* *
@@ -260,9 +260,17 @@ typedef struct VbKernelPreambleHeader {
/* Size of 16-bit header for vmlinuz in bytes. Readers should return 0 /* Size of 16-bit header for vmlinuz in bytes. Readers should return 0
for header version < 2.1 */ for header version < 2.1 */
uint64_t vmlinuz_header_size; uint64_t vmlinuz_header_size;
/*
* Flags passed in by the signer. Readers should return 0 for header
* version < 2.2. Flags field is currently defined as:
* [31:2] - Reserved (for future use)
* [1:0] - Kernel image type (0b00 - CrOS, 0b01 - bootimg)
*/
uint32_t flags;
} __attribute__((packed)) VbKernelPreambleHeader; } __attribute__((packed)) VbKernelPreambleHeader;
#define EXPECTED_VBKERNELPREAMBLEHEADER2_1_SIZE 112 #define EXPECTED_VBKERNELPREAMBLEHEADER2_1_SIZE 112
#define EXPECTED_VBKERNELPREAMBLEHEADER2_2_SIZE 116
/****************************************************************************/ /****************************************************************************/

View File

@@ -41,6 +41,8 @@ enum {
VBOOT_PREAMBLE_SIGNATURE, VBOOT_PREAMBLE_SIGNATURE,
/* Shared data is invalid. */ /* Shared data is invalid. */
VBOOT_SHARED_DATA_INVALID, VBOOT_SHARED_DATA_INVALID,
/* Kernel Preamble does not contain flags */
VBOOT_KERNEL_PREAMBLE_NO_FLAGS,
VBOOT_ERROR_MAX, VBOOT_ERROR_MAX,
}; };
extern const char *kVbootErrors[VBOOT_ERROR_MAX]; extern const char *kVbootErrors[VBOOT_ERROR_MAX];
@@ -160,6 +162,15 @@ int VbGetKernelVmlinuzHeader(const VbKernelPreambleHeader *preamble,
uint64_t *vmlinuz_header_address, uint64_t *vmlinuz_header_address,
uint64_t *vmlinuz_header_size); uint64_t *vmlinuz_header_size);
/**
* Checks if the kernel preamble has flags field. This is available only if the
* Kernel Preamble Header version >=2.2. If give a header of 2.1 or lower, it
* will return VBOOT_KERNEL_PREAMBLE_NO_FLAGS.
*
* Returns VBOOT_SUCCESS if version is >=2.2.
*/
int VbKernelHasFlags(const VbKernelPreambleHeader *preamble);
/** /**
* Verify that the Vmlinuz Header is contained inside of the kernel blob. * Verify that the Vmlinuz Header is contained inside of the kernel blob.
* *

View File

@@ -437,13 +437,20 @@ int VerifyKernelPreamble(const VbKernelPreambleHeader *preamble,
/* /*
* If the preamble header version is at least 2.1, verify we have space * If the preamble header version is at least 2.1, verify we have space
* for the added fields from 2.1. * for the added fields from >2.1.
*/ */
if (preamble->header_version_minor >= 1) { if (preamble->header_version_minor >= 1) {
if(size < EXPECTED_VBKERNELPREAMBLEHEADER2_1_SIZE) { if((preamble->header_version_minor == 1) &&
(size < EXPECTED_VBKERNELPREAMBLEHEADER2_1_SIZE)) {
VBDEBUG(("Not enough data for preamble header 2.1.\n")); VBDEBUG(("Not enough data for preamble header 2.1.\n"));
return VBOOT_PREAMBLE_INVALID; return VBOOT_PREAMBLE_INVALID;
} }
if((preamble->header_version_minor == 2) &&
(size < EXPECTED_VBKERNELPREAMBLEHEADER2_2_SIZE)) {
VBDEBUG(("Not enough data for preamble header 2.2.\n"));
return VBOOT_PREAMBLE_INVALID;
}
} }
/* Success */ /* Success */
@@ -469,6 +476,14 @@ int VbGetKernelVmlinuzHeader(const VbKernelPreambleHeader *preamble,
return VBOOT_SUCCESS; return VBOOT_SUCCESS;
} }
int VbKernelHasFlags(const VbKernelPreambleHeader *preamble)
{
if (preamble->header_version_minor > 1)
return VBOOT_SUCCESS;
return VBOOT_KERNEL_PREAMBLE_NO_FLAGS;
}
int VerifyVmlinuzInsideKBlob(uint64_t kblob, uint64_t kblob_size, int VerifyVmlinuzInsideKBlob(uint64_t kblob, uint64_t kblob_size,
uint64_t header, uint64_t header_size) uint64_t header, uint64_t header_size)
{ {

View File

@@ -419,6 +419,7 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
int retval = 0; int retval = 0;
uint64_t vmlinuz_header_size = 0; uint64_t vmlinuz_header_size = 0;
uint64_t vmlinuz_header_address = 0; uint64_t vmlinuz_header_address = 0;
uint32_t flags = 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)) {
@@ -483,6 +484,10 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
vmlinuz_header_size); vmlinuz_header_size);
} }
if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
flags = preamble->flags;
printf(" Flags: 0x%" PRIx32 "\n", flags);
/* Verify kernel body */ /* Verify kernel body */
if (option.fv) { if (option.fv) {
/* It's in a separate file, which we've already read in */ /* It's in a separate file, which we've already read in */

View File

@@ -219,7 +219,7 @@ int futil_cb_create_kernel_part(struct futil_traverse_state_s *state)
vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding, vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
option.version, option.kloadaddr, option.version, option.kloadaddr,
option.keyblock, option.signprivate, option.keyblock, option.signprivate,
&vblock_size); option.flags, &vblock_size);
if (!vblock_data) { if (!vblock_data) {
fprintf(stderr, "Unable to sign kernel blob\n"); fprintf(stderr, "Unable to sign kernel blob\n");
free(kblob_data); free(kblob_data);
@@ -288,6 +288,12 @@ int futil_cb_resign_kernel_part(struct futil_traverse_state_s *state)
if (!option.version_specified) if (!option.version_specified)
option.version = preamble->kernel_version; option.version = preamble->kernel_version;
/* Preserve the flags if not specified */
if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) {
if (option.flags_specified == 0)
option.flags = preamble->flags;
}
/* Replace the keyblock if asked */ /* Replace the keyblock if asked */
if (option.keyblock) if (option.keyblock)
keyblock = option.keyblock; keyblock = option.keyblock;
@@ -296,7 +302,7 @@ int futil_cb_resign_kernel_part(struct futil_traverse_state_s *state)
vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding, vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
option.version, option.kloadaddr, option.version, option.kloadaddr,
keyblock, option.signprivate, keyblock, option.signprivate,
&vblock_size); option.flags, &vblock_size);
if (!vblock_data) { if (!vblock_data) {
fprintf(stderr, "Unable to sign kernel blob\n"); fprintf(stderr, "Unable to sign kernel blob\n");
return 1; return 1;
@@ -612,7 +618,8 @@ static const char usage_new_kpart[] = "\n"
" --pad NUM The vblock padding size in bytes\n" " --pad NUM The vblock padding size in bytes\n"
" (default 0x%x)\n" " (default 0x%x)\n"
" --vblockonly Emit just the vblock (requires a\n" " --vblockonly Emit just the vblock (requires a\n"
" distinct outfile)\n"; " distinct outfile)\n"
" -f|--flags NUM The preamble flags value\n";
static const char usage_old_kpart[] = "\n" static const char usage_old_kpart[] = "\n"
"-----------------------------------------------------------------\n" "-----------------------------------------------------------------\n"
@@ -634,6 +641,7 @@ static const char usage_old_kpart[] = "\n"
" [--outfile] OUTFILE Output kernel partition or vblock\n" " [--outfile] OUTFILE Output kernel partition or vblock\n"
" --vblockonly Emit just the vblock (requires a\n" " --vblockonly Emit just the vblock (requires a\n"
" distinct OUTFILE)\n" " distinct OUTFILE)\n"
" -f|--flags NUM The preamble flags value\n"
"\n"; "\n";
static void print_help(const char *prog) static void print_help(const char *prog)

View File

@@ -63,6 +63,7 @@ enum {
OPT_VERBOSE, OPT_VERBOSE,
OPT_MINVERSION, OPT_MINVERSION,
OPT_VMLINUZ_OUT, OPT_VMLINUZ_OUT,
OPT_FLAGS,
}; };
static const struct option long_opts[] = { static const struct option long_opts[] = {
@@ -86,6 +87,7 @@ static const struct option long_opts[] = {
{"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}, {"vmlinuz-out", 1, 0, OPT_VMLINUZ_OUT},
{"flags", 1, 0, OPT_FLAGS},
{NULL, 0, 0, 0} {NULL, 0, 0, 0}
}; };
@@ -109,6 +111,7 @@ static const char usage[] =
" --kloadaddr <address> Assign kernel body load address\n" " --kloadaddr <address> Assign kernel body load address\n"
" --pad <number> Verification padding size in bytes\n" " --pad <number> Verification padding size in bytes\n"
" --vblockonly Emit just the verification blob\n" " --vblockonly Emit just the verification blob\n"
" --flags NUM Flags to be passed in the header\n"
"\nOR\n\n" "\nOR\n\n"
"Usage: " MYNAME " %s --repack <file> [PARAMETERS]\n" "Usage: " MYNAME " %s --repack <file> [PARAMETERS]\n"
"\n" "\n"
@@ -253,6 +256,7 @@ static int do_vbutil_kernel(int argc, char *argv[])
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;
uint32_t flags = 0;
FILE *f; FILE *f;
while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
@@ -328,6 +332,14 @@ static int do_vbutil_kernel(int argc, char *argv[])
vmlinuz_file = optarg; vmlinuz_file = optarg;
break; break;
case OPT_FLAGS:
flags = (uint32_t)strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --flags\n");
parse_error = 1;
}
break;
case OPT_BOOTLOADER: case OPT_BOOTLOADER:
bootloader_file = optarg; bootloader_file = optarg;
break; break;
@@ -435,7 +447,7 @@ static int do_vbutil_kernel(int argc, char *argv[])
vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad, vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
version, kernel_body_load_address, version, kernel_body_load_address,
t_keyblock, signpriv_key, t_keyblock, signpriv_key, flags,
&vblock_size); &vblock_size);
if (!vblock_data) if (!vblock_data)
Fatal("Unable to sign kernel blob\n"); Fatal("Unable to sign kernel blob\n");
@@ -498,6 +510,9 @@ static int do_vbutil_kernel(int argc, char *argv[])
if (!version_str) if (!version_str)
version = preamble->kernel_version; version = preamble->kernel_version;
if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
flags = preamble->flags;
if (keyblock_file) { if (keyblock_file) {
t_keyblock = t_keyblock =
(VbKeyBlockHeader *)ReadFile(keyblock_file, 0); (VbKeyBlockHeader *)ReadFile(keyblock_file, 0);
@@ -509,7 +524,7 @@ static int do_vbutil_kernel(int argc, char *argv[])
vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad, vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
version, kernel_body_load_address, version, kernel_body_load_address,
t_keyblock ? t_keyblock : keyblock, t_keyblock ? t_keyblock : keyblock,
signpriv_key, &vblock_size); signpriv_key, flags, &vblock_size);
if (!vblock_data) if (!vblock_data)
Fatal("Unable to sign kernel blob\n"); Fatal("Unable to sign kernel blob\n");

View File

@@ -305,6 +305,7 @@ uint8_t *UnpackKPart(uint8_t *kpart_data, uint64_t kpart_size,
uint64_t vmlinuz_header_size = 0; uint64_t vmlinuz_header_size = 0;
uint64_t vmlinuz_header_address = 0; uint64_t vmlinuz_header_address = 0;
uint64_t now = 0; uint64_t now = 0;
uint32_t flags = 0;
/* Sanity-check the keyblock */ /* Sanity-check the keyblock */
keyblock = (VbKeyBlockHeader *)kpart_data; keyblock = (VbKeyBlockHeader *)kpart_data;
@@ -347,6 +348,11 @@ uint8_t *UnpackKPart(uint8_t *kpart_data, uint64_t kpart_size,
Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size); Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
Debug(" kern_blob_size = 0x%" PRIx64 "\n", Debug(" kern_blob_size = 0x%" PRIx64 "\n",
preamble->body_signature.data_size); preamble->body_signature.data_size);
if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
flags = preamble->flags;
Debug(" flags = 0x%" PRIx32 "\n", flags);
g_preamble = preamble; g_preamble = preamble;
g_ondisk_bootloader_addr = g_preamble->bootloader_address; g_ondisk_bootloader_addr = g_preamble->bootloader_address;
@@ -392,7 +398,7 @@ uint8_t *SignKernelBlob(uint8_t *kernel_blob, uint64_t kernel_size,
uint64_t padding, uint64_t padding,
int version, uint64_t kernel_body_load_address, int version, uint64_t kernel_body_load_address,
VbKeyBlockHeader *keyblock, VbPrivateKey *signpriv_key, VbKeyBlockHeader *keyblock, VbPrivateKey *signpriv_key,
uint64_t *vblock_size_ptr) uint32_t flags, uint64_t *vblock_size_ptr)
{ {
VbSignature *body_sig; VbSignature *body_sig;
VbKernelPreambleHeader *preamble; VbKernelPreambleHeader *preamble;
@@ -416,6 +422,7 @@ uint8_t *SignKernelBlob(uint8_t *kernel_blob, uint64_t kernel_size,
body_sig, body_sig,
g_ondisk_vmlinuz_header_addr, g_ondisk_vmlinuz_header_addr,
g_vmlinuz_header_size, g_vmlinuz_header_size,
flags,
min_size, min_size,
signpriv_key); signpriv_key);
if (!preamble) { if (!preamble) {
@@ -591,6 +598,10 @@ int VerifyKernelBlob(uint8_t *kernel_blob,
vmlinuz_header_size); vmlinuz_header_size);
} }
if (VbKernelHasFlags(g_preamble) == VBOOT_SUCCESS)
printf(" Flags : 0x%" PRIx32 "\n",
g_preamble->flags);
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 %"

View File

@@ -18,7 +18,7 @@ uint8_t *SignKernelBlob(uint8_t *kernel_blob, uint64_t kernel_size,
uint64_t padding, uint64_t padding,
int version, uint64_t kernel_body_load_address, int version, uint64_t kernel_body_load_address,
VbKeyBlockHeader *keyblock, VbPrivateKey *signpriv_key, VbKeyBlockHeader *keyblock, VbPrivateKey *signpriv_key,
uint64_t *vblock_size_ptr); uint32_t flags, uint64_t *vblock_size_ptr);
int WriteSomeParts(const char *outfile, int WriteSomeParts(const char *outfile,
void *part1_data, uint64_t part1_size, void *part1_data, uint64_t part1_size,

View File

@@ -78,6 +78,7 @@ VbKernelPreambleHeader *CreateKernelPreamble(
const VbSignature *body_signature, const VbSignature *body_signature,
uint64_t vmlinuz_header_address, uint64_t vmlinuz_header_address,
uint64_t vmlinuz_header_size, uint64_t vmlinuz_header_size,
uint32_t flags,
uint64_t desired_size, uint64_t desired_size,
const VbPrivateKey *signing_key) const VbPrivateKey *signing_key)
{ {
@@ -111,6 +112,7 @@ VbKernelPreambleHeader *CreateKernelPreamble(
h->bootloader_size = bootloader_size; h->bootloader_size = bootloader_size;
h->vmlinuz_header_address = vmlinuz_header_address; h->vmlinuz_header_address = vmlinuz_header_address;
h->vmlinuz_header_size = vmlinuz_header_size; h->vmlinuz_header_size = vmlinuz_header_size;
h->flags = flags;
/* Copy body signature */ /* Copy body signature */
SignatureInit(&h->body_signature, body_sig_dest, SignatureInit(&h->body_signature, body_sig_dest,

View File

@@ -52,6 +52,7 @@ VbKernelPreambleHeader *CreateKernelPreamble(
const VbSignature *body_signature, const VbSignature *body_signature,
uint64_t vmlinuz_header_address, uint64_t vmlinuz_header_address,
uint64_t vmlinuz_header_size, uint64_t vmlinuz_header_size,
uint32_t flags,
uint64_t desired_size, uint64_t desired_size,
const VbPrivateKey *signing_key); const VbPrivateKey *signing_key);

View File

@@ -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, 0, 0); CreateKernelPreamble(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
/* file_keys.h */ /* file_keys.h */
BufferFromFile(0, 0); BufferFromFile(0, 0);

View File

@@ -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, 0, 0, private_key); 0, 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;

View File

@@ -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_VBKERNELPREAMBLEHEADER2_1_SIZE, TEST_EQ(EXPECTED_VBKERNELPREAMBLEHEADER2_2_SIZE,
sizeof(VbKernelPreambleHeader), sizeof(VbKernelPreambleHeader),
"sizeof(VbKernelPreambleHeader)"); "sizeof(VbKernelPreambleHeader)");