diff --git a/libteec/CMakeLists.txt b/libteec/CMakeLists.txt index 9422eeb9..901258b2 100644 --- a/libteec/CMakeLists.txt +++ b/libteec/CMakeLists.txt @@ -1,6 +1,10 @@ project(libteec C) -set(PROJECT_VERSION "1.0.0") +set(MAJOR_VERSION 2) +set(MINOR_VERSION 0) +set(PATCH_VERSION 0) + +set(PROJECT_VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}") ################################################################################ # Packages @@ -37,7 +41,7 @@ add_library (teec ${SRC}) set_target_properties (teec PROPERTIES VERSION ${PROJECT_VERSION} - SOVERSION 1 + SOVERSION ${MAJOR_VERSION} ) ################################################################################ diff --git a/libteec/Makefile b/libteec/Makefile index 3b279ab1..a46bf6c5 100644 --- a/libteec/Makefile +++ b/libteec/Makefile @@ -9,7 +9,7 @@ all: libteec ################################################################################ # Teec configuration ################################################################################ -MAJOR_VERSION := 1 +MAJOR_VERSION := 2 MINOR_VERSION := 0 PATCH_VERSION := 0 LIB_NAME := libteec.so diff --git a/libteec/include/linux/tee.h b/libteec/include/linux/tee.h index f883ebc9..c8cecdb8 100644 --- a/libteec/include/linux/tee.h +++ b/libteec/include/linux/tee.h @@ -43,8 +43,10 @@ #define TEE_IOC_BASE 0 /* Flags relating to shared memory */ +#define TEE_IOCTL_SHM_NONE 0x0 /* no flags */ #define TEE_IOCTL_SHM_MAPPED 0x1 /* memory mapped in normal world */ #define TEE_IOCTL_SHM_DMA_BUF 0x2 /* dma-buf handle on shared memory */ +#define TEE_IOCTL_SHM_OCALL 0x4 /* memory used for an OCALL */ #define TEE_MAX_ARG_SIZE 1024 @@ -52,6 +54,7 @@ #define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplicant) */ #define TEE_GEN_CAP_REG_MEM (1 << 2)/* Supports registering shared memory */ #define TEE_GEN_CAP_MEMREF_NULL (1 << 3) /* Support NULL MemRef */ +#define TEE_GEN_CAP_OCALL (1 << 4) /* Supports calls from TA to CA */ #define TEE_MEMREF_NULL ((__u64)-1) /* NULL MemRef Buffer */ @@ -167,9 +170,14 @@ struct tee_ioctl_shm_register_fd_data { /* Meta parameter carrying extra information about the message. */ #define TEE_IOCTL_PARAM_ATTR_META 0x100 +/* Parameter carrying information about an OCALL reply or request. */ +#define TEE_IOCTL_PARAM_ATTR_OCALL 0x200 + /* Mask of all known attr bits */ #define TEE_IOCTL_PARAM_ATTR_MASK \ - (TEE_IOCTL_PARAM_ATTR_TYPE_MASK | TEE_IOCTL_PARAM_ATTR_META) + (TEE_IOCTL_PARAM_ATTR_TYPE_MASK | \ + TEE_IOCTL_PARAM_ATTR_META | \ + TEE_IOCTL_PARAM_ATTR_OCALL) /* * Matches TEEC_LOGIN_* in GP TEE Client API @@ -243,6 +251,54 @@ struct tee_ioctl_open_session_arg { #define TEE_IOC_OPEN_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 2, \ struct tee_ioctl_buf_data) +/* + * Command sent to the CA to request allocation of shared memory to carry the + * parameters of an OCALL + * + * [in] param[0].u.value.b requested memory size + * [out] param[0].u.value.c SHM ID + * + * Note: [in] means from driver to CA, [out], from CA to driver. + */ +#define TEE_IOCTL_OCALL_CMD_SHM_ALLOC 1 + +/* + * Command sent to the CA to free previously allocated shared memory. + * + * [in] param[0].u.value.c SHM ID + * + * Note: [in] means from driver to CA. + */ +#define TEE_IOCTL_OCALL_CMD_SHM_FREE 2 + +/* + * Command sent to the CA to execute an OCALL by Id. + * + * [any] param[0..3].u.* carry OCALL parameters + */ +#define TEE_IOCTL_OCALL_CMD_INVOKE 3 + +/* + * Join the Id of the function that the TEE Client API must execute on behalf of + * the CA with the Id of the command that the CA must execute + * + * As an example, TEE_IOCTL_OCALL_MAKE_PAIR(TEE_IOCTL_OCALL_CMD_INVOKE, 10) + * means that the Client API must forward a function invocation to a CA-provided + * handler, and the handler must execute command Id '10', whose meaning is up to + * the user-defined contract between the CA & TA. + */ +#define TEE_IOCTL_OCALL_MAKE_PAIR(func, cmd) \ + (((__u64)(func) << 32) | (__u32)(cmd)) + +/* + * Get the Id of the function that the TEE Client API must execute on behalf of + * the CA + */ +#define TEE_IOCTL_OCALL_GET_FUNC(x) ((__u32)((x) >> 32)) + +/* Get the Id of the command that the CA must execute */ +#define TEE_IOCTL_OCALL_GET_CMD(x) ((__u32)(x)) + /** * struct tee_ioctl_invoke_func_arg - Invokes a function in a Trusted * Application diff --git a/libteec/src/tee_client_api.c b/libteec/src/tee_client_api.c index 608bf24c..ff7ea8aa 100644 --- a/libteec/src/tee_client_api.c +++ b/libteec/src/tee_client_api.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -62,7 +63,27 @@ #define SHM_FLAG_BUFFER_ALLOCED (1u << 0) #define SHM_FLAG_SHADOW_BUFFER_ALLOCED (1u << 1) +/* Helpers to access parts of the OCALL parameter */ +#define OCALL_PAIR(p) ((p)->a) +#define OCALL_FUNC(p) (TEE_IOCTL_OCALL_GET_FUNC(OCALL_PAIR(p))) +#define OCALL_CMD(p) (TEE_IOCTL_OCALL_GET_CMD(OCALL_PAIR(p))) + +/* Small helpers */ +#define SHIFT_U32(v, shift) ((uint32_t)(v) << (shift)) +#define PTR_ADD(p1, p2) ((void *)((uintptr_t)(p1) + (uintptr_t)(p2))) + +/* This only exists to avoid including in tee_client_api.h */ +struct teec_shm_record { + TEEC_SharedMemory shm; + SLIST_ENTRY(teec_shm_record) next; +}; + +/* List of registered shared memory objects used by OCALLs */ +static SLIST_HEAD(teec_reg_shm_head, teec_shm_record) teec_shm_records = + SLIST_HEAD_INITIALIZER(teec_reg_shm_head); + static pthread_mutex_t teec_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t teec_shm_records_mutex = PTHREAD_MUTEX_INITIALIZER; static void teec_mutex_lock(pthread_mutex_t *mu) { @@ -139,7 +160,8 @@ static int teec_shm_alloc(int fd, size_t size, int *id) return shm_fd; } -static int teec_shm_register(int fd, void *buf, size_t size, int *id) +static int teec_shm_register(int fd, void *buf, size_t size, int *id, + uint32_t flags) { int shm_fd = 0; struct tee_ioctl_shm_register_data data; @@ -148,6 +170,7 @@ static int teec_shm_register(int fd, void *buf, size_t size, int *id) data.addr = (uintptr_t)buf; data.length = size; + data.flags = flags; shm_fd = ioctl(fd, TEE_IOC_SHM_REGISTER, &data); if (shm_fd < 0) return -1; @@ -173,6 +196,9 @@ TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *ctx) ctx->fd = fd; ctx->reg_mem = gen_caps & TEE_GEN_CAP_REG_MEM; ctx->memref_null = gen_caps & TEE_GEN_CAP_MEMREF_NULL; + ctx->ocall = gen_caps & TEE_GEN_CAP_OCALL; + ctx->ocall_setting.handler = NULL; + ctx->ocall_setting.data = NULL; return TEEC_SUCCESS; } } @@ -180,6 +206,51 @@ TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *ctx) return TEEC_ERROR_ITEM_NOT_FOUND; } +TEEC_Result TEEC_InitializeContext2(const char *name, TEEC_Context *context, + const TEEC_ContextSetting *settings, + uint32_t numSettings) +{ + uint32_t n; + TEEC_Result res; + + if (!settings && numSettings) + return TEEC_ERROR_BAD_PARAMETERS; + + for (n = 0; n < numSettings; n++) { + switch (settings[n].type) { + case TEEC_CONTEXT_SETTING_OCALL: + if (!settings[n].u.ocall->handler) + return TEEC_ERROR_BAD_PARAMETERS; + break; + default: + return TEEC_ERROR_BAD_PARAMETERS; + } + } + + res = TEEC_InitializeContext(name, context); + if (res != TEEC_SUCCESS) + return res; + + for (n = 0; n < numSettings; n++) { + switch (settings[n].type) { + case TEEC_CONTEXT_SETTING_OCALL: + if (!context->ocall) { + TEEC_FinalizeContext(context); + return TEEC_ERROR_NOT_SUPPORTED; + } + context->ocall_setting.handler = + settings[n].u.ocall->handler; + context->ocall_setting.data = settings[n].u.ocall->data; + break; + default: + /* Not reached */ + break; + } + } + + return res; +} + void TEEC_FinalizeContext(TEEC_Context *ctx) { if (ctx) @@ -535,6 +606,15 @@ static void uuid_to_octets(uint8_t d[TEE_IOCTL_UUID_LEN], const TEEC_UUID *s) memcpy(d + 8, s->clockSeqAndNode, sizeof(s->clockSeqAndNode)); } +static void uuid_from_octets(TEEC_UUID *d, const uint8_t *s) +{ + d->timeLow = SHIFT_U32(s[0], 24) | SHIFT_U32(s[1], 16) | + SHIFT_U32(s[2], 8) | s[3]; + d->timeMid = SHIFT_U32(s[4], 8) | s[5]; + d->timeHiAndVersion = SHIFT_U32(s[6], 8) | s[7]; + memcpy(d->clockSeqAndNode, s + 8, sizeof(d->clockSeqAndNode)); +} + static void setup_client_data(struct tee_ioctl_open_session_arg *arg, uint32_t connection_method, const void *connection_data) @@ -588,19 +668,383 @@ static void setup_client_data(struct tee_ioctl_open_session_arg *arg, } } +static struct teec_shm_record *teec_find_tsr(int id) +{ + struct teec_shm_record *tsr = NULL; + + SLIST_FOREACH(tsr, &teec_shm_records, next) + if (tsr->shm.id == id) + break; + + return tsr; +} + +static struct teec_shm_record *teec_find_tsr_locked(int id) +{ + struct teec_shm_record *tsr = NULL; + + teec_mutex_lock(&teec_shm_records_mutex); + tsr = teec_find_tsr(id); + teec_mutex_unlock(&teec_shm_records_mutex); + + return tsr; +} + +static TEEC_Result teec_allocate_shared_memory(TEEC_Context *ctx, + TEEC_SharedMemory *shm, + uint32_t reg_flags) +{ + int fd = 0; + size_t s = 0; + + if (!ctx || !shm) + return TEEC_ERROR_BAD_PARAMETERS; + + if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT))) + return TEEC_ERROR_BAD_PARAMETERS; + + s = shm->size; + if (!s) + s = 8; + + if (ctx->reg_mem) { + shm->buffer = teec_paged_aligned_alloc(s); + if (!shm->buffer) + return TEEC_ERROR_OUT_OF_MEMORY; + + fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id, + reg_flags); + if (fd < 0) { + free(shm->buffer); + shm->buffer = NULL; + return TEEC_ERROR_OUT_OF_MEMORY; + } + shm->registered_fd = fd; + } else { + fd = teec_shm_alloc(ctx->fd, s, &shm->id); + if (fd < 0) + return TEEC_ERROR_OUT_OF_MEMORY; + + shm->buffer = mmap(NULL, s, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + close(fd); + if (shm->buffer == (void *)MAP_FAILED) { + shm->id = -1; + return TEEC_ERROR_OUT_OF_MEMORY; + } + shm->registered_fd = -1; + } + + shm->shadow_buffer = NULL; + shm->alloced_size = s; + shm->internal.flags = SHM_FLAG_BUFFER_ALLOCED; + return TEEC_SUCCESS; +} + +static void teec_ocall_process_shm_alloc(TEEC_Session *session, + struct tee_ioctl_param *ip, + uint32_t *ret, uint32_t *ret_origin) +{ + TEEC_Context *ctx = session->ctx; + struct teec_shm_record *tsr; + size_t n; + + *ret_origin = TEEC_ORIGIN_API; + + if (ip[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT) { + *ret = TEEC_ERROR_BAD_PARAMETERS; + return; + } + + for (n = 1; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) { + if (ip[n].attr != TEE_IOCTL_PARAM_ATTR_TYPE_NONE) { + *ret = TEEC_ERROR_BAD_PARAMETERS; + return; + } + } + + tsr = calloc(1, sizeof(*tsr)); + if (!tsr) { + *ret = TEEC_ERROR_OUT_OF_MEMORY; + return; + } + + tsr->shm.size = MEMREF_SIZE(ip); + tsr->shm.flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT; + *ret = teec_allocate_shared_memory(ctx, &tsr->shm, + TEE_IOCTL_SHM_OCALL); + if (*ret != TEEC_SUCCESS) { + free(tsr); + return; + } + + MEMREF_SHM_ID(ip) = tsr->shm.id; + + teec_mutex_lock(&teec_shm_records_mutex); + SLIST_INSERT_HEAD(&teec_shm_records, tsr, next); + teec_mutex_unlock(&teec_shm_records_mutex); + + *ret = TEEC_SUCCESS; +} + +static void teec_ocall_process_shm_free(struct tee_ioctl_param *ip, + uint32_t *ret, uint32_t *ret_origin) +{ + struct teec_shm_record *tsr; + size_t n; + int id; + + *ret_origin = TEEC_ORIGIN_API; + + if (ip[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT) { + *ret = TEEC_ERROR_BAD_PARAMETERS; + return; + } + + for (n = 1; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) { + if (ip[n].attr != TEE_IOCTL_PARAM_ATTR_TYPE_NONE) { + *ret = TEEC_ERROR_BAD_PARAMETERS; + return; + } + } + + if (MEMREF_SHM_ID(ip) > INT_MAX) { + *ret = TEEC_ERROR_SECURITY; + return; + } + + id = (int)MEMREF_SHM_ID(ip); + teec_mutex_lock(&teec_shm_records_mutex); + tsr = teec_find_tsr(id); + if (tsr) + SLIST_REMOVE(&teec_shm_records, tsr, teec_shm_record, next); + teec_mutex_unlock(&teec_shm_records_mutex); + if (!tsr) { + *ret = TEEC_ERROR_ITEM_NOT_FOUND; + return; + } + + TEEC_ReleaseSharedMemory(&tsr->shm); + free(tsr); + + *ret = TEEC_SUCCESS; +} + +static TEEC_Result teec_ocall_preprocess_memref(TEEC_Parameter *param, + TEEC_SharedMemory **shm, + struct tee_ioctl_param *ip) +{ + TEEC_TempMemoryReference *tmpref = ¶m->tmpref; + struct teec_shm_record *tsr; + const uint64_t id = MEMREF_SHM_ID(ip); + const size_t size = MEMREF_SIZE(ip); + const size_t offs = MEMREF_SHM_OFFS(ip); + + if (id == TEE_MEMREF_NULL) { + if (size || offs) + return TEEC_ERROR_BAD_PARAMETERS; + + tmpref->buffer = NULL; + tmpref->size = 0; + + return TEEC_SUCCESS; + } + + if (id > INT_MAX) + return TEEC_ERROR_BAD_PARAMETERS; + + tsr = teec_find_tsr_locked((int)id); + if (!tsr) + return TEEC_ERROR_ITEM_NOT_FOUND; + + if ((offs + size < offs) || (offs + size > tsr->shm.size)) + return TEEC_ERROR_BAD_PARAMETERS; + + tmpref->buffer = PTR_ADD(tsr->shm.buffer, offs); + tmpref->size = size; + + *shm = &tsr->shm; + return TEEC_SUCCESS; +} + +static TEEC_Result teec_ocall_preprocess_invoke(TEEC_Parameter *params, + uint32_t *param_types, + TEEC_SharedMemory **shm, + struct tee_ioctl_param *ip) +{ + TEEC_Result res; + size_t n; + + *param_types = 0; + for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) { + *param_types |= TEEC_PARAM_TYPE_SET(ip[n].attr, n); + switch (ip[n].attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + if (ip[n].a > UINT32_MAX || ip[n].b > UINT32_MAX) + return TEEC_ERROR_BAD_PARAMETERS; + params[n].value.a = (uint32_t)ip[n].a; + params[n].value.b = (uint32_t)ip[n].b; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + res = teec_ocall_preprocess_memref(params + n, shm + n, + ip + n); + if (res) + return res; + break; + default: + return TEEC_ERROR_BAD_PARAMETERS; + } + } + + return TEEC_SUCCESS; +} + +static TEEC_Result teec_ocall_postprocess_memref(TEEC_Parameter *param, + TEEC_SharedMemory *shm, + struct tee_ioctl_param *ip) +{ + TEEC_TempMemoryReference *tmpref = ¶m->tmpref; + const uint64_t id = MEMREF_SHM_ID(ip); + const size_t size = MEMREF_SIZE(ip); + const size_t offs = MEMREF_SHM_OFFS(ip); + + if (id == TEE_MEMREF_NULL) { + if (tmpref->buffer || tmpref->size) + return TEEC_ERROR_BAD_PARAMETERS; + return TEEC_SUCCESS; + } + + if (tmpref->buffer != PTR_ADD(shm->buffer, offs) || tmpref->size > size) + return TEEC_ERROR_BAD_PARAMETERS; + + MEMREF_SIZE(ip) = tmpref->size; + + return TEEC_SUCCESS; +} + +static TEEC_Result teec_ocall_postprocess_invoke(TEEC_Parameter *params, + TEEC_SharedMemory **shm, + struct tee_ioctl_param *ip) +{ + TEEC_Result res; + size_t n; + + for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) { + switch (ip[n].attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + ip[n].a = params[n].value.a; + ip[n].b = params[n].value.b; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + res = teec_ocall_postprocess_memref(params + n, shm[n], + ip + n); + if (res) + return res; + break; + default: + return TEEC_ERROR_BAD_PARAMETERS; + } + } + + return TEEC_SUCCESS; +} + +static void teec_ocall_process_invoke(TEEC_Session *session, + struct tee_ioctl_param *ocall, + struct tee_ioctl_param *ip, + uint32_t *ret, uint32_t *ret_origin) +{ + const TEEC_ContextSettingOCall *os = &session->ctx->ocall_setting; + TEEC_Parameter params[TEEC_CONFIG_PAYLOAD_REF_COUNT]; + TEEC_SharedMemory *shm[TEEC_CONFIG_PAYLOAD_REF_COUNT]; + void *sess_data = session->data_setting.data; + void *ctx_data = os->data; + uint32_t ocall_pt; + TEEC_UUID clnt_id; + TEEC_Result res; + + res = teec_ocall_preprocess_invoke(params, &ocall_pt, shm, ip); + if (res != TEEC_SUCCESS) + goto exit_set_ret_api; + + uuid_from_octets(&clnt_id, (const uint8_t *)&ocall->b); + res = os->handler(&clnt_id, OCALL_CMD(ocall), ocall_pt, params, + ctx_data, sess_data); + if (res != TEEC_SUCCESS) + goto exit_set_ret_ca; + + res = teec_ocall_postprocess_invoke(params, shm, ip); + if (res != TEEC_SUCCESS) + goto exit_set_ret_api; + +exit_set_ret_ca: + *ret = res; + *ret_origin = TEEC_ORIGIN_CLIENT_APP; + return; +exit_set_ret_api: + *ret = res; + *ret_origin = TEEC_ORIGIN_API; +} + +static void teec_handle_ocall(TEEC_Session *session, + struct tee_ioctl_param *ocall, + struct tee_ioctl_param *ip, + uint32_t *ret, uint32_t *ret_origin) +{ + if (!session->ctx->ocall_setting.handler) { + *ret = TEEC_ERROR_BAD_STATE; + *ret_origin = TEEC_ORIGIN_API; + return; + } + + switch (OCALL_FUNC(ocall)) { + case TEE_IOCTL_OCALL_CMD_SHM_ALLOC: + teec_ocall_process_shm_alloc(session, ip, ret, ret_origin); + break; + case TEE_IOCTL_OCALL_CMD_INVOKE: + teec_ocall_process_invoke(session, ocall, ip, ret, ret_origin); + break; + case TEE_IOCTL_OCALL_CMD_SHM_FREE: + teec_ocall_process_shm_free(ip, ret, ret_origin); + break; + default: + *ret = TEEC_ERROR_BAD_PARAMETERS; + *ret_origin = TEEC_ORIGIN_API; + break; + } +} + TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session, const TEEC_UUID *destination, uint32_t connection_method, const void *connection_data, TEEC_Operation *operation, uint32_t *ret_origin) { struct tee_ioctl_open_session_arg *arg = NULL; + struct tee_ioctl_param *normal_params = NULL; + struct tee_ioctl_param *ocall_param = NULL; struct tee_ioctl_param *params = NULL; TEEC_Result res = TEEC_ERROR_GENERIC; uint32_t eorig = 0; int rc = 0; + const TEEC_ContextSettingOCall *os = &ctx->ocall_setting; + const size_t num_meta = os->handler ? 1 : 0; + const size_t num_normal_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + + num_meta; const size_t arg_size = sizeof(struct tee_ioctl_open_session_arg) + - TEEC_CONFIG_PAYLOAD_REF_COUNT * - sizeof(struct tee_ioctl_param); + num_normal_params * + sizeof(struct tee_ioctl_param); union { struct tee_ioctl_open_session_arg arg; uint8_t data[arg_size]; @@ -622,8 +1066,14 @@ TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session, buf_data.buf_len = sizeof(buf); arg = &buf.arg; - arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; - params = (struct tee_ioctl_param *)(arg + 1); + arg->num_params = num_normal_params; + normal_params = (struct tee_ioctl_param *)(arg + 1); + ocall_param = os->handler ? normal_params : NULL; + params = normal_params + num_meta; + + if (ocall_param) + ocall_param->attr = TEE_IOCTL_PARAM_ATTR_OCALL | + TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT; uuid_to_octets(arg->uuid, destination); @@ -635,13 +1085,25 @@ TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session, goto out_free_temp_refs; } - rc = ioctl(ctx->fd, TEE_IOC_OPEN_SESSION, &buf_data); - if (rc) { - EMSG("TEE_IOC_OPEN_SESSION failed"); - eorig = TEEC_ORIGIN_COMMS; - res = ioctl_errno_to_res(errno); - goto out_free_temp_refs; + session->ctx = ctx; + session->data_setting.data = NULL; + for (;;) { + rc = ioctl(ctx->fd, TEE_IOC_OPEN_SESSION, &buf_data); + if (rc) { + EMSG("TEE_IOC_OPEN_SESSION failed"); + eorig = TEEC_ORIGIN_COMMS; + res = ioctl_errno_to_res(errno); + goto out_free_temp_refs; + } + + if (!ocall_param || !OCALL_FUNC(ocall_param)) + break; + + teec_handle_ocall(session, ocall_param, params, &arg->ret, + &arg->ret_origin); } + session->ctx = NULL; + res = arg->ret; eorig = arg->ret_origin; if (res == TEEC_SUCCESS) { @@ -658,6 +1120,50 @@ TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session, return res; } +TEEC_Result TEEC_OpenSession2(TEEC_Context *context, + TEEC_Session *session, + const TEEC_UUID *destination, + uint32_t connectionMethod, + const void *connectionData, + TEEC_Operation *operation, + uint32_t *returnOrigin, + const TEEC_SessionSetting *settings, + uint32_t numSettings) +{ + uint32_t n; + TEEC_Result res; + + if (!settings && numSettings) + return TEEC_ERROR_BAD_PARAMETERS; + + for (n = 0; n < numSettings; n++) { + switch (settings[n].type) { + case TEEC_SESSION_SETTING_DATA: + break; + default: + return TEEC_ERROR_BAD_PARAMETERS; + } + } + + res = TEEC_OpenSession(context, session, destination, connectionMethod, + connectionData, operation, returnOrigin); + if (res != TEEC_SUCCESS) + return res; + + for (n = 0; n < numSettings; n++) { + switch (settings[n].type) { + case TEEC_SESSION_SETTING_DATA: + session->data_setting.data = settings[n].u.data->data; + break; + default: + /* Not reached */ + break; + } + } + + return res; +} + void TEEC_CloseSession(TEEC_Session *session) { struct tee_ioctl_close_session_arg arg; @@ -676,13 +1182,19 @@ TEEC_Result TEEC_InvokeCommand(TEEC_Session *session, uint32_t cmd_id, TEEC_Operation *operation, uint32_t *error_origin) { struct tee_ioctl_invoke_arg *arg = NULL; + struct tee_ioctl_param *normal_params = NULL; + struct tee_ioctl_param *ocall_param = NULL; struct tee_ioctl_param *params = NULL; TEEC_Result res = TEEC_ERROR_GENERIC; uint32_t eorig = 0; int rc = 0; + const TEEC_ContextSettingOCall *os = &session->ctx->ocall_setting; + const size_t num_meta = os->handler ? 1 : 0; + const size_t num_normal_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + + num_meta; const size_t arg_size = sizeof(struct tee_ioctl_invoke_arg) + - TEEC_CONFIG_PAYLOAD_REF_COUNT * - sizeof(struct tee_ioctl_param); + num_normal_params * + sizeof(struct tee_ioctl_param); union { struct tee_ioctl_invoke_arg arg; uint8_t data[arg_size]; @@ -706,8 +1218,14 @@ TEEC_Result TEEC_InvokeCommand(TEEC_Session *session, uint32_t cmd_id, buf_data.buf_len = sizeof(buf); arg = &buf.arg; - arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; - params = (struct tee_ioctl_param *)(arg + 1); + arg->num_params = num_normal_params; + normal_params = (struct tee_ioctl_param *)(arg + 1); + ocall_param = os->handler ? normal_params : NULL; + params = normal_params + num_meta; + + if (ocall_param) + ocall_param->attr = TEE_IOCTL_PARAM_ATTR_OCALL | + TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT; arg->session = session->session_id; arg->func = cmd_id; @@ -724,12 +1242,20 @@ TEEC_Result TEEC_InvokeCommand(TEEC_Session *session, uint32_t cmd_id, goto out_free_temp_refs; } - rc = ioctl(session->ctx->fd, TEE_IOC_INVOKE, &buf_data); - if (rc) { - EMSG("TEE_IOC_INVOKE failed"); - eorig = TEEC_ORIGIN_COMMS; - res = ioctl_errno_to_res(errno); - goto out_free_temp_refs; + for (;;) { + rc = ioctl(session->ctx->fd, TEE_IOC_INVOKE, &buf_data); + if (rc) { + EMSG("TEE_IOC_INVOKE failed"); + eorig = TEEC_ORIGIN_COMMS; + res = ioctl_errno_to_res(errno); + goto out_free_temp_refs; + } + + if (!ocall_param || !OCALL_FUNC(ocall_param)) + break; + + teec_handle_ocall(session, ocall_param, params, &arg->ret, + &arg->ret_origin); } res = arg->ret; @@ -789,7 +1315,8 @@ TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm) if (!s) s = 8; if (ctx->reg_mem) { - fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id); + fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id, + TEE_IOCTL_SHM_NONE); if (fd >= 0) { shm->registered_fd = fd; shm->shadow_buffer = NULL; @@ -810,7 +1337,7 @@ TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm) if (!shm->shadow_buffer) return TEEC_ERROR_OUT_OF_MEMORY; fd = teec_shm_register(ctx->fd, shm->shadow_buffer, s, - &shm->id); + &shm->id, TEE_IOCTL_SHM_NONE); if (fd >= 0) { shm->registered_fd = fd; shm->internal.flags = SHM_FLAG_SHADOW_BUFFER_ALLOCED; @@ -875,50 +1402,7 @@ TEEC_Result TEEC_RegisterSharedMemoryFileDescriptor(TEEC_Context *ctx, TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm) { - int fd = 0; - size_t s = 0; - - if (!ctx || !shm) - return TEEC_ERROR_BAD_PARAMETERS; - - if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT))) - return TEEC_ERROR_BAD_PARAMETERS; - - s = shm->size; - if (!s) - s = 8; - - if (ctx->reg_mem) { - shm->buffer = teec_paged_aligned_alloc(s); - if (!shm->buffer) - return TEEC_ERROR_OUT_OF_MEMORY; - - fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id); - if (fd < 0) { - free(shm->buffer); - shm->buffer = NULL; - return TEEC_ERROR_OUT_OF_MEMORY; - } - shm->registered_fd = fd; - } else { - fd = teec_shm_alloc(ctx->fd, s, &shm->id); - if (fd < 0) - return TEEC_ERROR_OUT_OF_MEMORY; - - shm->buffer = mmap(NULL, s, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - close(fd); - if (shm->buffer == (void *)MAP_FAILED) { - shm->id = -1; - return TEEC_ERROR_OUT_OF_MEMORY; - } - shm->registered_fd = -1; - } - - shm->shadow_buffer = NULL; - shm->alloced_size = s; - shm->internal.flags = SHM_FLAG_BUFFER_ALLOCED; - return TEEC_SUCCESS; + return teec_allocate_shared_memory(ctx, shm, TEE_IOCTL_SHM_NONE); } void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *shm) diff --git a/public/tee_client_api.h b/public/tee_client_api.h index 715ca6bb..77a0d20b 100644 --- a/public/tee_client_api.h +++ b/public/tee_client_api.h @@ -198,11 +198,14 @@ extern "C" { * TEEC_ORIGIN_TEE The error originated within the common TEE code. * TEEC_ORIGIN_TRUSTED_APP The error originated within the Trusted Application * code. + * TEEC_ORIGIN_CLIENT_APP The error originated within the Client Application + * code during an OCALL. */ #define TEEC_ORIGIN_API 0x00000001 #define TEEC_ORIGIN_COMMS 0x00000002 #define TEEC_ORIGIN_TEE 0x00000003 #define TEEC_ORIGIN_TRUSTED_APP 0x00000004 +#define TEEC_ORIGIN_CLIENT_APP 0xF0000001 /** * Session login methods, for use in TEEC_OpenSession() as parameter @@ -246,18 +249,15 @@ extern "C" { */ #define TEEC_PARAM_TYPE_GET(p, i) (((p) >> (i * 4)) & 0xF) -typedef uint32_t TEEC_Result; - /** - * struct TEEC_Context - Represents a connection between a client application - * and a TEE. + * Set the i_th param type in the paramType. + * + * @param p The paramType. + * @param i The i-th parameter to set the type for. */ -typedef struct { - /* Implementation defined */ - int fd; - bool reg_mem; - bool memref_null; -} TEEC_Context; +#define TEEC_PARAM_TYPE_SET(p, i) (((uint32_t)(p) & 0xF) << ((i) * 4)) + +typedef uint32_t TEEC_Result; /** * This type contains a Universally Unique Resource Identifier (UUID) type as @@ -377,6 +377,106 @@ typedef union { TEEC_Value value; } TEEC_Parameter; +/** + * TEEC_Result (*TEEC_OCallHandler) - Type for a CA-provided function to call + * when the TA requests an OCALL. + * + * @param taUUID UUID of the TA whence the OCALL originated. + * @param commandID ID of the command the TA requests the CA execute. + * @param paramTypes Type of data passed by the TA in the OCALL. + * @param params Array of parameters of type TEEC_Parameter. + * @param ctxData Arbitrary CA-provided pointer attached to the TEE + * context. + * @param sessionData Arbitrary CA-provided pointer attached to the session. + */ +typedef TEEC_Result +(*TEEC_OCallHandler)(TEEC_UUID *taUUID, + uint32_t commandId, + uint32_t paramTypes, + TEEC_Parameter params[TEEC_CONFIG_PAYLOAD_REF_COUNT], + void *ctxData, + void *sessionData); + +/** + * enum TEEC_ContextSettingType - List of available settings when initializing a + * context. + */ +typedef enum { + TEEC_CONTEXT_SETTING_OCALL = 1 +} TEEC_ContextSettingType; + +/** + * struct TEEC_ContextSettingOCall - Setting to configure the behaviour of + * OCALLs. + * + * @param handler Pointer to the function to execute to handle an OCALL. + * @param data Arbitrary pointer to pass to the OCALL handler function via + * @ctxData. + */ +typedef struct { + TEEC_OCallHandler handler; + void *data; +} TEEC_ContextSettingOCall; + +/** + * struct TEEC_ContextSetting - A setting to be used when opening a context. + * + * @param type The type of setting this is (i.e., how to interpret the union). + * @param u Union of all possible settings. + */ +typedef struct { + TEEC_ContextSettingType type; + union { + const TEEC_ContextSettingOCall *ocall; + } u; +} TEEC_ContextSetting; + +/** + * struct TEEC_Context - Represents a connection between a client application + * and a TEE. + */ +typedef struct { + /* Implementation defined */ + int fd; + bool reg_mem; + bool memref_null; + bool ocall; + TEEC_ContextSettingOCall ocall_setting; +} TEEC_Context; + +/** + * enum TEEC_SessionSettingType - List of available settings when initializing a + * session. + */ +typedef enum { + TEEC_SESSION_SETTING_DATA = 1 +} TEEC_SessionSettingType; + +/** + * struct TEEC_SessionSettingData - Setting to attach an arbitrary pointer to a + * session; useful when handling OCALLs if per-session data is required by the + * OCALL handler. + * + * @param data Arbitrary pointer to pass to the OCALL handler function via + * @sessionData. + */ +typedef struct { + void *data; +} TEEC_SessionSettingData; + +/** + * struct TEEC_SessionSetting - A setting to be used when opening a session. + * + * @param type The type of setting this is (i.e., how to interpret the union). + * @param u Union of all possible settings. + */ +typedef struct { + TEEC_SessionSettingType type; + union { + const TEEC_SessionSettingData *data; + } u; +} TEEC_SessionSetting; + /** * struct TEEC_Session - Represents a connection between a client application * and a trusted application. @@ -385,6 +485,7 @@ typedef struct { /* Implementation defined */ TEEC_Context *ctx; uint32_t session_id; + TEEC_SessionSettingData data_setting; } TEEC_Session; /** diff --git a/public/tee_client_api_extensions.h b/public/tee_client_api_extensions.h index 85298aad..702a2e09 100644 --- a/public/tee_client_api_extensions.h +++ b/public/tee_client_api_extensions.h @@ -50,6 +50,65 @@ TEEC_Result TEEC_RegisterSharedMemoryFileDescriptor(TEEC_Context *context, TEEC_SharedMemory *sharedMem, int fd); +/** + * TEEC_InitializeContext2() - Behaves the same way as TEEC_InitializeContext + * allowing the caller to attach the specified settings to the resulting + * context. + * + * @param name A zero-terminated string identifying the TEE to connect + * to. If name is set to NULL, the default TEE is connected + * to. NULL is the only supported value in this version of + * the API implementation. + * @param context The context structure which is to be initialized. + * @param settings A list of settings to use to configure the new + * context, or NULL. + * @param numSettings The number of settings, if any. + * + * @return TEEC_SUCCESS The initialization was successful. + * @return TEEC_ERROR_BAD_PARAMETERS One or more parameters are wrong. + * @return TEEC_ERROR_NOT_SUPPORTED One or more settings are not supported. + * @return TEEC_Result Something else failed. + */ +TEEC_Result TEEC_InitializeContext2(const char *name, TEEC_Context *context, + const TEEC_ContextSetting *settings, + uint32_t numSettings); + +/** + * TEEC_OpenSession2() - Behaves the same way as TEEC_OpenSession allowing the + * caller to attach the specified settings to the resulting session. + * + * @param context The initialized TEE context structure in which scope + * to open the session. + * @param session The session to initialize. + * @param destination A structure identifying the trusted application with + * which to open a session. + * @param connectionMethod The connection method to use. + * @param connectionData Any data necessary to connect with the chosen + * connection method. Not supported, should be set to + * NULL. + * @param operation An operation structure to use in the session. May be + * set to NULL to signify no operation structure + * needed. + * @param returnOrigin A parameter which will hold the error origin if this + * function returns any value other than TEEC_SUCCESS. + * @param settings A list of settings to use to configure the new + * session, or NULL. + * @param numSettings The number of settings, if any. + * + * @return TEEC_SUCCESS Successfully opened a new session. + * @return TEEC_ERROR_BAD_PARAMETERS One or more parameters are wrong. + * @return TEEC_Result Something else failed. + */ +TEEC_Result TEEC_OpenSession2(TEEC_Context *context, + TEEC_Session *session, + const TEEC_UUID *destination, + uint32_t connectionMethod, + const void *connectionData, + TEEC_Operation *operation, + uint32_t *returnOrigin, + const TEEC_SessionSetting *settings, + uint32_t numSettings); + #ifdef __cplusplus } #endif diff --git a/typedefs.checkpatch b/typedefs.checkpatch index 84d846ea..2f145dd3 100644 --- a/typedefs.checkpatch +++ b/typedefs.checkpatch @@ -1,15 +1,23 @@ # Note: please keep the entries in this file sorted in reverse alphabetical # order (sort -r) -TEEC_Result -TEEC_Context +TEEC_Value TEEC_UUID -TEEC_SharedMemory TEEC_TempMemoryReference +TEEC_SharedMemory +TEEC_SessionSettingType +TEEC_SessionSettingData +TEEC_SessionSetting +TEEC_Session +TEEC_Result TEEC_RegisteredMemoryReference -TEEC_Value TEEC_Parameter -TEEC_Session TEEC_Operation +TEEC_OCallHandler +TEEC_ContextSettingType +TEEC_ContextSettingOCall +TEEC_ContextSetting +TEEC_Context +SLIST_ENTRY\(.*\) CK_VOID_PTR_PTR CK_VOID_PTR CK_VERSION_PTR @@ -61,9 +69,9 @@ CK_FLAGS CK_DESTROYMUTEX CK_DATE_PTR CK_DATE -CK_CREATEMUTEX CK_C_INITIALIZE_ARGS_PTR CK_C_INITIALIZE_ARGS +CK_CREATEMUTEX CK_CHAR_PTR CK_CHAR CK_CCM_PARAMS_PTR