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>
diff --git a/firmware/include/vboot_struct.h b/firmware/include/vboot_struct.h
index 9e845ef..09abf13 100644
--- a/firmware/include/vboot_struct.h
+++ b/firmware/include/vboot_struct.h
@@ -180,7 +180,7 @@
 /****************************************************************************/
 
 #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
  *
@@ -260,9 +260,17 @@
 	/* Size of 16-bit header for vmlinuz in bytes.  Readers should return 0
 	   for header version < 2.1 */
 	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;
 
 #define EXPECTED_VBKERNELPREAMBLEHEADER2_1_SIZE 112
+#define EXPECTED_VBKERNELPREAMBLEHEADER2_2_SIZE 116
 
 /****************************************************************************/
 
diff --git a/firmware/lib/include/vboot_common.h b/firmware/lib/include/vboot_common.h
index f792d1a..4d50ff6 100644
--- a/firmware/lib/include/vboot_common.h
+++ b/firmware/lib/include/vboot_common.h
@@ -41,6 +41,8 @@
 	VBOOT_PREAMBLE_SIGNATURE,
 	/* Shared data is invalid. */
 	VBOOT_SHARED_DATA_INVALID,
+	/* Kernel Preamble does not contain flags */
+	VBOOT_KERNEL_PREAMBLE_NO_FLAGS,
 	VBOOT_ERROR_MAX,
 };
 extern const char *kVbootErrors[VBOOT_ERROR_MAX];
@@ -161,6 +163,15 @@
 			     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.
  *
  * Returns VBOOT_SUCCESS or VBOOT_PREAMBLE_INVALID on error
diff --git a/firmware/lib/vboot_common.c b/firmware/lib/vboot_common.c
index 2cb01f3..226cdb7 100644
--- a/firmware/lib/vboot_common.c
+++ b/firmware/lib/vboot_common.c
@@ -437,13 +437,20 @@
 
 	/*
 	 * 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(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"));
 			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 */
@@ -469,6 +476,14 @@
 	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,
 			     uint64_t header, uint64_t header_size)
 {
diff --git a/futility/cmd_show.c b/futility/cmd_show.c
index dc7c814..b6c2574 100644
--- a/futility/cmd_show.c
+++ b/futility/cmd_show.c
@@ -419,6 +419,7 @@
 	int retval = 0;
 	uint64_t vmlinuz_header_size = 0;
 	uint64_t vmlinuz_header_address = 0;
+	uint32_t flags = 0;
 
 	/* Check the hash... */
 	if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
@@ -483,6 +484,10 @@
 		       vmlinuz_header_size);
 	}
 
+	if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
+		flags = preamble->flags;
+	printf("  Flags:                 0x%" PRIx32 "\n", flags);
+
 	/* Verify kernel body */
 	if (option.fv) {
 		/* It's in a separate file, which we've already read in */
diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c
index a960abd..2d247bc 100644
--- a/futility/cmd_sign.c
+++ b/futility/cmd_sign.c
@@ -219,7 +219,7 @@
 	vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
 				     option.version, option.kloadaddr,
 				     option.keyblock, option.signprivate,
-				     &vblock_size);
+				     option.flags, &vblock_size);
 	if (!vblock_data) {
 		fprintf(stderr, "Unable to sign kernel blob\n");
 		free(kblob_data);
@@ -288,6 +288,12 @@
 	if (!option.version_specified)
 		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 */
 	if (option.keyblock)
 		keyblock = option.keyblock;
@@ -296,7 +302,7 @@
 	vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
 				     option.version, option.kloadaddr,
 				     keyblock, option.signprivate,
-				     &vblock_size);
+				     option.flags, &vblock_size);
 	if (!vblock_data) {
 		fprintf(stderr, "Unable to sign kernel blob\n");
 		return 1;
@@ -612,7 +618,8 @@
 	"  --pad            NUM             The vblock padding size in bytes\n"
 	"                                     (default 0x%x)\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"
 	"-----------------------------------------------------------------\n"
@@ -634,6 +641,7 @@
 	"  [--outfile]      OUTFILE         Output kernel partition or vblock\n"
 	"  --vblockonly                     Emit just the vblock (requires a\n"
 	"                                     distinct OUTFILE)\n"
+	"  -f|--flags       NUM             The preamble flags value\n"
 	"\n";
 
 static void print_help(const char *prog)
diff --git a/futility/cmd_vbutil_kernel.c b/futility/cmd_vbutil_kernel.c
index ae4fd3f..3322e4b 100644
--- a/futility/cmd_vbutil_kernel.c
+++ b/futility/cmd_vbutil_kernel.c
@@ -63,6 +63,7 @@
 	OPT_VERBOSE,
 	OPT_MINVERSION,
 	OPT_VMLINUZ_OUT,
+	OPT_FLAGS,
 };
 
 static const struct option long_opts[] = {
@@ -86,6 +87,7 @@
 	{"verbose", 0, &opt_verbose, 1},
 	{"debug", 0, &debugging_enabled, 1},
 	{"vmlinuz-out", 1, 0, OPT_VMLINUZ_OUT},
+	{"flags", 1, 0, OPT_FLAGS},
 	{NULL, 0, 0, 0}
 };
 
@@ -109,6 +111,7 @@
 	"    --kloadaddr <address>     Assign kernel body load address\n"
 	"    --pad <number>            Verification padding size in bytes\n"
 	"    --vblockonly              Emit just the verification blob\n"
+	"    --flags NUM               Flags to be passed in the header\n"
 	"\nOR\n\n"
 	"Usage:  " MYNAME " %s --repack <file> [PARAMETERS]\n"
 	"\n"
@@ -253,6 +256,7 @@
 	uint64_t kblob_size = 0;
 	uint8_t *vblock_data = NULL;
 	uint64_t vblock_size = 0;
+	uint32_t flags = 0;
 	FILE *f;
 
 	while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
@@ -328,6 +332,14 @@
 			vmlinuz_file = optarg;
 			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:
 			bootloader_file = optarg;
 			break;
@@ -435,7 +447,7 @@
 
 		vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
 					     version, kernel_body_load_address,
-					     t_keyblock, signpriv_key,
+					     t_keyblock, signpriv_key, flags,
 					     &vblock_size);
 		if (!vblock_data)
 			Fatal("Unable to sign kernel blob\n");
@@ -498,6 +510,9 @@
 		if (!version_str)
 			version = preamble->kernel_version;
 
+		if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
+			flags = preamble->flags;
+
 		if (keyblock_file) {
 			t_keyblock =
 				(VbKeyBlockHeader *)ReadFile(keyblock_file, 0);
@@ -509,7 +524,7 @@
 		vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
 					     version, kernel_body_load_address,
 					     t_keyblock ? t_keyblock : keyblock,
-					     signpriv_key, &vblock_size);
+					     signpriv_key, flags, &vblock_size);
 		if (!vblock_data)
 			Fatal("Unable to sign kernel blob\n");
 
diff --git a/futility/vb1_helper.c b/futility/vb1_helper.c
index f40b7ac..3d3225a 100644
--- a/futility/vb1_helper.c
+++ b/futility/vb1_helper.c
@@ -305,6 +305,7 @@
 	uint64_t vmlinuz_header_size = 0;
 	uint64_t vmlinuz_header_address = 0;
 	uint64_t now = 0;
+	uint32_t flags = 0;
 
 	/* Sanity-check the keyblock */
 	keyblock = (VbKeyBlockHeader *)kpart_data;
@@ -347,6 +348,11 @@
 	Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
 	Debug(" kern_blob_size = 0x%" PRIx64 "\n",
 	      preamble->body_signature.data_size);
+
+	if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
+		flags = preamble->flags;
+	Debug(" flags = 0x%" PRIx32 "\n", flags);
+
 	g_preamble = preamble;
 	g_ondisk_bootloader_addr = g_preamble->bootloader_address;
 
@@ -392,7 +398,7 @@
 			uint64_t padding,
 			int version, uint64_t kernel_body_load_address,
 			VbKeyBlockHeader *keyblock, VbPrivateKey *signpriv_key,
-			uint64_t *vblock_size_ptr)
+			uint32_t flags, uint64_t *vblock_size_ptr)
 {
 	VbSignature *body_sig;
 	VbKernelPreambleHeader *preamble;
@@ -416,6 +422,7 @@
 					body_sig,
 					g_ondisk_vmlinuz_header_addr,
 					g_vmlinuz_header_size,
+					flags,
 					min_size,
 					signpriv_key);
 	if (!preamble) {
@@ -591,6 +598,10 @@
 		       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)) {
 		fprintf(stderr,
 			"Kernel version %" PRIu64 " is lower than minimum %"
diff --git a/futility/vb1_helper.h b/futility/vb1_helper.h
index fd976e0..2cf71f4 100644
--- a/futility/vb1_helper.h
+++ b/futility/vb1_helper.h
@@ -18,7 +18,7 @@
 			uint64_t padding,
 			int version, uint64_t kernel_body_load_address,
 			VbKeyBlockHeader *keyblock, VbPrivateKey *signpriv_key,
-			uint64_t *vblock_size_ptr);
+			uint32_t flags, uint64_t *vblock_size_ptr);
 
 int WriteSomeParts(const char *outfile,
 		   void *part1_data, uint64_t part1_size,
diff --git a/host/lib/host_common.c b/host/lib/host_common.c
index b9c00cd..959b65a 100644
--- a/host/lib/host_common.c
+++ b/host/lib/host_common.c
@@ -78,6 +78,7 @@
 	const VbSignature *body_signature,
 	uint64_t vmlinuz_header_address,
 	uint64_t vmlinuz_header_size,
+	uint32_t flags,
 	uint64_t desired_size,
 	const VbPrivateKey *signing_key)
 {
@@ -111,6 +112,7 @@
 	h->bootloader_size = bootloader_size;
 	h->vmlinuz_header_address = vmlinuz_header_address;
 	h->vmlinuz_header_size = vmlinuz_header_size;
+	h->flags = flags;
 
 	/* Copy body signature */
 	SignatureInit(&h->body_signature, body_sig_dest,
diff --git a/host/lib/include/host_common.h b/host/lib/include/host_common.h
index b4693f8..895a675 100644
--- a/host/lib/include/host_common.h
+++ b/host/lib/include/host_common.h
@@ -52,6 +52,7 @@
 	const VbSignature *body_signature,
 	uint64_t vmlinuz_header_address,
 	uint64_t vmlinuz_header_size,
+	uint32_t flags,
 	uint64_t desired_size,
 	const VbPrivateKey *signing_key);
 
diff --git a/host/linktest/main.c b/host/linktest/main.c
index e24d557..8e1525f 100644
--- a/host/linktest/main.c
+++ b/host/linktest/main.c
@@ -41,7 +41,7 @@
 
   /* host_common.h */
   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 */
   BufferFromFile(0, 0);
diff --git a/tests/vboot_common2_tests.c b/tests/vboot_common2_tests.c
index 3a2b59f..4095311 100644
--- a/tests/vboot_common2_tests.c
+++ b/tests/vboot_common2_tests.c
@@ -128,7 +128,7 @@
 
 	rsa = PublicKeyToRSA(public_key);
 	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");
 	if (!hdr)
 		return;
diff --git a/tests/vboot_common_tests.c b/tests/vboot_common_tests.c
index 8fd021a..3c303a6 100644
--- a/tests/vboot_common_tests.c
+++ b/tests/vboot_common_tests.c
@@ -31,7 +31,7 @@
 	TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE,
 		sizeof(VbFirmwarePreambleHeader),
 		"sizeof(VbFirmwarePreambleHeader)");
-	TEST_EQ(EXPECTED_VBKERNELPREAMBLEHEADER2_1_SIZE,
+	TEST_EQ(EXPECTED_VBKERNELPREAMBLEHEADER2_2_SIZE,
 		sizeof(VbKernelPreambleHeader),
 		"sizeof(VbKernelPreambleHeader)");