-
Notifications
You must be signed in to change notification settings - Fork 237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tee-supplicant: Enable command line support for RPMB_EMU #355
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,12 +26,14 @@ | |
*/ | ||
|
||
#include <dirent.h> | ||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <linux/types.h> | ||
#include <linux/mmc/ioctl.h> | ||
#include <netinet/in.h> | ||
#include <pthread.h> | ||
#include <rpmb.h> | ||
#include <stdarg.h> | ||
#include <stdbool.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
@@ -43,12 +45,7 @@ | |
#include <tee_supplicant.h> | ||
#include <unistd.h> | ||
|
||
#ifdef RPMB_EMU | ||
#include <stdarg.h> | ||
#include "hmac_sha2.h" | ||
#else | ||
#include <errno.h> | ||
#endif | ||
|
||
/* | ||
* Request and response definitions must be in sync with the secure side | ||
|
@@ -139,17 +136,16 @@ static pthread_mutex_t rpmb_mutex = PTHREAD_MUTEX_INITIALIZER; | |
/* Maximum number of commands used in a multiple ioc command request */ | ||
#define RPMB_MAX_IOC_MULTI_CMDS 3 | ||
|
||
#ifndef RPMB_EMU | ||
|
||
#define IOCTL(fd, request, ...) \ | ||
({ \ | ||
int ret; \ | ||
ret = ioctl((fd), (request), ##__VA_ARGS__); \ | ||
if (ret < 0) \ | ||
EMSG("ioctl ret=%d errno=%d", ret, errno); \ | ||
ret; \ | ||
}) | ||
typedef struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. prefer without a typedef definition, just |
||
int (*ioctl)(int d, long unsigned int request, ...); | ||
int (*get_fd)(uint16_t dev_id); | ||
TEEC_Result (*read_cid)(uint16_t dev_id, uint8_t *cid); | ||
TEEC_Result (*read_size_mult)(uint16_t dev_id, uint8_t *value); | ||
TEEC_Result (*read_rel_wr_sec_c)(uint16_t dev_id, uint8_t *value); | ||
bool (*remap_dev_id)(uint16_t dev_id, uint16_t *ndev_id); | ||
} rpmb_ops_t; | ||
|
||
static rpmb_ops_t rpmb_ops; | ||
|
||
/* Open and/or return file descriptor to RPMB partition of device dev_id */ | ||
static int mmc_rpmb_fd(uint16_t dev_id) | ||
|
@@ -389,10 +385,6 @@ static bool remap_rpmb_dev_id(uint16_t dev_id, uint16_t *ndev_id) | |
return found; | ||
} | ||
|
||
#else /* RPMB_EMU */ | ||
|
||
#define IOCTL(fd, request, ...) ioctl_emu((fd), (request), ##__VA_ARGS__) | ||
|
||
/* Emulated rel_wr_sec_c value (reliable write size, *256 bytes) */ | ||
#define EMU_RPMB_REL_WR_SEC_C 1 | ||
/* Emulated rpmb_size_mult value (RPMB size, *128 kB) */ | ||
|
@@ -414,9 +406,7 @@ struct rpmb_emu { | |
uint16_t address; | ||
} last_op; | ||
}; | ||
static struct rpmb_emu rpmb_emu = { | ||
.size = EMU_RPMB_SIZE_BYTES | ||
}; | ||
static struct rpmb_emu *rpmb_emu; | ||
|
||
static struct rpmb_emu *mem_for_fd(int fd) | ||
{ | ||
|
@@ -429,7 +419,7 @@ static struct rpmb_emu *mem_for_fd(int fd) | |
return NULL; | ||
} | ||
|
||
return &rpmb_emu; | ||
return rpmb_emu; | ||
} | ||
|
||
#if (DEBUGLEVEL >= TRACE_FLOW) | ||
|
@@ -609,7 +599,7 @@ static void ioctl_emu_read_ctr(struct rpmb_emu *mem, | |
frm->op_result = compute_hmac(mem, frm, 1); | ||
} | ||
|
||
static uint32_t read_cid(uint16_t dev_id, uint8_t *cid) | ||
static uint32_t read_cid_emu(uint16_t dev_id, uint8_t *cid) | ||
{ | ||
/* Taken from an actual eMMC chip */ | ||
static const uint8_t test_cid[] = { | ||
|
@@ -747,38 +737,36 @@ static int ioctl_emu(int fd, unsigned long request, ...) | |
return res; | ||
} | ||
|
||
static int mmc_rpmb_fd(uint16_t dev_id) | ||
static int mmc_rpmb_fd_emu(uint16_t dev_id) | ||
{ | ||
(void)dev_id; | ||
|
||
/* Any value != -1 will do in test mode */ | ||
return 0; | ||
} | ||
|
||
static TEEC_Result read_size_mult(uint16_t dev_id, uint8_t *value) | ||
static TEEC_Result read_size_mult_emu(uint16_t dev_id, uint8_t *value) | ||
{ | ||
(void)dev_id; | ||
|
||
*value = EMU_RPMB_SIZE_MULT; | ||
return TEEC_SUCCESS; | ||
} | ||
|
||
static TEEC_Result read_rel_wr_sec_c(uint16_t dev_id, uint8_t *value) | ||
static TEEC_Result read_rel_wr_sec_c_emu(uint16_t dev_id, uint8_t *value) | ||
{ | ||
(void)dev_id; | ||
|
||
*value = EMU_RPMB_REL_WR_SEC_C; | ||
return TEEC_SUCCESS; | ||
} | ||
|
||
static bool remap_rpmb_dev_id(uint16_t dev_id, uint16_t *ndev_id) | ||
static bool remap_rpmb_dev_id_emu(uint16_t dev_id, uint16_t *ndev_id) | ||
{ | ||
*ndev_id = dev_id; | ||
return true; | ||
} | ||
|
||
#endif /* RPMB_EMU */ | ||
|
||
static inline void set_mmc_io_cmd(struct mmc_ioc_cmd *cmd, unsigned int blocks, | ||
__u32 opcode, int write_flag) | ||
{ | ||
|
@@ -890,7 +878,7 @@ static uint32_t rpmb_data_req(int fd, struct rpmb_data_frame *req_frm, | |
goto out; | ||
} | ||
|
||
st = IOCTL(fd, MMC_IOC_MULTI_CMD, mcmd); | ||
st = rpmb_ops.ioctl(fd, MMC_IOC_MULTI_CMD, mcmd); | ||
if (st < 0) | ||
res = TEEC_ERROR_GENERIC; | ||
|
||
|
@@ -906,16 +894,16 @@ static uint32_t rpmb_get_dev_info(uint16_t dev_id, struct rpmb_dev_info *info) | |
uint8_t rpmb_size_mult = 0; | ||
uint8_t rel_wr_sec_c = 0; | ||
|
||
res = read_cid(dev_id, info->cid); | ||
res = rpmb_ops.read_cid(dev_id, info->cid); | ||
if (res != TEEC_SUCCESS) | ||
return res; | ||
|
||
res = read_size_mult(dev_id, &rpmb_size_mult); | ||
res = rpmb_ops.read_size_mult(dev_id, &rpmb_size_mult); | ||
if (res != TEEC_SUCCESS) | ||
return res; | ||
info->rpmb_size_mult = rpmb_size_mult; | ||
|
||
res = read_rel_wr_sec_c(dev_id, &rel_wr_sec_c); | ||
res = rpmb_ops.read_rel_wr_sec_c(dev_id, &rel_wr_sec_c); | ||
if (res != TEEC_SUCCESS) | ||
return res; | ||
info->rel_wr_sec_c = rel_wr_sec_c; | ||
|
@@ -943,14 +931,14 @@ static uint32_t rpmb_process_request_unlocked(void *req, size_t req_size, | |
if (req_size < sizeof(*sreq)) | ||
return TEEC_ERROR_BAD_PARAMETERS; | ||
|
||
if (!remap_rpmb_dev_id(sreq->dev_id, &dev_id)) | ||
if (!rpmb_ops.remap_dev_id(sreq->dev_id, &dev_id)) | ||
return TEEC_ERROR_ITEM_NOT_FOUND; | ||
|
||
switch (sreq->cmd) { | ||
case RPMB_CMD_DATA_REQ: | ||
req_nfrm = (req_size - sizeof(struct rpmb_req)) / 512; | ||
rsp_nfrm = rsp_size / 512; | ||
fd = mmc_rpmb_fd(dev_id); | ||
fd = rpmb_ops.get_fd(dev_id); | ||
if (fd < 0) | ||
return TEEC_ERROR_BAD_PARAMETERS; | ||
res = rpmb_data_req(fd, RPMB_REQ_DATA(req), req_nfrm, rsp, | ||
|
@@ -987,3 +975,31 @@ uint32_t rpmb_process_request(void *req, size_t req_size, void *rsp, | |
|
||
return res; | ||
} | ||
|
||
|
||
int rpmb_init() | ||
{ | ||
if (!supplicant_params.rpmb_emu_disable) { | ||
rpmb_emu = calloc(1, sizeof(*rpmb_emu)); | ||
if (!rpmb_emu) { | ||
EMSG("Failed to allocate buffer for RPMBi emulation"); | ||
return -ENOMEM; | ||
} | ||
rpmb_emu->size = EMU_RPMB_SIZE_BYTES; | ||
rpmb_ops.ioctl = ioctl_emu; | ||
rpmb_ops.get_fd = mmc_rpmb_fd_emu; | ||
rpmb_ops.read_cid = read_cid_emu; | ||
rpmb_ops.read_size_mult = read_size_mult_emu; | ||
rpmb_ops.read_rel_wr_sec_c = read_rel_wr_sec_c_emu; | ||
rpmb_ops.remap_dev_id = remap_rpmb_dev_id_emu; | ||
} else { | ||
rpmb_ops.ioctl = ioctl; | ||
rpmb_ops.get_fd = mmc_rpmb_fd; | ||
rpmb_ops.read_cid = read_cid; | ||
rpmb_ops.read_size_mult = read_size_mult; | ||
rpmb_ops.read_rel_wr_sec_c = read_rel_wr_sec_c; | ||
rpmb_ops.remap_dev_id = remap_rpmb_dev_id; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIRC, but I also didn't address this in my version, emulation comes with a rather large static buffer. Maybe that should now be allocated dynamically and only if emulation is actually used. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The 'emulation' itself seems useful (at least for our case). It's used to test the RPMB related functionalities before switching to real RPMB, which needs to program the one-time permanent RPMB keys. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, but you also don't ship debug symbols or allocate debug trace buffers statically when you operate in production mode. I'm just asking for reducing the overhead by a potentially unused mode during runtime. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it. I misunderstood the top comment. Will update it and post a new version. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated (in latest 21bad5b). |
||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -493,6 +493,7 @@ static int usage(int status) | |
fprintf(stderr, "\t-h, --help: this help\n"); | ||
fprintf(stderr, "\t-d, --daemonize: run as a daemon (fork and return " | ||
"after child has opened the TEE device or on error)\n"); | ||
fprintf(stderr, "\t-e, --rpmb-emu-disable: RPMB emunation disable\n"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems inverted: Emulation is the corner case, not the common one. So we likely rather want -e having the semantic of --rpmb-emulation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I would prefer the '--rpmb-emulation' idea as well. The problem is with the Linux distros we worked with requested to preserve the current default behavior, which means that "./tee-supplicant" should behave like RPMB EMU enabled. Thus adding the optional argument '--rpmb-emu-disable' to disable it. Or any suggestions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those distros could be given such a switch to keep the old behavior. In newer major distro releases, this can then be adjusted to something more useful than emulation only or emulation by default. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But I can't imagine any stable distro picking up this change anyway. It's clearly aiming at new major releases (eg. Debian trixie). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually we're working with Canonical support to add the real RPMB support (with this patch) into their existing LTS release. They're holding it 'pending the adoption of the pull request'. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi - I'm working with @lsun100 to see if there's a way to enable the non-emu version in Ubuntu, as a post-release update. With respect to whether or not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dannf , how about @jan-kiszka 's proposal to use "--rpmb-emulation" only. That's to say, use real RPMB by default and specify "--rpmb-emulation" when needed for emulation. In ubuntu 'debian/tee-supplicant.service' file, we could this argument like "ExecStart=/usr/sbin/tee-supplicant --rpmb-emulation"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a possibility that we have users using the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But emulation is a testing toy, not the real purpose of tee-supplicant. I would suggest to give those users the chance to restore the behavior at build-time but avoid bothering the rest. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jan-kiszka leaving it as a build-time option may very well be what is best for the upstream project - I'm not qualified to comment on that. My commentary is really just about the impact the chosen implementation would have on the feasibility of including those changes in a post-release update to an existing Ubuntu release. These objectives may end up being incompatible, in which case Ubuntu users will likely need to wait for a future release for a non-emulated support. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo - s/emunation/emulation/ |
||
fprintf(stderr, "\t-f, --fs-parent-path: secure fs parent path [%s]\n", | ||
supplicant_params.fs_parent_path); | ||
fprintf(stderr, "\t-t, --ta-dir: TAs dirname under %s [%s]\n", TEEC_LOAD_PATH, | ||
|
@@ -808,14 +809,15 @@ int main(int argc, char *argv[]) | |
/* long name | has argument | flag | short value */ | ||
{ "help", no_argument, 0, 'h' }, | ||
{ "daemonize", no_argument, 0, 'd' }, | ||
{ "rpmb-emu-disable", no_argument, 0, 'e' }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add also |
||
{ "fs-parent-path", required_argument, 0, 'f' }, | ||
{ "ta-dir", required_argument, 0, 't' }, | ||
{ "plugin-path", required_argument, 0, 'p' }, | ||
{ "rpmb-cid", required_argument, 0, 'r' }, | ||
{ 0, 0, 0, 0 } | ||
}; | ||
|
||
while ((opt = getopt_long(argc, argv, "hdf:t:p:r:", | ||
while ((opt = getopt_long(argc, argv, "hde:f:t:p:r:", | ||
long_options, &long_index )) != -1) { | ||
switch (opt) { | ||
case 'h' : | ||
|
@@ -824,6 +826,9 @@ int main(int argc, char *argv[]) | |
case 'd': | ||
daemonize = true; | ||
break; | ||
case 'e': | ||
supplicant_params.rpmb_emu_disable = true; | ||
break; | ||
case 'f': | ||
supplicant_params.fs_parent_path = optarg; | ||
break; | ||
|
@@ -895,6 +900,8 @@ int main(int argc, char *argv[]) | |
close(pipefd[1]); | ||
} | ||
|
||
rpmb_init(); | ||
|
||
while (!arg.abort) { | ||
if (!process_one_request(&arg)) | ||
arg.abort = true; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ struct tee_supplicant_params { | |
const char *plugin_load_path; | ||
const char *fs_parent_path; | ||
const char *rpmb_cid; | ||
bool rpmb_emu_disable; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better be called in a positive statement: |
||
}; | ||
|
||
extern struct tee_supplicant_params supplicant_params; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For backward compat, could config switch RPMB_EMU be preserved and set whether or not RPMB emulation is default enabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it really help? What would happen if set to OFF? I'd rather simplify things as much as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean preserving the config switch but just default it is
OFF
? If so, fine with me.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No I mean remove this config entirely, because otherwise it would be misleading when set to OFF.