Dev-mode only boots official kernels by default

Although we're now using a single unified BIOS, it is pretty nice to be able
to get a shell in developer mode while still using verified boot for the
kernel and filesystem. Alex & ZGB implemented this by requiring the dev-mode
user to install a special dev-mode BIOS. We don't do that, but we DO require
setting a special flag with "crossystem" to accomplish the same thing.

In order to allow booting a self-signed kernel, you must boot in developer
mode, open a shell, and run this:

  crossystem dev_boot_custom=1

Special note to internal developers: If you're in the habit (as I am) of
booting directly from a USB stick in dev-mode, you'll have to run this:

  crossystem dev_boot_custom=1 dev_boot_usb=1

Just using dev_boot_usb=1 is no longer enough, because the USB kernel is
signed using the recovery key and by pressing Ctrl-U, we validate it with
the kernel data key. That worked before this change because any self-signed
kernel was fine, and that's how the USB key was treated. Now it actually
requires a verified signature until you enable dev_boot_custom=1 also.

BUG=chrome-os-partner:5954
TEST=manual

Boot once in normal mode, which clears the special flags. Then switch to
developer mode. You should be able to boot and get a root shell.

Run

  crossystem dev_boot_usb=1

Obtain a USB recovery image that's keyed differently. For example, if you're
testing with dev-keys, use a PVT-signed image or vice-versa.

Reboot into dev-mode with the USB recovery stick inserted. At the dev-mode
screen, press Ctrl-U. You should hear a single beep, but it should not boot.

Press Ctrl-D to boot from the hard drive, log in to a shell and run

  crossystem dev_boot_custom=1

Repeat the previous test. This time when you press Ctrl-U, it should boot
the recovery image. Turn the system off before it does anything.

That's it.

Change-Id: I1811ee9a188974b3f94c83c52b00b60028b86c69
Reviewed-on: https://gerrit.chromium.org/gerrit/11442
Tested-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Bill Richardson
2011-11-09 09:11:34 -08:00
parent 9b717be86b
commit fa9d7782e8
9 changed files with 46 additions and 8 deletions

View File

@@ -54,6 +54,8 @@ typedef enum VbNvParam {
VBNV_TEST_ERROR_NUM,
/* Allow booting from USB in developer mode. 0=no, 1=yes. */
VBNV_DEV_BOOT_USB,
/* Allow booting self-signed images in developer mode. 0=no, 1=yes. */
VBNV_DEV_BOOT_CUSTOM,
} VbNvParam;

View File

@@ -234,6 +234,7 @@ typedef struct VbKernelPreambleHeader {
#define VBSD_LKP_CHECK_PREAMBLE_VALID 11
#define VBSD_LKP_CHECK_BODY_ADDRESS 12
#define VBSD_LKP_CHECK_BODY_OFFSET 13
#define VBSD_LKP_CHECK_SELF_SIGNED 14
#define VBSD_LKP_CHECK_BODY_EXCEEDS_MEM 15
#define VBSD_LKP_CHECK_BODY_EXCEEDS_PART 16
#define VBSD_LKP_CHECK_READ_DATA 17

View File

@@ -97,10 +97,11 @@ uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p,
/* Handle a normal boot. */
VbError_t VbBootNormal(VbCommonParams* cparams, LoadKernelParams* p) {
/* Force dev_boot_usb flag disabled. This ensures the flag will be
/* Force dev_boot_* flags disabled. This ensures they will be
* initially disabled if the user later transitions back into
* developer mode. */
VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 0);
VbNvSet(&vnc, VBNV_DEV_BOOT_CUSTOM, 0);
/* Boot from fixed disk only */
return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);

View File

@@ -521,6 +521,11 @@ VbError_t VbDisplayDebugInfo(VbCommonParams* cparams, VbNvContext *vncptr) {
used += Strncat(buf + used, "\ndev_boot_usb: ", DEBUG_INFO_SIZE - used);
used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
/* Add dev_boot_custom flag */
VbNvGet(vncptr, VBNV_DEV_BOOT_CUSTOM, &i);
used += Strncat(buf + used, "\ndev_boot_custom: ", DEBUG_INFO_SIZE - used);
used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
/* Add TPM versions */
used += Strncat(buf + used, "\nTPM: fwver=0x", DEBUG_INFO_SIZE - used);
used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,

View File

@@ -121,6 +121,7 @@ int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData* gptdata) {
/* disable MSVC warning on const logical expression (as in } while(0);) */
__pragma(warning(disable: 4127))
VbError_t LoadKernel(LoadKernelParams* params) {
VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob;
VbSharedDataKernelCall* shcall = NULL;
@@ -139,6 +140,7 @@ VbError_t LoadKernel(LoadKernelParams* params) {
int rec_switch, dev_switch;
BootMode boot_mode;
uint32_t test_err = 0;
uint32_t allow_self_signed = 0;
VbError_t retval = VBERROR_UNKNOWN;
int recovery = VBNV_RECOVERY_RO_UNSPECIFIED;
@@ -162,12 +164,14 @@ VbError_t LoadKernel(LoadKernelParams* params) {
/* Calculate switch positions and boot mode */
rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0);
dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0);
if (rec_switch)
if (rec_switch) {
boot_mode = kBootRecovery;
else if (dev_switch)
} else if (dev_switch) {
boot_mode = kBootDev;
else
VbNvGet(vnc, VBNV_DEV_BOOT_CUSTOM, &allow_self_signed);
} else {
boot_mode = kBootNormal;
}
/* Set up tracking for this call. This wraps around if called many times,
* so we need to initialize the call entry each time. */
@@ -293,8 +297,14 @@ VbError_t LoadKernel(LoadKernelParams* params) {
if (kBootDev != boot_mode)
goto bad_kernel;
/* In developer mode, we can continue if the SHA-512 hash of the key
* block is valid. */
/* In developer mode, we have to explictly allow self-signed kernels */
if (!allow_self_signed) {
VBDEBUG(("Self-signed custom kernels are not enabled.\n"));
shpart->check_result = VBSD_LKP_CHECK_SELF_SIGNED;
goto bad_kernel;
}
/* Allow the kernel if the SHA-512 hash of the key block is valid. */
if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) {
VBDEBUG(("Verifying key block hash failed.\n"));
shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_HASH;

View File

@@ -28,6 +28,7 @@
#define DEV_FLAGS_OFFSET 4
#define DEV_BOOT_USB_MASK 0x01
#define DEV_BOOT_CUSTOM_MASK 0x02
#define FIRMWARE_FLAGS_OFFSET 5
#define FIRMWARE_TEST_ERR_FUNC_MASK 0x38
@@ -142,6 +143,10 @@ int VbNvGet(VbNvContext* context, VbNvParam param, uint32_t* dest) {
*dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_USB_MASK ? 1 : 0);
return 0;
case VBNV_DEV_BOOT_CUSTOM:
*dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_CUSTOM_MASK ? 1 : 0);
return 0;
default:
return 1;
}
@@ -227,6 +232,13 @@ int VbNvSet(VbNvContext* context, VbNvParam param, uint32_t value) {
raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_USB_MASK;
break;
case VBNV_DEV_BOOT_CUSTOM:
if (value)
raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_CUSTOM_MASK;
else
raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_CUSTOM_MASK;
break;
default:
return 1;
}

View File

@@ -390,6 +390,8 @@ int VbGetSystemPropertyInt(const char* name) {
value = VbGetNvStorage(VBNV_LOCALIZATION_INDEX);
} else if (!strcasecmp(name,"dev_boot_usb")) {
value = VbGetNvStorage(VBNV_DEV_BOOT_USB);
} else if (!strcasecmp(name,"dev_boot_custom")) {
value = VbGetNvStorage(VBNV_DEV_BOOT_CUSTOM);
}
/* Other parameters */
else if (!strcasecmp(name,"cros_debug")) {
@@ -469,6 +471,8 @@ int VbSetSystemPropertyInt(const char* name, int value) {
return VbSetNvStorage(VBNV_LOCALIZATION_INDEX, value);
} else if (!strcasecmp(name,"dev_boot_usb")) {
return VbSetNvStorage(VBNV_DEV_BOOT_USB, value);
} else if (!strcasecmp(name,"dev_boot_custom")) {
return VbSetNvStorage(VBNV_DEV_BOOT_CUSTOM, value);
}
return -1;

View File

@@ -32,6 +32,7 @@ static VbNvField nvfields[] = {
{VBNV_TEST_ERROR_FUNC, 0, 1, 7, "verified boot test error func"},
{VBNV_TEST_ERROR_NUM, 0, 3, 6, "verified boot test error number"},
{VBNV_DEV_BOOT_USB, 0, 1, 0, "dev boot usb"},
{VBNV_DEV_BOOT_CUSTOM, 0, 1, 0, "dev boot custom"},
{0, 0, 0, 0, NULL}
};

View File

@@ -39,6 +39,8 @@ const Param sys_param_list[] = {
{"dbg_reset", CAN_WRITE, "Debug reset mode request (writable)"},
{"dev_boot_usb", CAN_WRITE,
"Enable developer mode boot from USB/SD (writable)"},
{"dev_boot_custom", CAN_WRITE,
"Enable developer mode boot using self-signed kernels (writable)"},
{"devsw_boot", 0, "Developer switch position at boot"},
{"devsw_cur", 0, "Developer switch current position"},
{"ecfw_act", IS_STRING, "Active EC firmware"},