summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-05-25 14:57:09 -0700
committerRandall Spangler <rspangler@chromium.org>2012-05-25 15:03:47 -0700
commit7ecd1d6d3c23b6acb13f90062d062647ddb4fed3 (patch)
tree796393a5afc4290d974f4ab391a0003c72c3056e
parente704c712ad473160e97717f139ab3929bcd249c1 (diff)
downloadchrome-ec-7ecd1d6d3c23b6acb13f90062d062647ddb4fed3.tar.gz
Add system_is_locked() to prevent sysjump on consumer systems
This returns true when both HW and SW write protect are enabled. Once WP is enabled, sysjump will be locked out. system_is_locked() can be used to gate other dangerous-ish commands too. Signed-off-by: Randall Spangler <rspangler@chromium.org> BUG=chrome-os-partner:7468 TEST=manual sysinfo -> unlocked, copy A sysjump B -> works flashwp lock reboot (make sure flashinfo shows WP asserted and flash locked; note there is a HW bug on proto1 which makes this flaky) sysinfo -> locked, copy A sysjump B -> fails (remove WP screw) reboot hard flashwp unlock Change-Id: I849b573675c2c1cb4c44b9a05d6973e38247ca23
-rw-r--r--board/bds/board.h1
-rw-r--r--board/daisy/board.h7
-rw-r--r--board/snow/board.h7
-rw-r--r--common/main.c5
-rw-r--r--common/system_common.c103
-rw-r--r--include/common.h11
-rw-r--r--include/system.h46
7 files changed, 123 insertions, 57 deletions
diff --git a/board/bds/board.h b/board/bds/board.h
index f22b1e8603..f9d1ef7751 100644
--- a/board/bds/board.h
+++ b/board/bds/board.h
@@ -10,6 +10,7 @@
/* Optional features */
#define CONFIG_CONSOLE_CMDHELP
+#define CONFIG_SYSTEM_UNLOCKED /* Allow dangerous commands */
enum adc_channel
{
diff --git a/board/daisy/board.h b/board/daisy/board.h
index 625df877b5..14270d8906 100644
--- a/board/daisy/board.h
+++ b/board/daisy/board.h
@@ -17,6 +17,13 @@
/* use I2C for host communication */
#define CONFIG_I2C
+/* Allow dangerous commands all the time, since we don't have a write protect
+ * switch. */
+/* TODO: (crosbug.com/p/9986) This is a serious security hole and should be
+ * removed in mass production. We add this to allow manual firmware update.
+ * Once we complete the vboot and autoupdate, we should remove this. */
+#define CONFIG_SYSTEM_UNLOCKED
+
/* By default, enable all console messages except keyboard */
#define CC_DEFAULT (CC_ALL & ~CC_MASK(CC_KEYSCAN))
diff --git a/board/snow/board.h b/board/snow/board.h
index dac98a22ed..0c6d301b9d 100644
--- a/board/snow/board.h
+++ b/board/snow/board.h
@@ -17,6 +17,13 @@
/* use I2C for host communication */
#define CONFIG_I2C
+/* Allow dangerous commands all the time, since we don't have a write protect
+ * switch. */
+/* TODO: (crosbug.com/p/9986) This is a serious security hole and should be
+ * removed in mass production. We add this to allow manual firmware update.
+ * Once we complete the vboot and autoupdate, we should remove this. */
+#define CONFIG_SYSTEM_UNLOCKED
+
/* By default, enable all console messages except keyboard */
#define CC_DEFAULT (CC_ALL & ~CC_MASK(CC_KEYSCAN))
diff --git a/common/main.c b/common/main.c
index 6b4dfb704c..74a698460e 100644
--- a/common/main.c
+++ b/common/main.c
@@ -110,6 +110,11 @@ int main(void)
* Note that steps above here may be done TWICE per boot, once in the
* RO image and once in the RW image. */
vboot_init();
+
+ /* If system is locked, disable system jumps now that vboot has had its
+ * chance to jump to a RW image. */
+ if (system_is_locked())
+ system_disable_jump();
#endif
/* Initialize other driver modules. These can occur in any order.
diff --git a/common/system_common.c b/common/system_common.c
index 9d93cdef25..c654143695 100644
--- a/common/system_common.c
+++ b/common/system_common.c
@@ -5,8 +5,10 @@
/* System module for Chrome EC : common functions */
+#include "board.h"
#include "clock.h"
#include "console.h"
+#include "flash.h"
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
@@ -62,6 +64,30 @@ static struct jump_data * const jdata =
static const char * const image_names[] = {"unknown", "RO", "A", "B"};
static enum system_reset_cause_t reset_cause = SYSTEM_RESET_UNKNOWN;
static int jumped_to_image;
+static int disable_jump;
+
+
+int system_is_locked(void)
+{
+#ifdef CONFIG_SYSTEM_UNLOCKED
+ /* System is explicitly unlocked */
+ return 0;
+
+#elif defined(BOARD_link) && defined(CONFIG_FLASH)
+ /* On link, unlocked if write protect pin deasserted or flash protect
+ * lock not applied. */
+ int lock = flash_get_protect_lock();
+ if (!(lock & FLASH_PROTECT_PIN_ASSERTED) ||
+ !(lock & FLASH_PROTECT_LOCK_APPLIED))
+ return 0;
+
+ /* If WP pin is asserted and lock is applied, we're locked */
+ return 1;
+#else
+ /* Other configs are locked by default */
+ return 1;
+#endif
+}
int system_usable_ram_end(void)
@@ -151,6 +177,12 @@ void system_set_reset_cause(enum system_reset_cause_t cause)
}
+void system_disable_jump(void)
+{
+ disable_jump = 1;
+}
+
+
const char *system_get_reset_cause_string(void)
{
static const char * const cause_descs[] = {
@@ -293,13 +325,26 @@ int system_run_image_copy(enum system_image_copy_t copy,
uint32_t base;
uint32_t init_addr;
- /* TODO: sanity checks (crosbug.com/p/7468)
- *
- * For this to be allowed either WP must be disabled, or ALL of the
- * following must be true:
- * - We must currently be running the RO image.
- * - We must still be in init (that is, before task_start().
- * - The target image must be A or B. */
+ if (system_is_locked()) {
+ /* System is locked, so disallow jumping between images unless
+ * this is the initial jump from RO to RW code. */
+
+ /* Must currently be running the RO image */
+ if (system_get_image_copy() != SYSTEM_IMAGE_RO)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* Target image must be RW image */
+ if (copy != SYSTEM_IMAGE_RW_A && copy != SYSTEM_IMAGE_RW_B)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* Can't have already jumped between images */
+ if (jumped_to_image)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* Jumping must still be enabled */
+ if (disable_jump)
+ return EC_ERROR_ACCESS_DENIED;
+ }
/* Load the appropriate reset vector */
base = get_base(copy);
@@ -316,7 +361,7 @@ int system_run_image_copy(enum system_image_copy_t copy,
jump_to_image(init_addr, recovery_required);
/* Should never get here */
- return EC_ERROR_UNIMPLEMENTED;
+ return EC_ERROR_UNKNOWN;
}
@@ -451,8 +496,9 @@ static int command_sysinfo(int argc, char **argv)
ccprintf("Last reset: %d (%s)\n",
system_get_reset_cause(),
system_get_reset_cause_string());
- ccprintf("Copy: %s\n", system_get_image_copy_string());
- ccprintf("Jump: %s\n", system_jumped_to_this_image() ? "yes" : "no");
+ ccprintf("Copy: %s\n", system_get_image_copy_string());
+ ccprintf("Jumped: %s\n", system_jumped_to_this_image() ? "yes" : "no");
+ ccprintf("Locked: %s\n", system_is_locked() ? "yes" : "no");
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(sysinfo, command_sysinfo,
@@ -530,8 +576,9 @@ static int command_sysjump(int argc, char **argv)
uint32_t addr;
char *e;
- /* TODO: (crosbug.com/p/7468) For this command to be allowed, WP must
- * be disabled. */
+ /* Command is only allowed on an unlocked system */
+ if (system_is_locked())
+ return EC_ERROR_ACCESS_DENIED;
if (argc < 2)
return EC_ERROR_PARAM_COUNT;
@@ -659,26 +706,16 @@ int host_command_get_board_version(uint8_t *data, int *resp_size)
DECLARE_HOST_COMMAND(EC_CMD_GET_BOARD_VERSION, host_command_get_board_version);
-#ifdef CONFIG_REBOOT_EC
-static void clean_busy_bits(void) {
-#ifdef CONFIG_LPC
- host_send_result(0, EC_RES_SUCCESS);
- host_send_result(1, EC_RES_SUCCESS);
-#endif
-}
-
int host_command_reboot(uint8_t *data, int *resp_size)
{
enum system_image_copy_t copy;
+ struct ec_params_reboot_ec *p = (struct ec_params_reboot_ec *)data;
+ int recovery_request = p->reboot_flags & EC_CMD_REBOOT_BIT_RECOVERY;
- struct ec_params_reboot_ec *p =
- (struct ec_params_reboot_ec *)data;
-
- int recovery_request = p->reboot_flags &
- EC_CMD_REBOOT_BIT_RECOVERY;
-
- /* TODO: (crosbug.com/p/7468) For this command to be allowed, WP must
- * be disabled. */
+ /* This command is only allowed on unlocked systems, because jumping
+ * directly to another image bypasses verified boot. */
+ if (system_is_locked())
+ return EC_RES_ACCESS_DENIED;
switch (p->target) {
case EC_IMAGE_RO:
@@ -694,8 +731,13 @@ int host_command_reboot(uint8_t *data, int *resp_size)
return EC_RES_ERROR;
}
- clean_busy_bits();
- CPUTS("Executing host reboot command\n");
+#ifdef CONFIG_LPC
+ /* Clean busy bits on host */
+ host_send_result(0, EC_RES_SUCCESS);
+ host_send_result(1, EC_RES_SUCCESS);
+#endif
+
+ CPUTS("[Executing host reboot command]\n");
system_run_image_copy(copy, recovery_request);
/* We normally never get down here, because we'll have jumped to
@@ -707,4 +749,3 @@ int host_command_reboot(uint8_t *data, int *resp_size)
return EC_RES_ERROR;
}
DECLARE_HOST_COMMAND(EC_CMD_REBOOT_EC, host_command_reboot);
-#endif /* CONFIG_REBOOT_EC */
diff --git a/include/common.h b/include/common.h
index 91a1a126a1..2eb2157247 100644
--- a/include/common.h
+++ b/include/common.h
@@ -10,15 +10,6 @@
#include <stdint.h>
-
-/* TODO: This is a serious security hole and should be removed in mass
- * production. We add this to allow manual firmware update.
- * Once we complete the vboot and autoupdate, we should remove this.
- * https://code.google.com/p/chrome-os-partner/issues/detail?id=8391
- */
-#define CONFIG_REBOOT_EC
-
-
/* List of common error codes that can be returned */
enum ec_error_list {
/* Success - no error */
@@ -35,6 +26,8 @@ enum ec_error_list {
EC_ERROR_INVAL = 5,
/* Already in use */
EC_ERROR_BUSY = 6,
+ /* Access denied */
+ EC_ERROR_ACCESS_DENIED = 7,
/* Invalid console command param (PARAMn means parameter n is bad) */
EC_ERROR_PARAM1 = 11,
EC_ERROR_PARAM2 = 12,
diff --git a/include/system.h b/include/system.h
index 33297dbc3f..fb9c802b8f 100644
--- a/include/system.h
+++ b/include/system.h
@@ -45,19 +45,31 @@ int system_common_pre_init(void);
* the cause is not known. */
enum system_reset_cause_t system_get_reset_cause(void);
-/* returns a Boolean indicating if BIOS should come up in recovery mode */
+/* Return a Boolean indicating if BIOS should come up in recovery mode */
int system_get_recovery_required(void);
/* Record the cause of the last reset. */
void system_set_reset_cause(enum system_reset_cause_t cause);
-/* Returns a text description of the last reset cause. */
+/* Return a text description of the last reset cause. */
const char *system_get_reset_cause_string(void);
-/* Returns the image copy which is currently running. */
+/* Return non-zero if the system is locked down for normal consumer use.
+ * Potentially-dangerous developer and/or factory commands must be disabled
+ * unless this command returns 0.
+ *
+ * This should be controlled by the same mechanism which write-protects the
+ * read-only image (so that the only way to unlock the system is to unprotect
+ * the read-only image). */
+int system_is_locked(void);
+
+/* Disable jumping between images for the rest of this boot. */
+void system_disable_jump(void);
+
+/* Return the image copy which is currently running. */
enum system_image_copy_t system_get_image_copy(void);
-/* Returns non-zero if the system has switched between image copies at least
+/* Return non-zero if the system has switched between image copies at least
* once since the last real boot. */
int system_jumped_to_this_image(void);
@@ -75,20 +87,20 @@ int system_add_jump_tag(uint16_t tag, int version, int size, const void *data);
* NULL if no matching tag is found. */
const uint8_t *system_get_jump_tag(uint16_t tag, int *version, int *size);
-/* Returns the address just past the last usable byte in RAM. */
+/* Return the address just past the last usable byte in RAM. */
int system_usable_ram_end(void);
/* Returns true if the given range is overlapped with the active image. */
int system_unsafe_to_overwrite(uint32_t offset, uint32_t size);
-/* Returns a text description of the image copy which is currently running. */
+/* Return a text description of the image copy which is currently running. */
const char *system_get_image_copy_string(void);
-/* Jumps to the specified image copy. */
+/* Jump to the specified image copy. */
int system_run_image_copy(enum system_image_copy_t copy,
int recovery_request);
-/* Returns the version string for an image copy, or an empty string if
+/* Return the version string for an image copy, or an empty string if
* error. If copy==SYSTEM_IMAGE_UNKNOWN, returns the version for the
* currently-running image. */
const char *system_get_version(enum system_image_copy_t copy);
@@ -97,25 +109,24 @@ const char *system_get_version(enum system_image_copy_t copy);
* board-dependent; see enum board_version in board.h for known versions. */
int system_get_board_version(void);
-/* Returns information about the build including the version
- * the build date and user/machine.
- */
+/* Return information about the build including the version, build date and
+ * user/machine which performed the build. */
const char *system_get_build_info(void);
-/* Resets the system. If is_hard, performs a hard reset, which cuts power to
+/* Reset the system. If is_hard, performs a hard reset, which cuts power to
* the entire system; else performs a soft reset (which resets the core and
* on-chip peripherals, without actually cutting power to the chip). */
void system_reset(int is_hard);
-/* Sets a scratchpad register to the specified value. The scratchpad
+/* Set a scratchpad register to the specified value. The scratchpad
* register must maintain its contents across a software-requested
* warm reset. */
int system_set_scratchpad(uint32_t value);
-/* Returns the current scratchpad register value. */
+/* Return the current scratchpad register value. */
uint32_t system_get_scratchpad(void);
-/* Returns the chip info */
+/* Return the chip info */
const char *system_get_chip_vendor(void);
const char *system_get_chip_name(void);
const char *system_get_chip_revision(void);
@@ -123,10 +134,11 @@ const char *system_get_chip_revision(void);
/* TODO: request sleep. How do we want to handle transitioning
* to/from low-power states? */
-/* put the system in hibernation for the specified duration */
+/* Put the EC in hibernate (lowest EC power state) for the specified
+ * duration. Note that this is NOT the same as chipset S4/hibernate. */
void system_hibernate(uint32_t seconds, uint32_t microseconds);
-/* minimum duration to get proper hibernation */
+/* Minimum duration to get proper hibernation */
#define SYSTEM_HIB_MINIMUM_DURATION 0, 1000
#endif /* __CROS_EC_SYSTEM_H */