summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNamyoon Woo <namyoon@chromium.org>2019-04-29 16:15:12 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2019-05-02 00:24:56 +0000
commitf5d226f2b6414f47f9e7438fd87af0b773124a58 (patch)
tree5bec0a5c59cca057aa01afa7e42765ff8c2dbc13
parent5f42355f08196bc86e51da2a23c2f5b754a2cb99 (diff)
downloadchrome-ec-f5d226f2b6414f47f9e7438fd87af0b773124a58.tar.gz
i2c: Implement whitelist for i2c passthrough against system lock
This CL defines I2C command white list, which are allowed though system is locked. A unit of whitelist is a pair of slave address and command ID. As of this CL, Kip has a Battery CT Label query command (0x70) at 0x0b slave address in whitelist. BUG=b:119534901 BRANCH=kip TEST=manually ran ectool. $ flashrom -p ec wp-status .. WP: write protect is enabled. $ ectool --ascii i2cxfer 0 0 0 0 EC result 4 (ACCESS_DENIED) $ ectool --ascii i2cxfer 0 0x0b 15 0x70 \x106EGXDN2RY7V09V Change-Id: I63dee7d8f8c2b11fb54bf7c85ee903ce59bb2013 Signed-off-by: Namyoon Woo <namyoon@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1588492 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r--board/kip/board.c16
-rw-r--r--common/i2c.c59
-rw-r--r--include/i2c.h18
3 files changed, 85 insertions, 8 deletions
diff --git a/board/kip/board.c b/board/kip/board.c
index 6949464dbb..f84bbc0ef5 100644
--- a/board/kip/board.c
+++ b/board/kip/board.c
@@ -220,6 +220,22 @@ struct ec_thermal_config thermal_params[] = {
};
BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT);
+/*
+ * Whitelist of I2C Passthru parameters that are allowed even when
+ * system is locked.
+ */
+const struct i2c_cmd_desc_t i2c_whitelist[] = {
+ /* Battery CT LABEL */
+ {
+ .port = 0x00,
+ .cmd = 0x70,
+ .slave_addr = 0x0b,
+ .leng_rd = 15,
+ .leng_wr = 1,
+ },
+};
+volatile const int i2c_whitelist_size = ARRAY_SIZE(i2c_whitelist);
+
/**
* Discharge battery when on AC power for factory test.
*/
diff --git a/common/i2c.c b/common/i2c.c
index f5ce577aa2..e483efe3ad 100644
--- a/common/i2c.c
+++ b/common/i2c.c
@@ -403,6 +403,27 @@ DECLARE_HOST_COMMAND(EC_CMD_I2C_WRITE, i2c_command_write, EC_VER_MASK(0));
#define PTHRUPRINTF(format, args...)
#endif
+#ifdef CONFIG_I2C_PASSTHRU_RESTRICTED
+__attribute__((weak)) const struct i2c_cmd_desc_t i2c_whitelist[] = { };
+__attribute__((weak)) volatile const int i2c_whitelist_size
+ = ARRAY_SIZE(i2c_whitelist);
+
+static int i2c_cmd_in_whitelist(const struct i2c_cmd_desc_t *cmd_desc)
+{
+ int i;
+
+ for (i = 0; i < i2c_whitelist_size; ++i) {
+ if (i2c_whitelist[i].port == cmd_desc->port &&
+ i2c_whitelist[i].cmd == cmd_desc->cmd &&
+ i2c_whitelist[i].slave_addr == cmd_desc->slave_addr &&
+ i2c_whitelist[i].leng_rd >= cmd_desc->leng_rd &&
+ i2c_whitelist[i].leng_wr >= cmd_desc->leng_wr)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
/**
* Perform the voluminous checking required for this message
*
@@ -416,7 +437,11 @@ static int check_i2c_params(const struct host_cmd_handler_args *args)
int read_len = 0, write_len = 0;
unsigned int size;
int msgnum;
-
+#ifdef CONFIG_I2C_PASSTHRU_RESTRICTED
+ uint16_t slave_addr = 0xFFFF;
+ uint8_t cmd_id = 0xFF;
+ const uint8_t *out;
+#endif
if (args->params_size < sizeof(*params)) {
PTHRUPRINTF("[%T i2c passthru no params, params_size=%d, "
"need at least %d]\n",
@@ -437,6 +462,9 @@ static int check_i2c_params(const struct host_cmd_handler_args *args)
return EC_RES_INVALID_PARAM;
}
+#ifdef CONFIG_I2C_PASSTHRU_RESTRICTED
+ out = args->params + size;
+#endif
/* Loop and process messages */;
for (msgnum = 0, msg = params->msg; msgnum < params->num_msgs;
msgnum++, msg++) {
@@ -456,12 +484,32 @@ static int check_i2c_params(const struct host_cmd_handler_args *args)
addr_flags & EC_I2C_ADDR_MASK,
msg->len);
- if (addr_flags & EC_I2C_FLAG_READ)
+ if (addr_flags & EC_I2C_FLAG_READ) {
read_len += msg->len;
- else
+ } else {
+#ifdef CONFIG_I2C_PASSTHRU_RESTRICTED
+ slave_addr = msg->addr_flags & EC_I2C_ADDR_MASK;
+ cmd_id = out[write_len];
+#endif
write_len += msg->len;
+ }
}
+#ifdef CONFIG_I2C_PASSTHRU_RESTRICTED
+ if (system_is_locked()) {
+ const struct i2c_cmd_desc_t cmd_desc = {
+ .port = params->port,
+ .cmd = cmd_id,
+ .slave_addr = slave_addr,
+ .leng_rd = read_len,
+ .leng_wr = write_len,
+ };
+
+ if (!i2c_cmd_in_whitelist(&cmd_desc))
+ return EC_RES_ACCESS_DENIED;
+ }
+#endif
+
/* Check there is room for the data */
if (args->response_max <
sizeof(struct ec_response_i2c_passthru) + read_len) {
@@ -487,11 +535,6 @@ static int i2c_command_passthru(struct host_cmd_handler_args *args)
int in_len;
int ret;
-#ifdef CONFIG_I2C_PASSTHRU_RESTRICTED
- if (system_is_locked())
- return EC_RES_ACCESS_DENIED;
-#endif
-
ret = check_i2c_params(args);
if (ret)
return ret;
diff --git a/include/i2c.h b/include/i2c.h
index ac572960df..f3d272cf8c 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -25,6 +25,24 @@ struct i2c_port_t {
extern const struct i2c_port_t i2c_ports[];
extern const unsigned int i2c_ports_used;
+/*
+ * Data structure to define I2C Parameters for a command
+ */
+struct i2c_cmd_desc_t {
+ uint8_t port; /* I2C port */
+ uint8_t cmd; /* command ID */
+ uint16_t slave_addr; /* Slave address */
+ uint16_t leng_rd; /* max byte length to allow for read*/
+ uint16_t leng_wr; /* max byte length to allow for write*/
+};
+
+/*
+ * The list of commands that are allowed even when the system is locked.
+ * board/${BOARD}/board.c should define this.
+ */
+extern const struct i2c_cmd_desc_t i2c_whitelist[];
+extern volatile const int i2c_whitelist_size;
+
/* Flags for i2c_xfer() */
#define I2C_XFER_START (1 << 0) /* Start smbus session from idle state */
#define I2C_XFER_STOP (1 << 1) /* Terminate smbus session with stop bit */