diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2017-02-20 12:15:52 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2017-03-02 16:48:25 +0000 |
commit | 00d4dd954399a07641bd5b30f070bcc663a128e6 (patch) | |
tree | 0a780de6fe424adb12867def488432bf35f69637 | |
parent | 1210ff1b9c9b288ffe11bf8e123fc795b09a151d (diff) | |
download | chrome-ec-00d4dd954399a07641bd5b30f070bcc663a128e6.tar.gz |
g: rate limit firmware updates
This patch introduces a delay between accepted cr50 firmware upload
attempts. The next attempt to write into the same or lower address in
flash would be accepted no sooner than in 60 seconds after the
previous attempt.
This would prevent a rogue user from wearing the flash by repeated
uploads to the same address.
This limitation is not imposed by dev images (those compiled with
CR50_DEV=1).
BRANCH=none
BUG=chrome-os-partner:63098
TEST=verified that attempts to update soon after the previous update
result in the following error message issued by usb_updater:
sending 0x2d8b8 bytes to 0x4000
Error: status 0x9
Modified usb_updater to send one random pdu twice. Observed the
same error message.
Change-Id: Idca55ad091d09daaddd0a4cad5b1f871af1ede93
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/445496
Reviewed-by: Randall Spangler <rspangler@chromium.org>
(cherry picked from commit 5221d127e157240a1e3b2275190b2686dfafe6e5)
Reviewed-on: https://chromium-review.googlesource.com/448335
-rw-r--r-- | chip/g/upgrade_fw.c | 40 | ||||
-rw-r--r-- | chip/g/upgrade_fw.h | 7 | ||||
-rw-r--r-- | extra/usb_updater/usb_updater.c | 1 |
3 files changed, 47 insertions, 1 deletions
diff --git a/chip/g/upgrade_fw.c b/chip/g/upgrade_fw.c index f36e5cbd7a..182f1308fc 100644 --- a/chip/g/upgrade_fw.c +++ b/chip/g/upgrade_fw.c @@ -252,7 +252,40 @@ static int contents_allowed(uint32_t block_offset, return 1; } + +static uint32_t prev_offset; +static uint64_t prev_timestamp; +#define BACKOFF_TIME (60 * SECOND) + +static int chunk_came_too_soon(uint32_t block_offset) +{ + if (!prev_timestamp || + ((get_time().val - prev_timestamp) > BACKOFF_TIME)) + return 0; + + if (!prev_offset || + (block_offset >= (prev_offset + SIGNED_TRANSFER_SIZE))) + return 0; + + CPRINTF("%s: rejecting a write to the same block\n", __func__); + return 1; +} + +static void new_chunk_written(uint32_t block_offset) +{ + prev_timestamp = get_time().val; + prev_offset = block_offset; +} #else +static int chunk_came_too_soon(uint32_t block_offset) +{ + return 0; +} + +static void new_chunk_written(uint32_t block_offset) +{ +} + static int contents_allowed(uint32_t block_offset, size_t body_size, void *upgrade_data) { @@ -354,6 +387,11 @@ void fw_upgrade_command_handler(void *body, if (*error_code) return; + if (chunk_came_too_soon(block_offset)) { + *error_code = UPGRADE_RATE_LIMIT_ERROR; + return; + } + CPRINTF("%s: programming at address 0x%x\n", __func__, block_offset + CONFIG_PROGRAM_MEMORY_BASE); if (flash_physical_write(block_offset, body_size, upgrade_data) @@ -363,6 +401,8 @@ void fw_upgrade_command_handler(void *body, return; } + new_chunk_written(block_offset); + /* Verify that data was written properly. */ if (memcmp(upgrade_data, (void *) (block_offset + CONFIG_PROGRAM_MEMORY_BASE), diff --git a/chip/g/upgrade_fw.h b/chip/g/upgrade_fw.h index 8fe0f0269c..092f2812fa 100644 --- a/chip/g/upgrade_fw.h +++ b/chip/g/upgrade_fw.h @@ -137,6 +137,13 @@ enum return_value { UPGRADE_GEN_ERROR = 6, UPGRADE_MALLOC_ERROR = 7, UPGRADE_ROLLBACK_ERROR = 8, + UPGRADE_RATE_LIMIT_ERROR = 9, }; +/* + * This is the size of the update frame payload, unless this is the last chunk + * of the image. + */ +#define SIGNED_TRANSFER_SIZE 1024 + #endif /* ! __EC_CHIP_G_UPGRADE_FW_H */ diff --git a/extra/usb_updater/usb_updater.c b/extra/usb_updater/usb_updater.c index e41c3027b1..50d7cfaf3c 100644 --- a/extra/usb_updater/usb_updater.c +++ b/extra/usb_updater/usb_updater.c @@ -179,7 +179,6 @@ struct upgrade_pkt { char data[0]; } __packed; -#define SIGNED_TRANSFER_SIZE 1024 #define MAX_BUF_SIZE (SIGNED_TRANSFER_SIZE + sizeof(struct upgrade_pkt)) struct usb_endpoint { |