diff options
-rw-r--r-- | common/rollback.c | 46 | ||||
-rw-r--r-- | common/rwsig.c | 34 | ||||
-rw-r--r-- | include/rollback.h | 7 |
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(¤t_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 */ |