diff options
author | Luigi Semenzato <semenzato@chromium.org> | 2014-01-10 16:26:08 -0800 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-01-19 04:14:59 +0000 |
commit | a53a0b040f45a1086515e7a5c8a8326c0b1d1f74 (patch) | |
tree | 080214e3c0574eaeac8d0e4f8e708831e3f379e7 /firmware/lib | |
parent | 46e00e63805f85c05449ce09cd843a18b76ca665 (diff) | |
download | vboot-a53a0b040f45a1086515e7a5c8a8326c0b1d1f74.tar.gz |
vboot: use recovery button as dev mode switch confirmationstabilize-5339.B
We don't allow ENTER from a USB keyboard as the confirmation
in the switch from normal to developer mode.
For devices that have a physical recovery button, we require
a recovery button press instead. For other devices, we
require that ENTER be pressed on the internal keyboard.
This prevents an "evil keyboard" attack in which a USB keyboard
(or other USB device pretending to be a keyboard) sends a
control-D/ENTER sequence shortly after every boot (followed
by more evil keys). In that situation, when users power-on in
recovery mode, they will be forced to dev mode even if it
was not their intention. Further attacks are easy at
that point.
TESTING. On a panther device:
1. powered on with recovery button pressed -> booted in recovery mode
2. pressed control-D on external USB keyboard -> got to ToDev? screen
3. pressed ENTER -> system beeped
4. pressed recovery button -> system rebooted in DEV mode
... all as expected
Also:
1. powered on with recovery button pressed and HELD recovery button
2. pressed control-D -> system beeped
BUG=chrome-os-partner:21729
TEST=manual (see commit message)
BRANCH=none
CQ-DEPEND=CL:182420,CL:182946,CL:182357
Change-Id: Ib986d00d4567c2d447f8bbff0e5ccfec94596aa7
Reviewed-on: https://chromium-review.googlesource.com/182241
Reviewed-by: Luigi Semenzato <semenzato@chromium.org>
Tested-by: Luigi Semenzato <semenzato@chromium.org>
Commit-Queue: Luigi Semenzato <semenzato@chromium.org>
Diffstat (limited to 'firmware/lib')
-rw-r--r-- | firmware/lib/include/vboot_kernel.h | 10 | ||||
-rw-r--r-- | firmware/lib/vboot_api_init.c | 2 | ||||
-rw-r--r-- | firmware/lib/vboot_api_kernel.c | 60 |
3 files changed, 65 insertions, 7 deletions
diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h index 48e12536..2804434f 100644 --- a/firmware/lib/include/vboot_kernel.h +++ b/firmware/lib/include/vboot_kernel.h @@ -44,6 +44,10 @@ void VbApiKernelFree(VbCommonParams *cparams); uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p, uint32_t get_info_flags); +/* Flags for VbUserConfirms() */ +#define VB_CONFIRM_MUST_TRUST_KEYBOARD (1 << 0) +#define VB_CONFIRM_SPACE_MEANS_NO (1 << 1) + /** * Ask the user to confirm something. * @@ -52,9 +56,13 @@ uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p, * don't return until one of those keys is pressed, or until asked to shut * down. * + * Additionally, in some situations we don't accept confirmations from an + * untrusted keyboard (such as a USB device). In those cases, a recovery + * button press is needed for confirmation, instead of ENTER. + * * Returns: 1=yes, 0=no, -1 = shutdown. */ -int VbUserConfirms(VbCommonParams *cparams, int space_means_no); +int VbUserConfirms(VbCommonParams *cparams, uint32_t confirm_flags); /** * Handle a normal boot. diff --git a/firmware/lib/vboot_api_init.c b/firmware/lib/vboot_api_init.c index ebafe2a7..58bc215f 100644 --- a/firmware/lib/vboot_api_init.c +++ b/firmware/lib/vboot_api_init.c @@ -76,6 +76,8 @@ VbError_t VbInit(VbCommonParams *cparams, VbInitParams *iparams) shared->flags |= VBSD_EC_SOFTWARE_SYNC; if (iparams->flags & VB_INIT_FLAG_EC_SLOW_UPDATE) shared->flags |= VBSD_EC_SLOW_UPDATE; + if (iparams->flags & VB_INIT_FLAG_VIRTUAL_REC_SWITCH) + shared->flags |= VBSD_BOOT_REC_SWITCH_VIRTUAL; is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0); diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index 4cf2a946..7f85dc75 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -130,26 +130,42 @@ uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p, #define CONFIRM_KEY_DELAY 20 /* Check confirm screen keys every 20ms */ -int VbUserConfirms(VbCommonParams *cparams, int space_means_no) +int VbUserConfirms(VbCommonParams *cparams, uint32_t confirm_flags) { + VbSharedDataHeader *shared = + (VbSharedDataHeader *)cparams->shared_data_blob; uint32_t key; + uint32_t key_flags; + uint32_t button; + int rec_button_was_pressed = 0; - VBDEBUG(("Entering %s(%d)\n", __func__, space_means_no)); + VBDEBUG(("Entering %s(0x%x)\n", __func__, confirm_flags)); /* Await further instructions */ while (1) { if (VbExIsShutdownRequested()) return -1; - key = VbExKeyboardRead(); + key = VbExKeyboardReadWithFlags(&key_flags); + button = VbExGetSwitches(VB_INIT_FLAG_REC_BUTTON_PRESSED); switch (key) { case '\r': + /* If we require a trusted keyboard for confirmation, + * but the keyboard may be faked (for instance, a USB + * device), beep and keep waiting. + */ + if (confirm_flags & VB_CONFIRM_MUST_TRUST_KEYBOARD && + !(key_flags & VB_KEY_FLAG_TRUSTED_KEYBOARD)) { + VbExBeep(120, 400); + break; + } + VBDEBUG(("%s() - Yes (1)\n", __func__)); return 1; break; case ' ': VBDEBUG(("%s() - Space (%d)\n", __func__, - space_means_no)); - if (space_means_no) + confirm_flags & VB_CONFIRM_SPACE_MEANS_NO)); + if (confirm_flags & VB_CONFIRM_SPACE_MEANS_NO) return 0; break; case 0x1b: @@ -157,6 +173,20 @@ int VbUserConfirms(VbCommonParams *cparams, int space_means_no) return 0; break; default: + /* If the recovery button is physical, and is pressed, + * this is also a YES, but must wait for release. + */ + if (!(shared->flags & VBSD_BOOT_REC_SWITCH_VIRTUAL)) { + if (button) { + VBDEBUG(("%s() - Rec button pressed\n", + __func__)); + rec_button_was_pressed = 1; + } else if (rec_button_was_pressed) { + VBDEBUG(("%s() - Rec button (1)\n", + __func__)); + return 1; + } + } VbCheckDisplayKey(cparams, key, &vnc); } VbExSleepMs(CONFIRM_KEY_DELAY); @@ -505,12 +535,30 @@ VbError_t VbBootRecovery(VbCommonParams *cparams, LoadKernelParams *p) !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) && (shared->flags & VBSD_BOOT_REC_SWITCH_ON) && VbExTrustEC()) { + if (!(shared->flags & + VBSD_BOOT_REC_SWITCH_VIRTUAL) && + VbExGetSwitches( + VB_INIT_FLAG_REC_BUTTON_PRESSED)) { + /* + * Is the recovery button stuck? In + * any case we don't like this. Beep + * and ignore. + */ + VBDEBUG(("%s() - ^D but rec switch " + "is pressed\n", __func__)); + VbExBeep(120, 400); + continue; + } + /* Ask the user to confirm entering dev-mode */ VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_TO_DEV, 0, &vnc); /* SPACE means no... */ - switch (VbUserConfirms(cparams, 1)) { + uint32_t vbc_flags = + VB_CONFIRM_SPACE_MEANS_NO | + VB_CONFIRM_MUST_TRUST_KEYBOARD; + switch (VbUserConfirms(cparams, vbc_flags)) { case 1: VBDEBUG(("%s() Enabling dev-mode...\n", __func__)); |