summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 */