summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/lib/ec_sync.c65
-rw-r--r--firmware/lib/include/vboot_common.h13
-rw-r--r--firmware/lib/vboot_api_kernel.c26
-rw-r--r--firmware/lib/vboot_common.c14
-rw-r--r--firmware/lib/vboot_ui.c15
-rw-r--r--firmware/lib/vboot_ui_menu.c15
-rw-r--r--tests/ec_sync_tests.c31
-rw-r--r--tests/vboot_api_kernel2_tests.c4
-rw-r--r--tests/vboot_api_kernel4_tests.c16
9 files changed, 59 insertions, 140 deletions
diff --git a/firmware/lib/ec_sync.c b/firmware/lib/ec_sync.c
index 10ce5576..baf3cfc2 100644
--- a/firmware/lib/ec_sync.c
+++ b/firmware/lib/ec_sync.c
@@ -197,59 +197,16 @@ static VbError_t update_ec(struct vb2_context *ctx, int devidx,
}
/**
- * Check if the EC has the correct image active.
+ * Set IN_RW flag for a EC
*
* @param ctx Vboot2 context
* @param devidx Which device (EC=0, PD=1)
- * @return VBERROR_SUCCESS, or non-zero if error.
*/
-static VbError_t check_ec_active(struct vb2_context *ctx, int devidx)
+static void check_ec_active(struct vb2_context *ctx, int devidx)
{
struct vb2_shared_data *sd = vb2_get_sd(ctx);
-
- /* Determine whether the EC is in RO or RW */
- int in_rw = 0;
- int rv = VbExEcRunningRW(devidx, &in_rw);
- if (in_rw) {
+ if (!VbExTrustEC(devidx))
sd->flags |= IN_RW(devidx);
- }
-
- if (sd->recovery_reason) {
- /*
- * Recovery mode; just verify the EC is in RO code. Don't do
- * software sync, since we don't have a RW image.
- */
- if (rv == VBERROR_SUCCESS && in_rw == 1) {
- /*
- * EC is definitely in RW firmware. We want it in
- * read-only code, so preserve the current recovery
- * reason and reboot.
- *
- * We don't reboot on error or unknown EC code, because
- * we could end up in an endless reboot loop. If we
- * had some way to track that we'd already rebooted for
- * this reason, we could retry only once.
- */
- VB2_DEBUG("want recovery but got EC-RW\n");
- request_recovery(ctx, sd->recovery_reason);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- VB2_DEBUG("in recovery; EC-RO\n");
- return VBERROR_SUCCESS;
- }
-
- /*
- * Not in recovery. If we couldn't determine where the EC was,
- * reboot to recovery.
- */
- if (rv != VBERROR_SUCCESS) {
- VB2_DEBUG("VbExEcRunningRW() returned %d\n", rv);
- request_recovery(ctx, VB2_RECOVERY_EC_UNKNOWN_IMAGE);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- return VBERROR_SUCCESS;
}
#define RO_RETRIES 2 /* Maximum times to retry flashing RO */
@@ -383,18 +340,10 @@ VbError_t ec_sync_phase1(struct vb2_context *ctx, VbCommonParams *cparams)
const int do_pd_sync = 0;
#endif
- /* Make sure the EC is running the correct image */
- if (check_ec_active(ctx, 0))
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- if (do_pd_sync && check_ec_active(ctx, 1))
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
-
- /*
- * In recovery mode; just verify the EC is in RO code. Don't do
- * software sync, since we don't have a RW image.
- */
- if (sd->recovery_reason)
- return VBERROR_SUCCESS;
+ /* Set IN_RW flags */
+ check_ec_active(ctx, 0);
+ if (do_pd_sync)
+ check_ec_active(ctx, 1);
/* Check if we need to update RW. Failures trigger recovery mode. */
if (check_ec_hash(ctx, 0, VB_SELECT_FIRMWARE_EC_ACTIVE))
diff --git a/firmware/lib/include/vboot_common.h b/firmware/lib/include/vboot_common.h
index 88bcb631..acfb58b7 100644
--- a/firmware/lib/include/vboot_common.h
+++ b/firmware/lib/include/vboot_common.h
@@ -137,4 +137,17 @@ uint64_t VbSharedDataReserve(VbSharedDataHeader *header, uint64_t size);
int VbSharedDataSetKernelKey(VbSharedDataHeader *header,
const VbPublicKey *src);
+/**
+ * Check whether recovery is allowed or not.
+ *
+ * The only way to pass this check and proceed to the recovery process is to
+ * physically request a recovery (a.k.a. manual recovery). All other recovery
+ * requests including manual recovery requested by a (compromised) host will
+ * end up with 'broken' screen.
+ *
+ * @param flags Flags of VbSharedDataHeader.
+ * @return 1: Yes. 0: No or not sure.
+ */
+int vb2_allow_recovery(uint32_t flags);
+
#endif /* VBOOT_REFERENCE_VBOOT_COMMON_H_ */
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index d1afc4f7..5c54c122 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -417,27 +417,29 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
goto VbSelectAndLoadKernel_exit;
/*
- * Do EC software sync if necessary. This has UI, but it's just a
- * single non-interactive WAIT screen.
+ * Do EC software sync unless we're in recovery mode. This has UI but
+ * it's just a single non-interactive WAIT screen.
*/
- retval = ec_sync_all(&ctx, cparams);
- if (retval)
- goto VbSelectAndLoadKernel_exit;
+ if (shared->recovery_reason == VB2_RECOVERY_NOT_REQUESTED) {
+ retval = ec_sync_all(&ctx, cparams);
+ if (retval)
+ goto VbSelectAndLoadKernel_exit;
+ }
/* Select boot path */
if (shared->recovery_reason) {
/* Recovery boot. This has UI. */
- if (kparams->inflags & VB_SALK_INFLAGS_ENABLE_DETACHABLE_UI)
- retval = VbBootRecoveryMenu(&ctx, cparams);
- else
- retval = VbBootRecovery(&ctx, cparams);
+ if (kparams->inflags & VB_SALK_INFLAGS_ENABLE_DETACHABLE_UI)
+ retval = VbBootRecoveryMenu(&ctx, cparams);
+ else
+ retval = VbBootRecovery(&ctx, cparams);
VbExEcEnteringMode(0, VB_EC_RECOVERY);
} else if (shared->flags & VBSD_BOOT_DEV_SWITCH_ON) {
/* Developer boot. This has UI. */
- if (kparams->inflags & VB_SALK_INFLAGS_ENABLE_DETACHABLE_UI)
- retval = VbBootDeveloperMenu(&ctx, cparams);
+ if (kparams->inflags & VB_SALK_INFLAGS_ENABLE_DETACHABLE_UI)
+ retval = VbBootDeveloperMenu(&ctx, cparams);
else
- retval = VbBootDeveloper(&ctx, cparams);
+ retval = VbBootDeveloper(&ctx, cparams);
VbExEcEnteringMode(0, VB_EC_DEVELOPER);
} else {
/* Normal boot */
diff --git a/firmware/lib/vboot_common.c b/firmware/lib/vboot_common.c
index fd6ef79b..1c826667 100644
--- a/firmware/lib/vboot_common.c
+++ b/firmware/lib/vboot_common.c
@@ -210,3 +210,17 @@ int VbSharedDataSetKernelKey(VbSharedDataHeader *header, const VbPublicKey *src)
return PublicKeyCopy(kdest, src);
}
+
+int vb2_allow_recovery(uint32_t flags)
+{
+ /* In dev mode, unconditionally allowed. */
+ if (flags & VBSD_BOOT_DEV_SWITCH_ON)
+ return 1;
+
+ /* If EC is in RW, it implies recovery wasn't manually requested. */
+ if (!VbExTrustEC(0))
+ return 0;
+
+ /* Now we confidently check the recovery switch state at boot */
+ return !!(flags & VBSD_BOOT_REC_SWITCH_ON);
+}
diff --git a/firmware/lib/vboot_ui.c b/firmware/lib/vboot_ui.c
index 4739cd64..c3a3e9e9 100644
--- a/firmware/lib/vboot_ui.c
+++ b/firmware/lib/vboot_ui.c
@@ -413,7 +413,7 @@ VbError_t VbBootDeveloper(struct vb2_context *ctx, VbCommonParams *cparams)
#define REC_KEY_DELAY 20 /* Check keys every 20ms */
#define REC_MEDIA_INIT_DELAY 500 /* Check removable media every 500ms */
-VbError_t vb2_recovery_ui(struct vb2_context *ctx, VbCommonParams *cparams)
+static VbError_t recovery_ui(struct vb2_context *ctx, VbCommonParams *cparams)
{
VbSharedDataHeader *shared =
(VbSharedDataHeader *)cparams->shared_data_blob;
@@ -423,21 +423,14 @@ VbError_t vb2_recovery_ui(struct vb2_context *ctx, VbCommonParams *cparams)
VB2_DEBUG("VbBootRecovery() start\n");
- /*
- * If the dev-mode switch is off and the user didn't press the recovery
- * button (recovery was triggerred automatically), show 'broken' screen.
- * The user can either only shutdown to abort or hit esc+refresh+power
- * to initiate recovery as instructed on the screen.
- */
- if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
- !(shared->flags & VBSD_BOOT_REC_SWITCH_ON)) {
+ if (!vb2_allow_recovery(shared->flags)) {
/*
* We have to save the reason here so that it will survive
* coming up three-finger-salute. We're saving it in
* VBNV_RECOVERY_SUBCODE to avoid a recovery loop.
* If we save the reason in VBNV_RECOVERY_REQUEST, we will come
* back here, thus, we won't be able to give a user a chance to
- * reboot to workaround boot hicups.
+ * reboot to workaround a boot hiccup.
*/
VB2_DEBUG("VbBootRecovery() saving recovery reason (%#x)\n",
shared->recovery_reason);
@@ -563,7 +556,7 @@ VbError_t vb2_recovery_ui(struct vb2_context *ctx, VbCommonParams *cparams)
VbError_t VbBootRecovery(struct vb2_context *ctx, VbCommonParams *cparams)
{
- VbError_t retval = vb2_recovery_ui(ctx, cparams);
+ VbError_t retval = recovery_ui(ctx, cparams);
VbDisplayScreen(ctx, cparams, VB_SCREEN_BLANK, 0);
return retval;
}
diff --git a/firmware/lib/vboot_ui_menu.c b/firmware/lib/vboot_ui_menu.c
index cacee432..9d6b37d8 100644
--- a/firmware/lib/vboot_ui_menu.c
+++ b/firmware/lib/vboot_ui_menu.c
@@ -1019,7 +1019,7 @@ VbError_t VbBootDeveloperMenu(struct vb2_context *ctx, VbCommonParams *cparams)
* @param cparams Vboot1 common params
* @return VBERROR_SUCCESS, or non-zero error code if error.
*/
-VbError_t vb2_recovery_menu(struct vb2_context *ctx, VbCommonParams *cparams)
+static VbError_t recovery_ui(struct vb2_context *ctx, VbCommonParams *cparams)
{
VbSharedDataHeader *shared =
(VbSharedDataHeader *)cparams->shared_data_blob;
@@ -1031,21 +1031,14 @@ VbError_t vb2_recovery_menu(struct vb2_context *ctx, VbCommonParams *cparams)
VB2_DEBUG("start\n");
- /*
- * If the dev-mode switch is off and the user didn't press the recovery
- * button (recovery was triggerred automatically), show 'broken' screen.
- * The user can either only shutdown to abort or hit esc+refresh+power
- * to initiate recovery as instructed on the screen.
- */
- if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
- !(shared->flags & VBSD_BOOT_REC_SWITCH_ON)) {
+ if (!vb2_allow_recovery(shared->flags)) {
/*
* We have to save the reason here so that it will survive
* coming up three-finger-salute. We're saving it in
* VBNV_RECOVERY_SUBCODE to avoid a recovery loop.
* If we save the reason in VBNV_RECOVERY_REQUEST, we will come
* back here, thus, we won't be able to give a user a chance to
- * reboot to workaround boot hicups.
+ * reboot to workaround a boot hiccup.
*/
VB2_DEBUG("saving recovery reason (%#x)\n",
shared->recovery_reason);
@@ -1253,7 +1246,7 @@ VbError_t vb2_recovery_menu(struct vb2_context *ctx, VbCommonParams *cparams)
VbError_t VbBootRecoveryMenu(struct vb2_context *ctx, VbCommonParams *cparams)
{
- VbError_t retval = vb2_recovery_menu(ctx, cparams);
+ VbError_t retval = recovery_ui(ctx, cparams);
VbDisplayScreen(ctx, cparams, VB_SCREEN_BLANK, 0);
return retval;
}
diff --git a/tests/ec_sync_tests.c b/tests/ec_sync_tests.c
index dc708c1f..56f3baae 100644
--- a/tests/ec_sync_tests.c
+++ b/tests/ec_sync_tests.c
@@ -32,9 +32,7 @@ static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
static GoogleBinaryBlockHeader gbb;
-static int trust_ec;
static int mock_in_rw;
-static VbError_t in_rw_retval;
static int protect_retval;
static int ec_ro_protected;
static int ec_rw_protected;
@@ -90,14 +88,12 @@ static void ResetMocks(void)
VbSharedDataInit(shared, sizeof(shared_data));
shared->flags = VBSD_EC_SOFTWARE_SYNC;
- trust_ec = 0;
mock_in_rw = 0;
ec_ro_protected = 0;
ec_rw_protected = 0;
ec_run_image = 0; /* 0 = RO, 1 = RW */
ec_ro_updated = 0;
ec_rw_updated = 0;
- in_rw_retval = VBERROR_SUCCESS;
protect_retval = VBERROR_SUCCESS;
update_retval = VBERROR_SUCCESS;
run_retval = VBERROR_SUCCESS;
@@ -143,13 +139,7 @@ uint32_t VbExIsShutdownRequested(void)
int VbExTrustEC(int devidx)
{
- return trust_ec;
-}
-
-VbError_t VbExEcRunningRW(int devidx, int *in_rw)
-{
- *in_rw = mock_in_rw;
- return in_rw_retval;
+ return !mock_in_rw;
}
VbError_t VbExEcProtect(int devidx, enum VbSelectFirmware_t select)
@@ -169,7 +159,6 @@ VbError_t VbExEcDisableJump(int devidx)
VbError_t VbExEcJumpToRW(int devidx)
{
ec_run_image = 1;
- mock_in_rw = 1;
return run_retval;
}
@@ -248,24 +237,6 @@ static void test_ssync(VbError_t retval, int recovery_reason, const char *desc)
static void VbSoftwareSyncTest(void)
{
- /* Recovery cases */
- ResetMocks();
- sd->recovery_reason = 123;
- test_ssync(0, 0, "In recovery, EC-RO");
- TEST_EQ(ec_rw_protected, 0, " ec rw protected");
-
- ResetMocks();
- sd->recovery_reason = 123;
- mock_in_rw = 1;
- test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
- 123, "Recovery needs EC-RO");
-
- /* AP-RO cases */
- ResetMocks();
- in_rw_retval = VBERROR_SIMULATED;
- test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
- VBNV_RECOVERY_EC_UNKNOWN_IMAGE, "Unknown EC image");
-
/* Calculate hashes */
ResetMocks();
mock_ec_rw_hash_size = 0;
diff --git a/tests/vboot_api_kernel2_tests.c b/tests/vboot_api_kernel2_tests.c
index f6776e9e..02a9087a 100644
--- a/tests/vboot_api_kernel2_tests.c
+++ b/tests/vboot_api_kernel2_tests.c
@@ -591,8 +591,8 @@ static void VbBootRecTest(void)
TEST_EQ(VbBootRecovery(&ctx, &cparams),
VBERROR_SHUTDOWN_REQUESTED,
"No remove in rec");
- TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_INSERT,
- " insert screen");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_OS_BROKEN,
+ " broken screen");
/* Removal if no disk initially found, but found on second attempt */
ResetMocks();
diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c
index 41e58c8e..59650701 100644
--- a/tests/vboot_api_kernel4_tests.c
+++ b/tests/vboot_api_kernel4_tests.c
@@ -29,7 +29,6 @@ static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
static GoogleBinaryBlockHeader gbb;
-static int ecsync_retval;
static uint32_t rkr_version;
static uint32_t new_version;
static struct RollbackSpaceFwmp rfr_fwmp;
@@ -62,7 +61,6 @@ static void ResetMocks(void)
memset(&rfr_fwmp, 0, sizeof(rfr_fwmp));
rfr_retval = TPM_SUCCESS;
- ecsync_retval = VBERROR_SUCCESS;
rkr_version = new_version = 0x10002;
rkr_retval = rkw_retval = rkl_retval = VBERROR_SUCCESS;
vbboot_retval = VBERROR_SUCCESS;
@@ -82,11 +80,6 @@ VbError_t VbExNvStorageWrite(const uint8_t *buf)
return VBERROR_SUCCESS;
}
-VbError_t VbExEcRunningRW(int devidx, int *in_rw)
-{
- return ecsync_retval;
-}
-
uint32_t RollbackKernelRead(uint32_t *version)
{
*version = rkr_version;
@@ -158,26 +151,17 @@ static void VbSlkTest(void)
ResetMocks();
test_slk(0, 0, "Normal");
- /* Mock error early in software sync */
- ResetMocks();
- shared->flags |= VBSD_EC_SOFTWARE_SYNC;
- ecsync_retval = VBERROR_SIMULATED;
- test_slk(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
- VBNV_RECOVERY_EC_UNKNOWN_IMAGE, "EC sync bad");
-
/*
* If shared->flags doesn't ask for software sync, we won't notice
* that error.
*/
ResetMocks();
- ecsync_retval = VBERROR_SIMULATED;
test_slk(0, 0, "EC sync not done");
/* Same if shared->flags asks for sync, but it's overridden by GBB */
ResetMocks();
shared->flags |= VBSD_EC_SOFTWARE_SYNC;
gbb.flags |= GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC;
- ecsync_retval = VBERROR_SIMULATED;
test_slk(0, 0, "EC sync disabled by GBB");
/* Rollback kernel version */