summaryrefslogtreecommitdiff
path: root/common/rollback.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /common/rollback.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14438.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'common/rollback.c')
-rw-r--r--common/rollback.c520
1 files changed, 0 insertions, 520 deletions
diff --git a/common/rollback.c b/common/rollback.c
deleted file mode 100644
index 984058c49a..0000000000
--- a/common/rollback.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/* Copyright 2017 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/* Rollback protection logic. */
-
-#include "common.h"
-#include "console.h"
-#ifdef CONFIG_LIBCRYPTOC
-#include "cryptoc/util.h"
-#endif
-#include "flash.h"
-#include "hooks.h"
-#include "host_command.h"
-#ifdef CONFIG_MPU
-#include "mpu.h"
-#endif
-#include "rollback.h"
-#include "rollback_private.h"
-#include "sha256.h"
-#include "system.h"
-#include "task.h"
-#include "trng.h"
-#include "util.h"
-
-/* Console output macros */
-#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
-
-/* Number of rollback regions */
-#define ROLLBACK_REGIONS 2
-
-static int get_rollback_offset(int region)
-{
-#ifdef CONFIG_FLASH_MULTIPLE_REGION
- int rv;
- int rollback_start_bank = crec_flash_bank_index(CONFIG_ROLLBACK_OFF);
-
- rv = crec_flash_bank_start_offset(rollback_start_bank + region);
- ASSERT(rv >= 0);
- return rv;
-#else
- return CONFIG_ROLLBACK_OFF + region * CONFIG_FLASH_ERASE_SIZE;
-#endif
-}
-
-#ifdef SECTION_IS_RO
-static int get_rollback_erase_size_bytes(int region)
-{
- int erase_size;
-
-#ifndef CONFIG_FLASH_MULTIPLE_REGION
- erase_size = CONFIG_FLASH_ERASE_SIZE;
-#else
- int rollback_start_bank = crec_flash_bank_index(CONFIG_ROLLBACK_OFF);
-
- erase_size = crec_flash_bank_erase_size(rollback_start_bank + region);
-#endif
- ASSERT(erase_size > 0);
- ASSERT(ROLLBACK_REGIONS * erase_size <= CONFIG_ROLLBACK_SIZE);
- ASSERT(sizeof(struct rollback_data) <= erase_size);
- return erase_size;
-}
-#endif
-
-/*
- * When MPU is available, read rollback with interrupts disabled, to minimize
- * time protection is left open.
- */
-static void lock_rollback(void)
-{
-#ifdef CONFIG_ROLLBACK_MPU_PROTECT
- mpu_lock_rollback(1);
- interrupt_enable();
-#endif
-}
-
-static void unlock_rollback(void)
-{
-#ifdef CONFIG_ROLLBACK_MPU_PROTECT
- interrupt_disable();
- mpu_lock_rollback(0);
-#endif
-}
-
-static void clear_rollback(struct rollback_data *data)
-{
-#ifdef CONFIG_ROLLBACK_SECRET_SIZE
- always_memset(data->secret, 0, sizeof(data->secret));
-#endif
-}
-
-int read_rollback(int region, struct rollback_data *data)
-{
- int offset;
- int ret = EC_SUCCESS;
-
- offset = get_rollback_offset(region);
-
- unlock_rollback();
- if (crec_flash_read(offset, sizeof(*data), (char *)data))
- ret = EC_ERROR_UNKNOWN;
- lock_rollback();
-
- return ret;
-}
-
-/*
- * Get the most recent rollback information.
- *
- * @data: Returns most recent rollback data block. The data is filled
- * with zeros if no valid rollback block is present
- *
- * Return most recent region index on success (>= 0, or 0 if no rollback
- * region is valid), negative value on error.
- */
-static int get_latest_rollback(struct rollback_data *data)
-{
- int ret = -1;
- int region;
- int min_region = -1;
- int max_id = -1;
- struct rollback_data tmp_data;
-
- for (region = 0; region < ROLLBACK_REGIONS; region++) {
- if (read_rollback(region, &tmp_data))
- goto failed;
-
- /* Check if not initialized or invalid cookie. */
- if (tmp_data.cookie != CROS_EC_ROLLBACK_COOKIE)
- continue;
-
- if (tmp_data.id > max_id) {
- min_region = region;
- max_id = tmp_data.id;
- }
- }
-
- if (min_region >= 0) {
- if (read_rollback(min_region, data))
- goto failed;
- } else {
- min_region = 0;
- clear_rollback(data);
- }
- ret = min_region;
-
-failed:
- clear_rollback(&tmp_data);
- return ret;
-}
-
-int32_t rollback_get_minimum_version(void)
-{
- struct rollback_data data;
- int32_t ret = -1;
-
- if (get_latest_rollback(&data) < 0)
- goto failed;
- ret = data.rollback_min_version;
-
-failed:
- clear_rollback(&data);
- return ret;
-}
-
-#ifdef CONFIG_ROLLBACK_SECRET_SIZE
-test_mockable int rollback_get_secret(uint8_t *secret)
-{
- int ret = EC_ERROR_UNKNOWN;
- struct rollback_data data;
-
- if (get_latest_rollback(&data) < 0)
- goto failed;
-
- /* Check that secret is not full of 0x00 or 0xff */
- if (bytes_are_trivial(data.secret, sizeof(data.secret)))
- goto failed;
-
- memcpy(secret, data.secret, sizeof(data.secret));
- ret = EC_SUCCESS;
-failed:
- clear_rollback(&data);
- return ret;
-}
-#endif
-
-#ifdef CONFIG_ROLLBACK_UPDATE
-
-#ifdef CONFIG_ROLLBACK_SECRET_SIZE
-static int add_entropy(uint8_t *dst, const uint8_t *src,
- const uint8_t *add, unsigned int add_len)
-{
- int ret = 0;
-#ifdef CONFIG_SHA256
-BUILD_ASSERT(SHA256_DIGEST_SIZE == CONFIG_ROLLBACK_SECRET_SIZE);
- struct sha256_ctx ctx;
- uint8_t *hash;
-#ifdef CONFIG_ROLLBACK_SECRET_LOCAL_ENTROPY_SIZE
- uint8_t extra;
- int i;
-#endif
-
- SHA256_init(&ctx);
- SHA256_update(&ctx, src, CONFIG_ROLLBACK_SECRET_SIZE);
- SHA256_update(&ctx, add, add_len);
-#ifdef CONFIG_ROLLBACK_SECRET_LOCAL_ENTROPY_SIZE
- /* Add some locally produced entropy */
- for (i = 0; i < CONFIG_ROLLBACK_SECRET_LOCAL_ENTROPY_SIZE; i++) {
- if (!board_get_entropy(&extra, 1))
- goto failed;
- SHA256_update(&ctx, &extra, 1);
- }
-#endif
- hash = SHA256_final(&ctx);
-
- memcpy(dst, hash, CONFIG_ROLLBACK_SECRET_SIZE);
- ret = 1;
-
-#ifdef CONFIG_ROLLBACK_SECRET_LOCAL_ENTROPY_SIZE
-failed:
-#endif
- always_memset(&ctx, 0, sizeof(ctx));
-#else
-#error "Adding entropy to secret in rollback region requires SHA256."
-#endif
- return ret;
-}
-#endif /* CONFIG_ROLLBACK_SECRET_SIZE */
-
-/**
- * Update rollback block.
- *
- * @param next_min_version Minimum version to update in rollback block. Can
- * be a negative value if entropy is provided (in
- * that case the current minimum version is kept).
- * @param entropy Entropy to be added to rollback block secret
- * (can be NULL, in that case no entropy is added).
- * @param len entropy length
- *
- * @return EC_SUCCESS on success, EC_ERROR_* on error.
- */
-static int rollback_update(int32_t next_min_version,
- const uint8_t *entropy, unsigned int length)
-{
- /*
- * When doing flash_write operation, the data needs to be in blocks
- * of CONFIG_FLASH_WRITE_SIZE, pad rollback_data as required.
- */
- uint8_t block[CONFIG_FLASH_WRITE_SIZE *
- DIV_ROUND_UP(sizeof(struct rollback_data),
- CONFIG_FLASH_WRITE_SIZE)];
- struct rollback_data *data = (struct rollback_data *)block;
- BUILD_ASSERT(sizeof(block) >= sizeof(*data));
- int erase_size, offset, region, ret;
-
- if (crec_flash_get_protect() & EC_FLASH_PROTECT_ROLLBACK_NOW) {
- ret = EC_ERROR_ACCESS_DENIED;
- goto out;
- }
-
- /* Initialize the rest of the block. */
- memset(&block[sizeof(*data)], 0xff, sizeof(block)-sizeof(*data));
-
- region = get_latest_rollback(data);
-
- if (region < 0) {
- ret = EC_ERROR_UNKNOWN;
- goto out;
- }
-
-#ifdef CONFIG_ROLLBACK_SECRET_SIZE
- if (entropy) {
- /* Do not accept to decrease the value. */
- if (next_min_version < data->rollback_min_version)
- next_min_version = data->rollback_min_version;
- } else
-#endif
- {
- /* Do not accept to decrease the value. */
- if (next_min_version < data->rollback_min_version) {
- ret = EC_ERROR_INVAL;
- goto out;
- }
-
- /* No need to update if version is already correct. */
- if (next_min_version == data->rollback_min_version) {
- ret = EC_SUCCESS;
- goto out;
- }
- }
-
- /* Use the other region. */
- region = (region + 1) % ROLLBACK_REGIONS;
-
- offset = get_rollback_offset(region);
-
- data->id = data->id + 1;
- data->rollback_min_version = next_min_version;
-#ifdef CONFIG_ROLLBACK_SECRET_SIZE
- /*
- * If we are provided with some entropy, add it to secret. Otherwise,
- * data.secret is left untouched and written back to the other region.
- */
- if (entropy) {
- if (!add_entropy(data->secret, data->secret, entropy, length)) {
- ret = EC_ERROR_UNCHANGED;
- goto out;
- }
- }
-#endif
- data->cookie = CROS_EC_ROLLBACK_COOKIE;
-
- erase_size = get_rollback_erase_size_bytes(region);
-
- if (erase_size < 0) {
- ret = EC_ERROR_UNKNOWN;
- goto out;
- }
-
- /* Offset should never be part of active image. */
- if (system_unsafe_to_overwrite(offset, erase_size)) {
- ret = EC_ERROR_UNKNOWN;
- goto out;
- }
-
- unlock_rollback();
- if (crec_flash_erase(offset, erase_size)) {
- ret = EC_ERROR_UNKNOWN;
- lock_rollback();
- goto out;
- }
-
- ret = crec_flash_write(offset, sizeof(block), block);
- lock_rollback();
-
-out:
- clear_rollback(data);
- return ret;
-}
-
-int rollback_update_version(int32_t next_min_version)
-{
- return rollback_update(next_min_version, NULL, 0);
-}
-
-int rollback_add_entropy(const uint8_t *data, unsigned int len)
-{
- return rollback_update(-1, data, len);
-}
-
-static int command_rollback_update(int argc, char **argv)
-{
- int32_t min_version;
- char *e;
-
- if (argc < 2)
- return EC_ERROR_PARAM_COUNT;
-
- min_version = strtoi(argv[1], &e, 0);
-
- if (*e || min_version < 0)
- return EC_ERROR_PARAM1;
-
- return rollback_update_version(min_version);
-}
-DECLARE_CONSOLE_COMMAND(rollbackupdate, command_rollback_update,
- "min_version",
- "Update rollback info");
-
-#ifdef CONFIG_ROLLBACK_SECRET_SIZE
-static int command_rollback_add_entropy(int argc, char **argv)
-{
- int len;
-
- if (argc < 2)
- return EC_ERROR_PARAM_COUNT;
-
- len = strlen(argv[1]);
-
- return rollback_add_entropy(argv[1], len);
-}
-DECLARE_CONSOLE_COMMAND(rollbackaddent, command_rollback_add_entropy,
- "data",
- "Add entropy to rollback block");
-
-#ifdef CONFIG_RNG
-static int add_entropy_action;
-static int add_entropy_rv = EC_RES_UNAVAILABLE;
-
-static void add_entropy_deferred(void)
-{
- uint8_t rand[CONFIG_ROLLBACK_SECRET_SIZE];
- int repeat = 1;
-
- /*
- * If asked to reset the old secret, just add entropy multiple times,
- * which will ping-pong between the blocks.
- */
- if (add_entropy_action == ADD_ENTROPY_RESET_ASYNC)
- repeat = ROLLBACK_REGIONS;
-
- init_trng();
- do {
- rand_bytes(rand, sizeof(rand));
- if (rollback_add_entropy(rand, sizeof(rand)) != EC_SUCCESS) {
- add_entropy_rv = EC_RES_ERROR;
- goto out;
- }
- } while (--repeat);
-
- add_entropy_rv = EC_RES_SUCCESS;
-out:
- exit_trng();
-}
-DECLARE_DEFERRED(add_entropy_deferred);
-
-static enum ec_status
-hc_rollback_add_entropy(struct host_cmd_handler_args *args)
-{
- const struct ec_params_rollback_add_entropy *p = args->params;
-
- switch (p->action) {
- case ADD_ENTROPY_ASYNC:
- case ADD_ENTROPY_RESET_ASYNC:
- if (add_entropy_rv == EC_RES_BUSY)
- return EC_RES_BUSY;
-
- add_entropy_action = p->action;
- add_entropy_rv = EC_RES_BUSY;
- hook_call_deferred(&add_entropy_deferred_data, 0);
-
- return EC_RES_SUCCESS;
-
- case ADD_ENTROPY_GET_RESULT:
- return add_entropy_rv;
- }
-
- return EC_RES_INVALID_PARAM;
-}
-DECLARE_HOST_COMMAND(EC_CMD_ADD_ENTROPY,
- hc_rollback_add_entropy,
- EC_VER_MASK(0));
-#endif /* CONFIG_RNG */
-#endif /* CONFIG_ROLLBACK_SECRET_SIZE */
-#endif /* CONFIG_ROLLBACK_UPDATE */
-
-static int command_rollback_info(int argc, char **argv)
-{
- int ret = EC_ERROR_UNKNOWN;
- int region, min_region;
- int32_t rw_rollback_version;
- struct rollback_data data;
-
- min_region = get_latest_rollback(&data);
-
- if (min_region < 0)
- goto failed;
-
- rw_rollback_version = system_get_rollback_version(EC_IMAGE_RW);
-
- ccprintf("rollback minimum version: %d\n", data.rollback_min_version);
- ccprintf("RW rollback version: %d\n", rw_rollback_version);
-
- for (region = 0; region < ROLLBACK_REGIONS; region++) {
- ret = read_rollback(region, &data);
- if (ret)
- goto failed;
-
- ccprintf("rollback %d: %08x %08x %08x",
- region, data.id, data.rollback_min_version,
- data.cookie);
-#ifdef CONFIG_ROLLBACK_SECRET_SIZE
- if (!system_is_locked()) {
- /* If system is unlocked, show some of the secret. */
- ccprintf(" [%02x..%02x]", data.secret[0],
- data.secret[CONFIG_ROLLBACK_SECRET_SIZE-1]);
- }
-#endif
- if (min_region == region)
- ccprintf(" *");
- ccprintf("\n");
- }
- ret = EC_SUCCESS;
-
-failed:
- clear_rollback(&data);
- return ret;
-}
-DECLARE_SAFE_CONSOLE_COMMAND(rollbackinfo, command_rollback_info,
- NULL,
- "Print rollback info");
-
-static enum ec_status
-host_command_rollback_info(struct host_cmd_handler_args *args)
-{
- int ret = EC_RES_UNAVAILABLE;
- struct ec_response_rollback_info *r = args->response;
- int min_region;
- struct rollback_data data;
-
- min_region = get_latest_rollback(&data);
-
- if (min_region < 0)
- goto failed;
-
- r->id = data.id;
- r->rollback_min_version = data.rollback_min_version;
- r->rw_rollback_version = system_get_rollback_version(EC_IMAGE_RW);
-
- args->response_size = sizeof(*r);
- ret = EC_RES_SUCCESS;
-
-failed:
- clear_rollback(&data);
- return ret;
-}
-DECLARE_HOST_COMMAND(EC_CMD_ROLLBACK_INFO,
- host_command_rollback_info,
- EC_VER_MASK(0));