From 1967a764e071748706ceb430f5317e527651e2dc Mon Sep 17 00:00:00 2001 From: Tim Crawford Date: Mon, 20 Nov 2023 07:24:17 -0700 Subject: [PATCH] ec/system76: Support lockdown based on EC security state Change-Id: I202c0607c2cdac1df59f42fb41735704dd5bd95c Signed-off-by: Jeremy Soller Signed-off-by: Tim Crawford --- src/ec/system76/ec/Kconfig | 5 +++ src/ec/system76/ec/Makefile.mk | 1 + src/ec/system76/ec/lockdown.c | 59 ++++++++++++++++++++++++++++++++ src/ec/system76/ec/system76_ec.c | 9 +++++ src/ec/system76/ec/system76_ec.h | 11 ++++++ 5 files changed, 85 insertions(+) create mode 100644 src/ec/system76/ec/lockdown.c diff --git a/src/ec/system76/ec/Kconfig b/src/ec/system76/ec/Kconfig index 4b7191241b..213b6f20a1 100644 --- a/src/ec/system76/ec/Kconfig +++ b/src/ec/system76/ec/Kconfig @@ -15,6 +15,11 @@ config EC_SYSTEM76_EC_DGPU bool default n +config EC_SYSTEM76_EC_LOCKDOWN + depends on EC_SYSTEM76_EC + bool + default n + config EC_SYSTEM76_EC_OLED depends on EC_SYSTEM76_EC bool diff --git a/src/ec/system76/ec/Makefile.mk b/src/ec/system76/ec/Makefile.mk index 9808e297d6..02fcda537c 100644 --- a/src/ec/system76/ec/Makefile.mk +++ b/src/ec/system76/ec/Makefile.mk @@ -4,6 +4,7 @@ ifeq ($(CONFIG_EC_SYSTEM76_EC),y) all-y += system76_ec.c ramstage-y += smbios.c +ramstage-$(CONFIG_EC_SYSTEM76_EC_LOCKDOWN) += lockdown.c smm-$(CONFIG_DEBUG_SMI) += system76_ec.c diff --git a/src/ec/system76/ec/lockdown.c b/src/ec/system76/ec/lockdown.c new file mode 100644 index 0000000000..d6f52f4102 --- /dev/null +++ b/src/ec/system76/ec/lockdown.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include "system76_ec.h" +#include +#include +#include +#include + +static int protect_region_by_name(const char *name) +{ + int res; + struct region region; + + res = fmap_locate_area(name, ®ion); + if (res < 0) { + printk(BIOS_ERR, "fmap_locate_area '%s' failed: %d\n", name, res); + return res; + } + + res = spi_flash_ctrlr_protect_region( + boot_device_spi_flash(), + ®ion, + WRITE_PROTECT + ); + if (res < 0) { + printk(BIOS_ERR, "spi_flash_ctrlr_protect_region '%s' failed: %d\n", name, res); + return res; + } + + printk(BIOS_INFO, "protected '%s'\n", name); + return 0; +} + +static void lock(void *unused) +{ + uint8_t state = SYSTEM76_EC_SECURITY_STATE_UNLOCK; + if (!system76_ec_security_get(&state)) { + printk(BIOS_INFO, "failed to get security state, assuming unlocked\n"); + state = SYSTEM76_EC_SECURITY_STATE_UNLOCK; + } + + printk(BIOS_INFO, "security state: %d\n", state); + if (state != SYSTEM76_EC_SECURITY_STATE_UNLOCK) { + // Protect WP_RO region, which should contain FMAP and COREBOOT + protect_region_by_name("WP_RO"); + // Protect RW_MRC_CACHE region, this must be done after it is written + protect_region_by_name("RW_MRC_CACHE"); + //TODO: protect entire flash except when in SMM? + } +} + +/* + * Keep in sync with mrc_cache.c + */ +#if CONFIG(MRC_WRITE_NV_LATE) +BOOT_STATE_INIT_ENTRY(BS_OS_RESUME_CHECK, BS_ON_EXIT, lock, NULL); +#else +BOOT_STATE_INIT_ENTRY(BS_DEV_RESOURCES, BS_ON_ENTRY, lock, NULL); +#endif diff --git a/src/ec/system76/ec/system76_ec.c b/src/ec/system76/ec/system76_ec.c index 828376d0e5..ee41b1e8d7 100644 --- a/src/ec/system76/ec/system76_ec.c +++ b/src/ec/system76/ec/system76_ec.c @@ -26,6 +26,9 @@ #define CMD_PRINT_REG_LEN 3 #define CMD_PRINT_REG_DATA 4 +// Get security state command +#define CMD_SECURITY_GET 20 + static inline uint8_t system76_ec_read(uint8_t addr) { return inb(SYSTEM76_EC_BASE + (uint16_t)addr); @@ -110,3 +113,9 @@ bool system76_ec_cmd(uint8_t cmd, const uint8_t *request_data, return ret; } + +bool system76_ec_security_get(uint8_t *state) +{ + *state = SYSTEM76_EC_SECURITY_STATE_LOCK; + return system76_ec_cmd(CMD_SECURITY_GET, NULL, 0, state, sizeof(*state)); +} diff --git a/src/ec/system76/ec/system76_ec.h b/src/ec/system76/ec/system76_ec.h index 9675bd0caf..6c91bb6aec 100644 --- a/src/ec/system76/ec/system76_ec.h +++ b/src/ec/system76/ec/system76_ec.h @@ -6,6 +6,15 @@ #include #include +// Default value, flashing is prevented, cannot be set with CMD_SECURITY_SET +#define SYSTEM76_EC_SECURITY_STATE_LOCK 0 +// Flashing is allowed, cannot be set with CMD_SECURITY_SET +#define SYSTEM76_EC_SECURITY_STATE_UNLOCK 1 +// Flashing will be prevented on the next reboot +#define SYSTEM76_EC_SECURITY_STATE_PREPARE_LOCK 2 +// Flashing will be allowed on the next reboot +#define SYSTEM76_EC_SECURITY_STATE_PREPARE_UNLOCK 3 + /* * Send a command to the EC. request_data/request_size are the request payload, * request_data can be NULL if request_size is 0. reply_data/reply_size are @@ -14,4 +23,6 @@ bool system76_ec_cmd(uint8_t cmd, const uint8_t *request_data, uint8_t request_size, uint8_t *reply_data, uint8_t reply_size); +bool system76_ec_security_get(uint8_t *state); + #endif