diff options
author | Namyoon Woo <namyoon@chromium.org> | 2019-04-29 16:15:12 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2019-05-02 00:24:56 +0000 |
commit | f5d226f2b6414f47f9e7438fd87af0b773124a58 (patch) | |
tree | 5bec0a5c59cca057aa01afa7e42765ff8c2dbc13 | |
parent | 5f42355f08196bc86e51da2a23c2f5b754a2cb99 (diff) | |
download | chrome-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.c | 16 | ||||
-rw-r--r-- | common/i2c.c | 59 | ||||
-rw-r--r-- | include/i2c.h | 18 |
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 */ |