diff options
-rw-r--r-- | security/tlk_driver/ote_comms.c | 159 | ||||
-rw-r--r-- | security/tlk_driver/ote_device.c | 298 | ||||
-rw-r--r-- | security/tlk_driver/ote_protocol.h | 105 |
3 files changed, 562 insertions, 0 deletions
diff --git a/security/tlk_driver/ote_comms.c b/security/tlk_driver/ote_comms.c index eb9fc688e384..46d7fc679b78 100644 --- a/security/tlk_driver/ote_comms.c +++ b/security/tlk_driver/ote_comms.c @@ -102,6 +102,42 @@ static int te_setup_temp_buffers(struct te_request *request, return ret; } +static int te_setup_temp_buffers_compat(struct te_request_compat *request, + struct tlk_context *context) +{ + uint32_t i; + int ret = OTE_SUCCESS; + struct te_oper_param_compat *params; + + params = (struct te_oper_param_compat *)(uintptr_t)request->params; + for (i = 0; i < request->params_size; i++) { + switch (params[i].type) { + case TE_PARAM_TYPE_NONE: + case TE_PARAM_TYPE_INT_RO: + case TE_PARAM_TYPE_INT_RW: + break; + case TE_PARAM_TYPE_MEM_RO: + case TE_PARAM_TYPE_MEM_RW: + ret = te_pin_mem_buffers( + (void *)(uintptr_t)params[i].u.Mem.base, + params[i].u.Mem.len, + context); + if (ret < 0) { + pr_err("%s failed with err (%d)\n", + __func__, ret); + ret = OTE_ERROR_BAD_PARAMETERS; + break; + } + break; + default: + pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__); + ret = OTE_ERROR_BAD_PARAMETERS; + break; + } + } + return ret; +} + static void te_del_shmem_desc(void *buffer, struct tlk_context *context) { struct te_shmem_desc *shmem_desc, *tmp_shmem_desc; @@ -150,6 +186,32 @@ static void te_unpin_temp_buffers(struct te_request *request, } } +static void te_unpin_temp_buffers_compat(struct te_request_compat *request, + struct tlk_context *context) +{ + uint32_t i; + struct te_oper_param_compat *params; + + params = (struct te_oper_param_compat *)(uintptr_t)request->params; + for (i = 0; i < request->params_size; i++) { + switch (params[i].type) { + case TE_PARAM_TYPE_NONE: + case TE_PARAM_TYPE_INT_RO: + case TE_PARAM_TYPE_INT_RW: + break; + case TE_PARAM_TYPE_MEM_RO: + case TE_PARAM_TYPE_MEM_RW: + te_unregister_memory( + (void *)(uintptr_t)params[i].u.Mem.base, + context); + break; + default: + pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__); + break; + } + } +} + #ifdef CONFIG_SMP cpumask_t saved_cpu_mask; static void switch_cpumask_to_cpu0(void) @@ -278,6 +340,30 @@ static void do_smc(struct te_request *request, struct tlk_device *dev) } /* + * Do an SMC call + */ +static void do_smc_compat(struct te_request_compat *request, + struct tlk_device *dev) +{ + uint32_t smc_args; + uint32_t smc_params = 0; + + smc_args = (char *)request - dev->req_param_buf; + if (request->params) { + smc_params = + (char *)(uintptr_t)request->params - dev->req_param_buf; + } + + tlk_generic_smc(request->type, smc_args, smc_params); + + /* + * Check to see if there are any logs in written by TLK. + * If there are, print them out. + */ + ote_print_logs(); +} + +/* * VPR programming SMC */ int te_set_vpr_params(void *vpr_base, size_t vpr_size) @@ -373,6 +459,79 @@ void te_launch_operation(struct te_launchop *cmd, te_unpin_temp_buffers(request, context); } +/* + * Open session SMC (supporting client-based te_open_session() calls) + */ +void te_open_session_compat(struct te_opensession_compat *cmd, + struct te_request_compat *request, + struct tlk_context *context) +{ + int ret; + + ret = te_setup_temp_buffers_compat(request, context); + if (ret != OTE_SUCCESS) { + pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret); + SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API); + return; + } + + memcpy(&request->dest_uuid, + &cmd->dest_uuid, + sizeof(struct te_service_id)); + + pr_info("OPEN_CLIENT_SESSION_COMPAT: 0x%x 0x%x 0x%x 0x%x\n", + request->dest_uuid[0], + request->dest_uuid[1], + request->dest_uuid[2], + request->dest_uuid[3]); + + request->type = TE_SMC_OPEN_SESSION; + + do_smc_compat(request, context->dev); + + te_unpin_temp_buffers_compat(request, context); +} + +/* + * Close session SMC (supporting client-based te_close_session() calls) + */ +void te_close_session_compat(struct te_closesession_compat *cmd, + struct te_request_compat *request, + struct tlk_context *context) +{ + request->session_id = cmd->session_id; + request->type = TE_SMC_CLOSE_SESSION; + + do_smc_compat(request, context->dev); + if (request->result) + pr_info("Error closing session: %08x\n", request->result); +} + +/* + * Launch operation SMC (supporting client-based te_launch_operation() calls) + */ +void te_launch_operation_compat(struct te_launchop_compat *cmd, + struct te_request_compat *request, + struct tlk_context *context) +{ + int ret; + + ret = te_setup_temp_buffers_compat(request, context); + if (ret != OTE_SUCCESS) { + pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret); + SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API); + return; + } + + request->session_id = cmd->session_id; + request->command_id = cmd->operation.command; + request->type = TE_SMC_LAUNCH_OPERATION; + + do_smc_compat(request, context->dev); + + te_unpin_temp_buffers_compat(request, context); +} + static int __init tlk_register_irq_handler(void) { tlk_generic_smc(TE_SMC_REGISTER_IRQ_HANDLER, diff --git a/security/tlk_driver/ote_device.c b/security/tlk_driver/ote_device.c index 03fa1acc2129..170f46c06e14 100644 --- a/security/tlk_driver/ote_device.c +++ b/security/tlk_driver/ote_device.c @@ -41,6 +41,7 @@ static int te_create_free_cmd_list(struct tlk_device *dev) { int cmd_desc_count, ret = 0; struct te_cmd_req_desc *req_desc; + struct te_cmd_req_desc_compat *req_desc_compat; int bitmap_size; bool use_reqbuf; @@ -80,6 +81,12 @@ static int te_create_free_cmd_list(struct tlk_device *dev) goto error; } + /* requests in the first page, params in the second */ + dev->req_addr_compat = (struct te_request_compat *) + dev->req_param_buf; + dev->param_addr_compat = (struct te_oper_param_compat *) + (dev->req_param_buf + PAGE_SIZE); + /* alloc param bitmap allocator */ bitmap_size = BITS_TO_LONGS(TE_PARAM_MAX) * sizeof(long); dev->param_bitmap = kzalloc(bitmap_size, GFP_KERNEL); @@ -99,6 +106,25 @@ static int te_create_free_cmd_list(struct tlk_device *dev) /* Add the cmd param descriptor to free list */ list_add_tail(&req_desc->list, &(dev->free_cmd_list)); } + + for (cmd_desc_count = 0; + cmd_desc_count < TE_CMD_DESC_MAX_COMPAT; cmd_desc_count++) { + + req_desc_compat = kzalloc(sizeof(struct te_cmd_req_desc_compat), + GFP_KERNEL); + if (req_desc_compat == NULL) { + pr_err("Failed to allocate cmd req descriptor\n"); + ret = -ENOMEM; + goto error; + } + req_desc_compat->req_addr = + dev->req_addr_compat + cmd_desc_count; + INIT_LIST_HEAD(&(req_desc_compat->list)); + + /* Add the cmd param descriptor to free list */ + list_add_tail(&req_desc_compat->list, &(dev->free_cmd_list)); + } + error: return ret; } @@ -129,6 +155,32 @@ static void te_put_free_params(struct tlk_device *dev, bitmap_release_region(dev->param_bitmap, idx, nbits); } +static struct te_oper_param_compat * + te_get_free_params_compat(struct tlk_device *dev, unsigned int nparams) +{ + struct te_oper_param_compat *params = NULL; + int idx, nbits; + + if (nparams) { + nbits = get_count_order(nparams); + idx = bitmap_find_free_region(dev->param_bitmap, + TE_PARAM_MAX, nbits); + if (idx >= 0) + params = dev->param_addr_compat + idx; + } + return params; +} + +static void te_put_free_params_compat(struct tlk_device *dev, + struct te_oper_param_compat *params, uint32_t nparams) +{ + int idx, nbits; + + idx = (params - dev->param_addr_compat); + nbits = get_count_order(nparams); + bitmap_release_region(dev->param_bitmap, idx, nbits); +} + static struct te_cmd_req_desc *te_get_free_cmd_desc(struct tlk_device *dev) { struct te_cmd_req_desc *cmd_desc = NULL; @@ -159,6 +211,37 @@ static void te_put_used_cmd_desc(struct tlk_device *dev, } } +static struct te_cmd_req_desc_compat * +te_get_free_cmd_desc_compat(struct tlk_device *dev) +{ + struct te_cmd_req_desc_compat *cmd_desc = NULL; + + if (!(list_empty(&(dev->free_cmd_list)))) { + cmd_desc = list_first_entry(&(dev->free_cmd_list), + struct te_cmd_req_desc_compat, list); + list_del(&(cmd_desc->list)); + list_add_tail(&cmd_desc->list, &(dev->used_cmd_list)); + } + return cmd_desc; +} + +static void te_put_used_cmd_desc_compat(struct tlk_device *dev, + struct te_cmd_req_desc_compat *cmd_desc) +{ + struct te_cmd_req_desc_compat *param_desc, *tmp_param_desc; + + if (cmd_desc) { + list_for_each_entry_safe(param_desc, tmp_param_desc, + &(dev->used_cmd_list), list) { + if (cmd_desc->req_addr == param_desc->req_addr) { + list_del(¶m_desc->list); + list_add_tail(¶m_desc->list, + &(dev->free_cmd_list)); + } + } + } +} + static void __attribute__((unused)) te_print_cmd_list( struct tlk_device *dev, int used_list) { @@ -403,6 +486,209 @@ error: return err; } +static int copy_params_from_user_compat(struct te_request_compat *req, + struct te_operation_compat *operation) +{ + struct te_oper_param_compat *param_array; + struct te_oper_param_compat *user_param; + uint32_t i; + + if (operation->list_count == 0) + return 0; + + param_array = (struct te_oper_param_compat *)(uintptr_t)req->params; + if (param_array == NULL) { + pr_err("param_array empty\n"); + return 1; + } + + user_param = (struct te_oper_param_compat *)(uintptr_t) + operation->list_head; + for (i = 0; i < operation->list_count && user_param != NULL; i++) { + if (copy_from_user(param_array + i, user_param, + sizeof(struct te_oper_param_compat))) { + pr_err("Failed to copy operation parameter:%d, %p, " \ + "list_count: %d\n", + i, user_param, operation->list_count); + return 1; + } + user_param = (struct te_oper_param_compat *)(uintptr_t) + param_array[i].next_ptr_user; + } + return 0; +} + +static int copy_params_to_user_compat(struct te_request_compat *req, + struct te_operation_compat *operation) +{ + struct te_oper_param_compat *param_array; + struct te_oper_param_compat *user_param; + uint32_t i; + + if (operation->list_count == 0) + return 0; + + param_array = + (struct te_oper_param_compat *)(uintptr_t)req->params; + if (param_array == NULL) { + pr_err("param_array empty\n"); + return 1; + } + + user_param = + (struct te_oper_param_compat *)(uintptr_t)operation->list_head; + for (i = 0; i < req->params_size; i++) { + if (copy_to_user(user_param, param_array + i, + sizeof(struct te_oper_param_compat))) { + pr_err("Failed to copy back parameter:%d %p\n", i, + user_param); + return 1; + } + user_param = (struct te_oper_param_compat *)(uintptr_t) + param_array[i].next_ptr_user; + } + return 0; +} + +static long te_handle_trustedapp_ioctl_compat(struct file *file, + unsigned int ioctl_num, unsigned long ioctl_param) +{ + long err = 0; + union te_cmd_compat cmd_compat; + struct te_operation_compat *operation = NULL; + struct te_oper_param_compat *params = NULL; + struct te_request_compat *request; + void __user *ptr_user_answer = NULL; + struct te_answer answer; + struct te_cmd_req_desc_compat *cmd_desc = NULL; + struct tlk_context *context = file->private_data; + struct tlk_device *dev = context->dev; + + if (copy_from_user(&cmd_compat, (void __user *)ioctl_param, + sizeof(union te_cmd_compat))) { + pr_err("Failed to copy command request\n"); + err = -EFAULT; + goto error; + } + + memset(&answer, 0, sizeof(struct te_answer)); + + switch (ioctl_num) { + case TE_IOCTL_OPEN_CLIENT_SESSION_COMPAT: + operation = &cmd_compat.opensession.operation; + ptr_user_answer = (void *)(uintptr_t) + cmd_compat.opensession.answer; + + cmd_desc = te_get_free_cmd_desc_compat(dev); + params = te_get_free_params_compat(dev, operation->list_count); + + if (!cmd_desc || (operation->list_count && !params)) { + SET_ANSWER(answer, + OTE_ERROR_OUT_OF_MEMORY, + OTE_RESULT_ORIGIN_COMMS); + pr_err("failed to get cmd_desc/params\n"); + goto error; + } + + request = cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request_compat)); + + request->params = (uintptr_t)params; + request->params_size = operation->list_count; + + if (copy_params_from_user_compat(request, operation)) { + err = -EFAULT; + pr_info("failed to copy params from user\n"); + goto error; + } + + te_open_session_compat(&cmd_compat.opensession, + request, context); + + SET_ANSWER(answer, request->result, request->result_origin); + answer.session_id = request->session_id; + break; + + case TE_IOCTL_CLOSE_CLIENT_SESSION_COMPAT: + ptr_user_answer = (void *)(uintptr_t) + cmd_compat.closesession.answer; + cmd_desc = te_get_free_cmd_desc_compat(dev); + if (!cmd_desc) { + SET_ANSWER(answer, + OTE_ERROR_OUT_OF_MEMORY, + OTE_RESULT_ORIGIN_COMMS); + pr_err("failed to get cmd_desc\n"); + goto error; + } + + request = cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request_compat)); + + /* close session cannot fail */ + te_close_session_compat(&cmd_compat.closesession, + request, context); + break; + + case TE_IOCTL_LAUNCH_OPERATION_COMPAT: + operation = &cmd_compat.launchop.operation; + ptr_user_answer = (void *)(uintptr_t)cmd_compat.launchop.answer; + + cmd_desc = te_get_free_cmd_desc_compat(dev); + params = te_get_free_params_compat(dev, operation->list_count); + + if (!cmd_desc || (operation->list_count && !params)) { + SET_ANSWER(answer, + OTE_ERROR_OUT_OF_MEMORY, + OTE_RESULT_ORIGIN_COMMS); + pr_err("failed to get cmd_desc/params\n"); + goto error; + } + + request = cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request_compat)); + + request->params = (uintptr_t)params; + request->params_size = operation->list_count; + + if (copy_params_from_user_compat(request, operation)) { + err = -EFAULT; + pr_info("failed to copy params from user\n"); + goto error; + } + + te_launch_operation_compat(&cmd_compat.launchop, + request, context); + + SET_ANSWER(answer, request->result, request->result_origin); + break; + + default: + pr_err("Invalid IOCTL Cmd\n"); + err = -EINVAL; + goto error; + } + if (ptr_user_answer && !err) { + if (copy_to_user(ptr_user_answer, &answer, + sizeof(struct te_answer))) { + pr_err("Failed to copy answer\n"); + err = -EFAULT; + } + } + if (request->params && !err) { + if (copy_params_to_user_compat(request, operation)) { + pr_err("Failed to copy return params\n"); + err = -EFAULT; + } + } + +error: + if (cmd_desc) + te_put_used_cmd_desc_compat(dev, cmd_desc); + if (params) + te_put_free_params_compat(dev, params, operation->list_count); + return err; +} + static long tlk_device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { @@ -417,6 +703,15 @@ static long tlk_device_ioctl(struct file *file, unsigned int ioctl_num, mutex_unlock(&smc_lock); break; + case TE_IOCTL_OPEN_CLIENT_SESSION_COMPAT: + case TE_IOCTL_CLOSE_CLIENT_SESSION_COMPAT: + case TE_IOCTL_LAUNCH_OPERATION_COMPAT: + mutex_lock(&smc_lock); + err = te_handle_trustedapp_ioctl_compat(file, ioctl_num, + ioctl_param); + mutex_unlock(&smc_lock); + break; + case TE_IOCTL_FILE_NEW_REQ: case TE_IOCTL_FILE_FILL_BUF: case TE_IOCTL_FILE_REQ_COMPLETE: @@ -446,6 +741,9 @@ static const struct file_operations tlk_device_fops = { .open = tlk_device_open, .release = tlk_device_release, .unlocked_ioctl = tlk_device_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = tlk_device_ioctl, +#endif }; struct miscdevice tlk_misc_device = { diff --git a/security/tlk_driver/ote_protocol.h b/security/tlk_driver/ote_protocol.h index f74e1734df7a..66228e4a9eaa 100644 --- a/security/tlk_driver/ote_protocol.h +++ b/security/tlk_driver/ote_protocol.h @@ -28,6 +28,15 @@ _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x11, union te_cmd) #define TE_IOCTL_LAUNCH_OPERATION \ _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x14, union te_cmd) + +/* ioctls using new structs (eventually to replace current ioctls) */ +#define TE_IOCTL_OPEN_CLIENT_SESSION_COMPAT \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x10, union te_cmd_compat) +#define TE_IOCTL_CLOSE_CLIENT_SESSION_COMPAT \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x11, union te_cmd_compat) +#define TE_IOCTL_LAUNCH_OPERATION_COMPAT \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x14, union te_cmd_compat) + #define TE_IOCTL_FILE_NEW_REQ \ _IOR(TE_IOCTL_MAGIC_NUMBER, 0x16, struct te_file_req) #define TE_IOCTL_FILE_FILL_BUF \ @@ -46,6 +55,11 @@ #define TE_CMD_DESC_MAX (PAGE_SIZE / sizeof(struct te_request)) #define TE_PARAM_MAX (PAGE_SIZE / sizeof(struct te_oper_param)) +#define TE_CMD_DESC_MAX_COMPAT \ + (PAGE_SIZE / sizeof(struct te_request_compat)) +#define TE_PARAM_MAX_COMPAT \ + (PAGE_SIZE / sizeof(struct te_oper_param_compat)) + #define MAX_EXT_SMC_ARGS 12 extern struct mutex smc_lock; @@ -60,6 +74,9 @@ struct tlk_device { struct te_oper_param *param_addr; dma_addr_t param_addr_phys; + struct te_request_compat *req_addr_compat; + struct te_oper_param_compat *param_addr_compat; + char *req_param_buf; unsigned long *param_bitmap; @@ -73,6 +90,11 @@ struct te_cmd_req_desc { struct list_head list; }; +struct te_cmd_req_desc_compat { + struct te_request_compat *req_addr; + struct list_head list; +}; + struct te_shmem_desc { struct list_head list; void *buffer; @@ -126,6 +148,21 @@ struct te_oper_param { void *next_ptr_user; }; +struct te_oper_param_compat { + uint32_t index; + uint32_t type; + union { + struct { + uint32_t val; + } Int; + struct { + uint64_t base; + uint32_t len; + } Mem; + } u; + uint64_t next_ptr_user; +}; + struct te_operation { uint32_t command; struct te_oper_param *list_head; @@ -175,6 +212,51 @@ union te_cmd { struct te_launchop launchop; }; +/* + * Compat versions of the original structs (eventually to replace + * the old structs, once the lib/TLK kernel changes are in). + */ +struct te_operation_compat { + uint32_t command; + uint32_t status; + uint64_t list_head; + uint64_t list_tail; + uint32_t list_count; + uint32_t interface_side; +}; + +/* + * OpenSession + */ +struct te_opensession_compat { + struct te_service_id dest_uuid; + struct te_operation_compat operation; + uint64_t answer; +}; + +/* + * CloseSession + */ +struct te_closesession_compat { + uint32_t session_id; + uint64_t answer; +}; + +/* + * LaunchOperation + */ +struct te_launchop_compat { + uint32_t session_id; + struct te_operation_compat operation; + uint64_t answer; +}; + +union te_cmd_compat { + struct te_opensession_compat opensession; + struct te_closesession_compat closesession; + struct te_launchop_compat launchop; +}; + struct te_request { uint32_t type; uint32_t session_id; @@ -186,6 +268,17 @@ struct te_request { uint32_t result_origin; }; +struct te_request_compat { + uint32_t type; + uint32_t session_id; + uint32_t command_id; + uint64_t params; + uint32_t params_size; + uint32_t dest_uuid[4]; + uint32_t result; + uint32_t result_origin; +}; + struct te_answer { uint32_t result; uint32_t session_id; @@ -204,6 +297,18 @@ void te_launch_operation(struct te_launchop *cmd, struct te_request *request, struct tlk_context *context); +void te_open_session_compat(struct te_opensession_compat *cmd, + struct te_request_compat *request, + struct tlk_context *context); + +void te_close_session_compat(struct te_closesession_compat *cmd, + struct te_request_compat *request, + struct tlk_context *context); + +void te_launch_operation_compat(struct te_launchop_compat *cmd, + struct te_request_compat *request, + struct tlk_context *context); + #define TE_MAX_FILE_NAME_LEN 64 enum te_file_req_type { |