From 57ba8c58fc40e4546fdf991a969d225c81658f78 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Thu, 21 Feb 2019 13:58:58 -0800 Subject: [PATCH] Add support for RPMB over VirtIO Serial In order to test Trusty gatekeeper automatically, the storage proxy needs to be active inside the emulator. This patch allows storageproxyd to speak a length-framed RPMB to an external RPMB daemon. For a concrete example of a daemon speaking this protocol, see rpmb_dev in the Trusty tree. Bug: 124277696 Test: Launch storageproxyd with -t virt, use Trusty test infra Change-Id: I391d4768976f0eb1f3b8df58eefd58fc3a9409cd --- trusty/storage/proxy/proxy.c | 28 +++++++- trusty/storage/proxy/rpmb.c | 125 +++++++++++++++++++++++++---------- trusty/storage/proxy/rpmb.h | 4 +- 3 files changed, 117 insertions(+), 40 deletions(-) diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c index 9a71ae380..c61f7d007 100644 --- a/trusty/storage/proxy/proxy.c +++ b/trusty/storage/proxy/proxy.c @@ -39,15 +39,29 @@ static const char* trusty_devname; static const char* rpmb_devname; static const char* ss_srv_name = STORAGE_DISK_PROXY_PORT; -static const char* _sopts = "hp:d:r:"; +static enum dev_type dev_type = MMC_RPMB; + +static enum dev_type parse_dev_type(const char* dev_type_name) { + if (!strcmp(dev_type_name, "mmc")) { + return MMC_RPMB; + } else if (!strcmp(dev_type_name, "virt")) { + return VIRT_RPMB; + } else { + return UNKNOWN_RPMB; + } +} + +static const char* _sopts = "hp:d:r:t:"; static const struct option _lopts[] = {{"help", no_argument, NULL, 'h'}, {"trusty_dev", required_argument, NULL, 'd'}, {"data_path", required_argument, NULL, 'p'}, {"rpmb_dev", required_argument, NULL, 'r'}, + {"dev_type", required_argument, NULL, 't'}, {0, 0, 0, 0}}; static void show_usage_and_exit(int code) { - ALOGE("usage: storageproxyd -d -p -r \n"); + ALOGE("usage: storageproxyd -d -p -r -t \n"); + ALOGE("Available dev types: mmc, virt\n"); exit(code); } @@ -195,6 +209,14 @@ static void parse_args(int argc, char* argv[]) { rpmb_devname = strdup(optarg); break; + case 't': + dev_type = parse_dev_type(optarg); + if (dev_type == UNKNOWN_RPMB) { + ALOGE("Unrecognized dev type: %s\n", optarg); + show_usage_and_exit(EXIT_FAILURE); + } + break; + default: ALOGE("unrecognized option (%c):\n", opt); show_usage_and_exit(EXIT_FAILURE); @@ -226,7 +248,7 @@ int main(int argc, char* argv[]) { if (rc < 0) return EXIT_FAILURE; /* open rpmb device */ - rc = rpmb_open(rpmb_devname); + rc = rpmb_open(rpmb_devname, dev_type); if (rc < 0) return EXIT_FAILURE; /* connect to Trusty secure storage server */ diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c index e706d0ace..29827e28f 100644 --- a/trusty/storage/proxy/rpmb.c +++ b/trusty/storage/proxy/rpmb.c @@ -51,6 +51,7 @@ static int rpmb_fd = -1; static uint8_t read_buf[4096]; +static enum dev_type dev_type = UNKNOWN_RPMB; #ifdef RPMB_DEBUG @@ -68,36 +69,16 @@ static void print_buf(const char* prefix, const uint8_t* buf, size_t size) { #endif -int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len) { - int rc; +static int send_mmc_rpmb_req(int mmc_fd, const struct storage_rpmb_send_req* req) { struct { struct mmc_ioc_multi_cmd multi; struct mmc_ioc_cmd cmd_buf[3]; } mmc = {}; struct mmc_ioc_cmd* cmd = mmc.multi.cmds; - const struct storage_rpmb_send_req* req = r; - - if (req_len < sizeof(*req)) { - ALOGW("malformed rpmb request: invalid length (%zu < %zu)\n", req_len, sizeof(*req)); - msg->result = STORAGE_ERR_NOT_VALID; - goto err_response; - } - - size_t expected_len = sizeof(*req) + req->reliable_write_size + req->write_size; - if (req_len != expected_len) { - ALOGW("malformed rpmb request: invalid length (%zu != %zu)\n", req_len, expected_len); - msg->result = STORAGE_ERR_NOT_VALID; - goto err_response; - } + int rc; const uint8_t* write_buf = req->payload; if (req->reliable_write_size) { - if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) { - ALOGW("invalid reliable write size %u\n", req->reliable_write_size); - msg->result = STORAGE_ERR_NOT_VALID; - goto err_response; - } - cmd->write_flag = MMC_WRITE_FLAG_RELW; cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK; cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; @@ -114,12 +95,6 @@ int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len) { } if (req->write_size) { - if ((req->write_size % MMC_BLOCK_SIZE) != 0) { - ALOGW("invalid write size %u\n", req->write_size); - msg->result = STORAGE_ERR_NOT_VALID; - goto err_response; - } - cmd->write_flag = MMC_WRITE_FLAG_W; cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK; cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; @@ -136,12 +111,6 @@ int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len) { } if (req->read_size) { - if (req->read_size % MMC_BLOCK_SIZE != 0 || req->read_size > sizeof(read_buf)) { - ALOGE("%s: invalid read size %u\n", __func__, req->read_size); - msg->result = STORAGE_ERR_NOT_VALID; - goto err_response; - } - cmd->write_flag = MMC_WRITE_FLAG_R; cmd->opcode = MMC_READ_MULTIPLE_BLOCK; cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC, cmd->blksz = MMC_BLOCK_SIZE; @@ -154,9 +123,92 @@ int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len) { cmd++; } - rc = ioctl(rpmb_fd, MMC_IOC_MULTI_CMD, &mmc.multi); + rc = ioctl(mmc_fd, MMC_IOC_MULTI_CMD, &mmc.multi); if (rc < 0) { ALOGE("%s: mmc ioctl failed: %d, %s\n", __func__, rc, strerror(errno)); + } + return rc; +} + +static int send_virt_rpmb_req(int rpmb_fd, void* read_buf, size_t read_size, const void* payload, + size_t payload_size) { + int rc; + uint16_t res_count = read_size / MMC_BLOCK_SIZE; + uint16_t cmd_count = payload_size / MMC_BLOCK_SIZE; + rc = write(rpmb_fd, &res_count, sizeof(res_count)); + if (rc < 0) { + return rc; + } + rc = write(rpmb_fd, &cmd_count, sizeof(cmd_count)); + if (rc < 0) { + return rc; + } + rc = write(rpmb_fd, payload, payload_size); + if (rc < 0) { + return rc; + } + rc = read(rpmb_fd, read_buf, read_size); + return rc; +} + +int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len) { + int rc; + const struct storage_rpmb_send_req* req = r; + + if (req_len < sizeof(*req)) { + ALOGW("malformed rpmb request: invalid length (%zu < %zu)\n", req_len, sizeof(*req)); + msg->result = STORAGE_ERR_NOT_VALID; + goto err_response; + } + + size_t expected_len = sizeof(*req) + req->reliable_write_size + req->write_size; + if (req_len != expected_len) { + ALOGW("malformed rpmb request: invalid length (%zu != %zu)\n", req_len, expected_len); + msg->result = STORAGE_ERR_NOT_VALID; + goto err_response; + } + + if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) { + ALOGW("invalid reliable write size %u\n", req->reliable_write_size); + msg->result = STORAGE_ERR_NOT_VALID; + goto err_response; + } + + if ((req->write_size % MMC_BLOCK_SIZE) != 0) { + ALOGW("invalid write size %u\n", req->write_size); + msg->result = STORAGE_ERR_NOT_VALID; + goto err_response; + } + + if (req->read_size % MMC_BLOCK_SIZE != 0 || req->read_size > sizeof(read_buf)) { + ALOGE("%s: invalid read size %u\n", __func__, req->read_size); + msg->result = STORAGE_ERR_NOT_VALID; + goto err_response; + } + + if (dev_type == MMC_RPMB) { + rc = send_mmc_rpmb_req(rpmb_fd, req); + if (rc < 0) { + msg->result = STORAGE_ERR_GENERIC; + goto err_response; + } + } else if (dev_type == VIRT_RPMB) { + size_t payload_size = req->reliable_write_size + req->write_size; + rc = send_virt_rpmb_req(rpmb_fd, read_buf, req->read_size, req->payload, payload_size); + if (rc < 0) { + ALOGE("send_virt_rpmb_req failed: %d, %s\n", rc, strerror(errno)); + msg->result = STORAGE_ERR_GENERIC; + goto err_response; + } + if (rc != req->read_size) { + ALOGE("send_virt_rpmb_req got incomplete response: " + "(size %d, expected %d)\n", + rc, req->read_size); + msg->result = STORAGE_ERR_GENERIC; + goto err_response; + } + } else { + ALOGE("Unsupported dev_type\n"); msg->result = STORAGE_ERR_GENERIC; goto err_response; } @@ -178,8 +230,9 @@ err_response: return ipc_respond(msg, NULL, 0); } -int rpmb_open(const char* rpmb_devname) { +int rpmb_open(const char* rpmb_devname, enum dev_type open_dev_type) { int rc; + dev_type = open_dev_type; rc = open(rpmb_devname, O_RDWR, 0); if (rc < 0) { diff --git a/trusty/storage/proxy/rpmb.h b/trusty/storage/proxy/rpmb.h index 510736107..4c330c921 100644 --- a/trusty/storage/proxy/rpmb.h +++ b/trusty/storage/proxy/rpmb.h @@ -18,6 +18,8 @@ #include #include -int rpmb_open(const char* rpmb_devname); +enum dev_type { UNKNOWN_RPMB, MMC_RPMB, VIRT_RPMB }; + +int rpmb_open(const char* rpmb_devname, enum dev_type dev_type); int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len); void rpmb_close(void);