summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2017-02-18 21:21:33 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2017-03-02 16:30:16 +0000
commit1210ff1b9c9b288ffe11bf8e123fc795b09a151d (patch)
tree116568064d9822a9452a108352dc3435da7ba942
parent5fbdd1dbd710bb88c25ff9b287a8f3e24ceec516 (diff)
downloadchrome-ec-1.9308_B.0.tar.gz
g: harden upgrade validity checks for prod imagesv1.9308_B.0
Let's not allow downloading older images when in prod mode. When the received chunk is destined into RO or RW header, verify that the chunk's version is not lower than the current running version. Also, if the chunk is not properly aligned with the header, verify that it does not overlap with the header in any way. BRANCH=none BUG=chrome-os-partner:63098 TEST=verified that older images are rejected by prod images, and newer and current level are accepted. Verified that dev images still allow to downgrade. Change-Id: I19c74f1d1bb5469cc935293a5841405149a968f6 Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/448702 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--chip/g/upgrade_fw.c98
-rw-r--r--chip/g/upgrade_fw.h1
2 files changed, 97 insertions, 2 deletions
diff --git a/chip/g/upgrade_fw.c b/chip/g/upgrade_fw.c
index 6d351c5ba0..f36e5cbd7a 100644
--- a/chip/g/upgrade_fw.c
+++ b/chip/g/upgrade_fw.c
@@ -170,6 +170,96 @@ int usb_pdu_valid(struct upgrade_command *cmd_body, size_t cmd_size)
return 1;
}
+#ifndef CR50_DEV
+
+/* Compare two versions, return True if the new version is older. */
+static int new_is_older(const struct SignedHeader *new,
+ const struct SignedHeader *old)
+{
+ if (new->epoch_ != old->epoch_)
+ return new->epoch_ < old->epoch_;
+
+ if (new->major_ != old->major_)
+ return new->major_ < old->major_;
+
+
+ return new->minor_ < old->minor_;
+}
+
+/*
+ * Check if this chunk of data is a rollback attempt, or is unaligned and
+ * overlaps RO or RW header.
+ *
+ * Return False if this is such an attempt or an overlap, when in prod mode;
+ * otherwise return True.
+ */
+static int contents_allowed(uint32_t block_offset,
+ size_t body_size, void *upgrade_data)
+{
+ /* Pointer to RO or RW header in flash, to compare against. */
+ const struct SignedHeader *header;
+
+ if (block_offset == valid_sections.ro_base_offset) {
+ header = (const struct SignedHeader *)
+ get_program_memory_addr(system_get_ro_image_copy());
+ } else if (block_offset == valid_sections.rw_base_offset) {
+ header = (const struct SignedHeader *)
+ get_program_memory_addr(system_get_image_copy());
+ } else {
+
+ /*
+ * The received block is not destined to a header directly,
+ * but does it overlap with a header by any chance?
+ */
+ int i;
+ /* Base offsets of valid headers in flash. */
+ uint32_t bases[] = { valid_sections.ro_base_offset,
+ valid_sections.rw_base_offset };
+ /* Range of offsets this block is covering. */
+ uint32_t range[] = { block_offset, block_offset + body_size };
+
+ for (i = 0; i < ARRAY_SIZE(bases); i++) {
+ int j;
+
+ for (j = 0; j < ARRAY_SIZE(range); j++) {
+ if ((range[j] >= bases[i]) &&
+ (range[j] <
+ (bases[i] +
+ sizeof(struct SignedHeader)))) {
+ CPRINTF("%s:"
+ " unaligned block overlaps\n",
+ __func__);
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+ }
+
+ /* This block is a header (ro or rw) of the new image. */
+ if (body_size < sizeof(struct SignedHeader)) {
+ CPRINTF("%s: block too short\n", __func__);
+ return 0;
+ }
+
+ /* upgrade_data is the new header. */
+ if (new_is_older(upgrade_data, header)) {
+ CPRINTF("%s: rejecting an older header.\n", __func__);
+ return 0;
+ }
+
+ return 1;
+}
+
+#else
+static int contents_allowed(uint32_t block_offset,
+ size_t body_size, void *upgrade_data)
+{
+ return 1;
+}
+#endif
+
void fw_upgrade_command_handler(void *body,
size_t cmd_size,
size_t *response_size)
@@ -253,6 +343,12 @@ void fw_upgrade_command_handler(void *body,
return;
}
+ upgrade_data = cmd_body + 1;
+ if (!contents_allowed(block_offset, body_size, upgrade_data)) {
+ *error_code = UPGRADE_ROLLBACK_ERROR;
+ return;
+ }
+
/* Check if the block will fit into the valid area. */
*error_code = check_update_chunk(block_offset, body_size);
if (*error_code)
@@ -260,7 +356,6 @@ void fw_upgrade_command_handler(void *body,
CPRINTF("%s: programming at address 0x%x\n", __func__,
block_offset + CONFIG_PROGRAM_MEMORY_BASE);
- upgrade_data = cmd_body + 1;
if (flash_physical_write(block_offset, body_size, upgrade_data)
!= EC_SUCCESS) {
*error_code = UPGRADE_WRITE_FAILURE;
@@ -285,4 +380,3 @@ void fw_upgrade_complete(void)
{
system_clear_retry_counter();
}
-
diff --git a/chip/g/upgrade_fw.h b/chip/g/upgrade_fw.h
index f91e684e38..8fe0f0269c 100644
--- a/chip/g/upgrade_fw.h
+++ b/chip/g/upgrade_fw.h
@@ -136,6 +136,7 @@ enum return_value {
UPGRADE_VERIFY_ERROR = 5,
UPGRADE_GEN_ERROR = 6,
UPGRADE_MALLOC_ERROR = 7,
+ UPGRADE_ROLLBACK_ERROR = 8,
};
#endif /* ! __EC_CHIP_G_UPGRADE_FW_H */