summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@google.com>2017-03-30 17:40:18 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-04-11 20:22:31 -0700
commit3f0714c1e29dab5817dfe1aa8733c7235ea85ee4 (patch)
tree21342a7fce6ee2c7686117211ca05ecfe9a3d2e4
parentbcc4e087a13727755482b13b44f1ab7bfd361beb (diff)
downloadchrome-ec-3f0714c1e29dab5817dfe1aa8733c7235ea85ee4.tar.gz
rollback: Update and lock rollback block as part of rwsig verification
This is done at RO stage. If the rollback region is unprotected, update it to match the version in the RW image. If the rollback region is protected, we can't do that update, so we wait for RW to unlock that region (presumably after AP has verified that image is somewhat functional) before updating it. BRANCH=none BUG=b:35586219 TEST=flashwp true; reboot => hammer reboots twice flashinfo shows RO+rollback protected: Flags: wp_gpio_asserted ro_at_boot ro_now rollback_at_boot rollback_now Protected now: YYYYYYYY YYYYYYYY Y....... ........ TEST=Hack version.c to add "+1" to rollback_version, check that RO updates ROLLBACK info block on first boot. TEST=Use hack above, convert rwsig to separate task, add 5000 ms delay in rwsig just before rollback information is updated. Then: Quickly type: flashwp true; reboot; flashwp all; reboot => Wait for system to jump to RW rollbackinfo => minimum version 0 flashwp norb; reboot; wait for jump to RW rollbackinfo => minimum version 1 Change-Id: I78e502315c611c5edaf34b8d70a12fedd3e57bdf Reviewed-on: https://chromium-review.googlesource.com/452816 Commit-Ready: Nicolas Boichat <drinkcat@chromium.org> Tested-by: Nicolas Boichat <drinkcat@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--common/rollback.c46
-rw-r--r--common/rwsig.c34
-rw-r--r--include/rollback.h7
3 files changed, 79 insertions, 8 deletions
diff --git a/common/rollback.c b/common/rollback.c
index dbeffaa051..c720b6b97b 100644
--- a/common/rollback.c
+++ b/common/rollback.c
@@ -12,6 +12,9 @@
#include "system.h"
#include "util.h"
+/* Console output macros */
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
+
/* Number of rollback regions */
#define ROLLBACK_REGIONS 2
@@ -90,13 +93,41 @@ int32_t rollback_get_minimum_version(void)
return rollback_min_version;
}
+int rollback_lock(void)
+{
+ int ret;
+
+ /* Already locked */
+ if (flash_get_protect() & EC_FLASH_PROTECT_ROLLBACK_NOW)
+ return EC_SUCCESS;
+
+ CPRINTS("Protecting rollback");
+
+ /* This may do nothing if WP is not enabled, or RO is not protected. */
+ ret = flash_set_protect(EC_FLASH_PROTECT_ROLLBACK_AT_BOOT, -1);
+
+ if (!(flash_get_protect() & EC_FLASH_PROTECT_ROLLBACK_NOW) &&
+ flash_get_protect() & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) {
+ /*
+ * If flash protection is still not enabled (some chips may
+ * be able to enable it immediately), reboot.
+ */
+ cflush();
+ system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);
+ }
+
+ return ret;
+}
+
int rollback_update(int32_t next_min_version)
{
struct rollback_data data;
uintptr_t offset;
int region;
int32_t current_min_version;
- int ret;
+
+ if (flash_get_protect() & EC_FLASH_PROTECT_ROLLBACK_NOW)
+ return EC_ERROR_ACCESS_DENIED;
region = get_latest_rollback(&current_min_version);
@@ -119,14 +150,17 @@ int rollback_update(int32_t next_min_version)
data.rollback_min_version = next_min_version;
data.cookie = CROS_EC_ROLLBACK_COOKIE;
+ /* Offset should never be part of active image. */
if (system_unsafe_to_overwrite(offset, CONFIG_FLASH_ERASE_SIZE))
- return EC_ERROR_ACCESS_DENIED;
+ return EC_ERROR_UNKNOWN;
- ret = flash_erase(offset, CONFIG_FLASH_ERASE_SIZE);
- if (ret)
- return ret;
+ if (flash_erase(offset, CONFIG_FLASH_ERASE_SIZE))
+ return EC_ERROR_UNKNOWN;
- return flash_write(offset, sizeof(data), (char *)&data);
+ if (flash_write(offset, sizeof(data), (char *)&data))
+ return EC_ERROR_UNKNOWN;
+
+ return EC_SUCCESS;
}
static int command_rollback_info(int argc, char **argv)
diff --git a/common/rwsig.c b/common/rwsig.c
index f7d9429270..d2218ba77e 100644
--- a/common/rwsig.c
+++ b/common/rwsig.c
@@ -152,13 +152,43 @@ void check_rw_signature(void)
hash = SHA256_final(&ctx);
good = rsa_verify(key, sig, hash, rsa_workbuf);
+ if (!good)
+ goto out;
+
+#ifdef CONFIG_ROLLBACK
+ /*
+ * Signature verified: we know that rw_rollback_version is valid, check
+ * if rollback information should be updated.
+ */
+ if (rw_rollback_version != min_rollback_version) {
+ /*
+ * This will fail if the rollback block is protected (RW image
+ * will unprotect that block later on).
+ */
+ int ret = rollback_update(rw_rollback_version);
+
+ if (ret == 0) {
+ CPRINTS("Rollback updated to %d",
+ rw_rollback_version);
+ } else if (ret != EC_ERROR_ACCESS_DENIED) {
+ CPRINTS("Rollback update error %d", ret);
+ good = 0;
+ }
+ }
+
+ /*
+ * Lock the ROLLBACK region, this will cause the board to reboot if the
+ * region is not already protected.
+ */
+ rollback_lock();
+#endif
out:
+ CPRINTS("RW verify %s", good ? "OK" : "FAILED");
+
if (good) {
- CPRINTS("RW image verified");
/* Jump to the RW firmware */
system_run_image_copy(SYSTEM_IMAGE_RW);
} else {
- CPRINTS("RSA verify FAILED");
pd_log_event(PD_EVENT_ACC_RW_FAIL, 0, 0, NULL);
/* RW firmware is invalid : do not jump there */
if (system_is_locked())
diff --git a/include/rollback.h b/include/rollback.h
index 7221691c1f..d9d79eb67d 100644
--- a/include/rollback.h
+++ b/include/rollback.h
@@ -27,6 +27,13 @@ int rollback_get_minimum_version(void);
*/
int rollback_update(int32_t next_min_version);
+/**
+ * Lock rollback protection block, reboot if necessary.
+ *
+ * @return EC_SUCCESS if rollback was already protected.
+ */
+int rollback_lock(void);
+
#endif
#endif /* __CROS_EC_ROLLBACK_H */