diff options
Diffstat (limited to 'drivers/tee')
| -rw-r--r-- | drivers/tee/amdtee/amdtee_private.h | 16 | ||||
| -rw-r--r-- | drivers/tee/amdtee/call.c | 2 | ||||
| -rw-r--r-- | drivers/tee/amdtee/core.c | 52 | ||||
| -rw-r--r-- | drivers/tee/optee/call.c | 3 | ||||
| -rw-r--r-- | drivers/tee/optee/optee_msg.h | 50 | ||||
| -rw-r--r-- | drivers/tee/optee/optee_private.h | 120 | ||||
| -rw-r--r-- | drivers/tee/optee/supp.c | 107 | ||||
| -rw-r--r-- | drivers/tee/qcomtee/core.c | 6 | ||||
| -rw-r--r-- | drivers/tee/tee_core.c | 56 | ||||
| -rw-r--r-- | drivers/tee/tee_shm.c | 2 |
10 files changed, 203 insertions, 211 deletions
diff --git a/drivers/tee/amdtee/amdtee_private.h b/drivers/tee/amdtee/amdtee_private.h index d87050033894..2c5ba02258b8 100644 --- a/drivers/tee/amdtee/amdtee_private.h +++ b/drivers/tee/amdtee/amdtee_private.h @@ -65,13 +65,9 @@ struct amdtee_session { /** * struct amdtee_context_data - AMD-TEE driver context data * @sess_list: Keeps track of sessions opened in current TEE context - * @shm_list: Keeps track of buffers allocated and mapped in current TEE - * context */ struct amdtee_context_data { struct list_head sess_list; - struct list_head shm_list; - struct mutex shm_mutex; /* synchronizes access to @shm_list */ }; struct amdtee_driver_data { @@ -84,17 +80,6 @@ struct shmem_desc { }; /** - * struct amdtee_shm_data - Shared memory data - * @kaddr: Kernel virtual address of shared memory - * @buf_id: Buffer id of memory mapped by TEE_CMD_ID_MAP_SHARED_MEM - */ -struct amdtee_shm_data { - struct list_head shm_node; - void *kaddr; - u32 buf_id; -}; - -/** * struct amdtee_ta_data - Keeps track of all TAs loaded in AMD Secure * Processor * @ta_handle: Handle to TA loaded in TEE @@ -168,5 +153,4 @@ int handle_invoke_cmd(struct tee_ioctl_invoke_arg *arg, u32 sinfo, struct tee_shm_pool *amdtee_config_shm(void); -u32 get_buffer_id(struct tee_shm *shm); #endif /*AMDTEE_PRIVATE_H*/ diff --git a/drivers/tee/amdtee/call.c b/drivers/tee/amdtee/call.c index 441b2ceaafc3..23ccd0f037a7 100644 --- a/drivers/tee/amdtee/call.c +++ b/drivers/tee/amdtee/call.c @@ -45,7 +45,7 @@ static int tee_params_to_amd_params(struct tee_param *tee, u32 count, /* It is assumed that all values are within 2^32-1 */ if (type > TEE_OP_PARAM_TYPE_VALUE_INOUT) { - u32 buf_id = get_buffer_id(tee[i].u.memref.shm); + u32 buf_id = (u32)tee[i].u.memref.shm->sec_world_id; amd->params[i].mref.buf_id = buf_id; amd->params[i].mref.offset = tee[i].u.memref.shm_offs; diff --git a/drivers/tee/amdtee/core.c b/drivers/tee/amdtee/core.c index a1347d04b3ac..0e56f4cf2697 100644 --- a/drivers/tee/amdtee/core.c +++ b/drivers/tee/amdtee/core.c @@ -43,8 +43,6 @@ static int amdtee_open(struct tee_context *ctx) return -ENOMEM; INIT_LIST_HEAD(&ctxdata->sess_list); - INIT_LIST_HEAD(&ctxdata->shm_list); - mutex_init(&ctxdata->shm_mutex); ctx->data = ctxdata; return 0; @@ -87,7 +85,6 @@ static void amdtee_release(struct tee_context *ctx) list_del(&sess->list_node); release_session(sess); } - mutex_destroy(&ctxdata->shm_mutex); kfree(ctxdata); ctx->data = NULL; @@ -152,23 +149,6 @@ static struct amdtee_session *find_session(struct amdtee_context_data *ctxdata, return NULL; } -u32 get_buffer_id(struct tee_shm *shm) -{ - struct amdtee_context_data *ctxdata = shm->ctx->data; - struct amdtee_shm_data *shmdata; - u32 buf_id = 0; - - mutex_lock(&ctxdata->shm_mutex); - list_for_each_entry(shmdata, &ctxdata->shm_list, shm_node) - if (shmdata->kaddr == shm->kaddr) { - buf_id = shmdata->buf_id; - break; - } - mutex_unlock(&ctxdata->shm_mutex); - - return buf_id; -} - static DEFINE_MUTEX(drv_mutex); static int copy_ta_binary(struct tee_context *ctx, void *ptr, void **ta, size_t *ta_size) @@ -342,8 +322,6 @@ int amdtee_close_session(struct tee_context *ctx, u32 session) int amdtee_map_shmem(struct tee_shm *shm) { - struct amdtee_context_data *ctxdata; - struct amdtee_shm_data *shmnode; struct shmem_desc shmem; int rc, count; u32 buf_id; @@ -351,10 +329,6 @@ int amdtee_map_shmem(struct tee_shm *shm) if (!shm) return -EINVAL; - shmnode = kmalloc_obj(*shmnode); - if (!shmnode) - return -ENOMEM; - count = 1; shmem.kaddr = shm->kaddr; shmem.size = shm->size; @@ -366,44 +340,26 @@ int amdtee_map_shmem(struct tee_shm *shm) rc = handle_map_shmem(count, &shmem, &buf_id); if (rc) { pr_err("map_shmem failed: ret = %d\n", rc); - kfree(shmnode); return rc; } - shmnode->kaddr = shm->kaddr; - shmnode->buf_id = buf_id; - ctxdata = shm->ctx->data; - mutex_lock(&ctxdata->shm_mutex); - list_add(&shmnode->shm_node, &ctxdata->shm_list); - mutex_unlock(&ctxdata->shm_mutex); + shm->sec_world_id = buf_id; - pr_debug("buf_id :[%x] kaddr[%p]\n", shmnode->buf_id, shmnode->kaddr); + pr_debug("buf_id :[%x] kaddr[%p]\n", buf_id, shm->kaddr); return 0; } void amdtee_unmap_shmem(struct tee_shm *shm) { - struct amdtee_context_data *ctxdata; - struct amdtee_shm_data *shmnode; u32 buf_id; if (!shm) return; - buf_id = get_buffer_id(shm); - /* Unmap the shared memory from TEE */ + buf_id = (u32)shm->sec_world_id; handle_unmap_shmem(buf_id); - - ctxdata = shm->ctx->data; - mutex_lock(&ctxdata->shm_mutex); - list_for_each_entry(shmnode, &ctxdata->shm_list, shm_node) - if (buf_id == shmnode->buf_id) { - list_del(&shmnode->shm_node); - kfree(shmnode); - break; - } - mutex_unlock(&ctxdata->shm_mutex); + shm->sec_world_id = 0; } int amdtee_invoke_func(struct tee_context *ctx, diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index 9effe88049e9..e046aff61828 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -602,7 +602,8 @@ static bool is_normal_memory(pgprot_t p) return (((pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEALLOC) || ((pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEBACK)); #elif defined(CONFIG_ARM64) - return (pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL); + return ((pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL)) || + ((pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED)); #else #error "Unsupported architecture" #endif diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h index 838e1d4a22f0..7d9b12e71c03 100644 --- a/drivers/tee/optee/optee_msg.h +++ b/drivers/tee/optee/optee_msg.h @@ -103,9 +103,9 @@ /** * struct optee_msg_param_tmem - temporary memory reference parameter - * @buf_ptr: Address of the buffer - * @size: Size of the buffer - * @shm_ref: Temporary shared memory reference, pointer to a struct tee_shm + * @buf_ptr: address of the buffer + * @size: size of the buffer + * @shm_ref: temporary shared memory reference, pointer to a struct tee_shm * * Secure and normal world communicates pointers as physical address * instead of the virtual address. This is because secure and normal world @@ -122,9 +122,9 @@ struct optee_msg_param_tmem { /** * struct optee_msg_param_rmem - registered memory reference parameter - * @offs: Offset into shared memory reference - * @size: Size of the buffer - * @shm_ref: Shared memory reference, pointer to a struct tee_shm + * @offs: offset into shared memory reference + * @size: size of the buffer + * @shm_ref: shared memory reference, pointer to a struct tee_shm */ struct optee_msg_param_rmem { u64 offs; @@ -134,12 +134,12 @@ struct optee_msg_param_rmem { /** * struct optee_msg_param_fmem - FF-A memory reference parameter - * @offs_lower: Lower bits of offset into shared memory reference - * @offs_upper: Upper bits of offset into shared memory reference - * @internal_offs: Internal offset into the first page of shared memory - * reference - * @size: Size of the buffer - * @global_id: Global identifier of the shared memory + * @offs_low: lower bits of offset into shared memory reference + * @offs_high: higher bits of offset into shared memory reference + * @internal_offs: internal offset into the first page of shared memory + * reference + * @size: size of the buffer + * @global_id: global identifier of the shared memory */ struct optee_msg_param_fmem { u32 offs_low; @@ -151,6 +151,9 @@ struct optee_msg_param_fmem { /** * struct optee_msg_param_value - opaque value parameter + * @a: first opaque value + * @b: second opaque value + * @c: third opaque value * * Value parameters are passed unchecked between normal and secure world. */ @@ -168,6 +171,7 @@ struct optee_msg_param_value { * @fmem: parameter by FF-A registered memory reference * @value: parameter by opaque value * @octets: parameter by octet string + * @u: union holding OP-TEE msg parameter * * @attr & OPTEE_MSG_ATTR_TYPE_MASK indicates if tmem, rmem or value is used in * the union. OPTEE_MSG_ATTR_TYPE_VALUE_* indicates value or octets, @@ -189,16 +193,18 @@ struct optee_msg_param { /** * struct optee_msg_arg - call argument - * @cmd: Command, one of OPTEE_MSG_CMD_* or OPTEE_MSG_RPC_CMD_* - * @func: Trusted Application function, specific to the Trusted Application, - * used if cmd == OPTEE_MSG_CMD_INVOKE_COMMAND - * @session: In parameter for all OPTEE_MSG_CMD_* except - * OPTEE_MSG_CMD_OPEN_SESSION where it's an output parameter instead - * @cancel_id: Cancellation id, a unique value to identify this request - * @ret: return value - * @ret_origin: origin of the return value - * @num_params: number of parameters supplied to the OS Command - * @params: the parameters supplied to the OS Command + * @cmd: command, one of OPTEE_MSG_CMD_* or OPTEE_MSG_RPC_CMD_* + * @func: Trusted Application function, specific to the Trusted + * Application, used if cmd == OPTEE_MSG_CMD_INVOKE_COMMAND + * @session: in parameter for all OPTEE_MSG_CMD_* except + * OPTEE_MSG_CMD_OPEN_SESSION where it's an output parameter + * instead + * @cancel_id: cancellation id, a unique value to identify this request + * @pad: padding for alignment + * @ret: return value + * @ret_origin: origin of the return value + * @num_params: number of parameters supplied to the OS Command + * @params: the parameters supplied to the OS Command * * All normal calls to Trusted OS uses this struct. If cmd requires further * information than what these fields hold it can be passed as a parameter diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index acd3051c4879..aefe1e6f5689 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -47,11 +47,11 @@ typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, struct arm_smccc_res *); -/* +/** * struct optee_call_waiter - TEE entry may need to wait for a free TEE thread - * @list_node Reference in waiters list - * @c Waiting completion reference - * @sys_thread True if waiter belongs to a system thread + * @list_node: reference in waiters list + * @c: waiting completion reference + * @sys_thread: true if waiter belongs to a system thread */ struct optee_call_waiter { struct list_head list_node; @@ -59,13 +59,13 @@ struct optee_call_waiter { bool sys_thread; }; -/* +/** * struct optee_call_queue - OP-TEE call queue management - * @mutex Serializes access to this struct - * @waiters List of threads waiting to enter OP-TEE - * @total_thread_count Overall number of thread context in OP-TEE or 0 - * @free_thread_count Number of threads context free in OP-TEE - * @sys_thread_req_count Number of registered system thread sessions + * @mutex: serializes access to this struct + * @waiters: list of threads waiting to enter OP-TEE + * @total_thread_count: overall number of thread context in OP-TEE or 0 + * @free_thread_count: number of threads context free in OP-TEE + * @sys_thread_req_count: number of registered system thread sessions */ struct optee_call_queue { /* Serializes access to this struct */ @@ -96,17 +96,17 @@ struct optee_shm_arg_cache { /** * struct optee_supp - supplicant synchronization struct - * @ctx the context of current connected supplicant. - * if !NULL the supplicant device is available for use, - * else busy - * @mutex: held while accessing content of this struct - * @req_id: current request id if supplicant is doing synchronous - * communication, else -1 - * @reqs: queued request not yet retrieved by supplicant - * @idr: IDR holding all requests currently being processed - * by supplicant - * @reqs_c: completion used by supplicant when waiting for a - * request to be queued. + * @mutex: held while accessing content of this struct + * @ctx: the context of current connected supplicant. + * if !NULL the supplicant device is available for use, + * else busy + * @req_id: current request id if supplicant is doing synchronous + * communication, else -1 + * @reqs: queued request not yet retrieved by supplicant + * @idr: IDR holding all requests currently being processed + * by supplicant + * @reqs_c: completion used by supplicant when waiting for a + * request to be queued. */ struct optee_supp { /* Serializes access to this struct */ @@ -119,25 +119,25 @@ struct optee_supp { struct completion reqs_c; }; -/* +/** * struct optee_pcpu - per cpu notif private struct passed to work functions - * @optee optee device reference + * @optee: optee device reference */ struct optee_pcpu { struct optee *optee; }; -/* +/** * struct optee_smc - optee smc communication struct - * @invoke_fn handler function to invoke secure monitor - * @memremaped_shm virtual address of memory in shared memory pool + * @invoke_fn: handler function to invoke secure monitor + * @memremaped_shm: virtual address of memory in shared memory pool * @sec_caps: secure world capabilities defined by * OPTEE_SMC_SEC_CAP_* in optee_smc.h - * @notif_irq interrupt used as async notification by OP-TEE or 0 - * @optee_pcpu per_cpu optee instance for per cpu work or NULL - * @notif_pcpu_wq workqueue for per cpu asynchronous notification or NULL - * @notif_pcpu_work work for per cpu asynchronous notification - * @notif_cpuhp_state CPU hotplug state assigned for pcpu interrupt management + * @notif_irq: interrupt used as async notification by OP-TEE or 0 + * @optee_pcpu: per_cpu optee instance for per cpu work or NULL + * @notif_pcpu_wq: workqueue for per cpu asynchronous notification or NULL + * @notif_pcpu_work: work for per cpu asynchronous notification + * @notif_cpuhp_state: CPU hotplug state assigned for pcpu interrupt management */ struct optee_smc { optee_invoke_fn *invoke_fn; @@ -151,13 +151,15 @@ struct optee_smc { }; /** - * struct optee_ffa_data - FFA communication struct - * @ffa_dev FFA device, contains the destination id, the id of + * struct optee_ffa - FFA communication struct + * @ffa_dev: FFA device, contains the destination id, the id of * OP-TEE in secure world - * @bottom_half_value Notification ID used for bottom half signalling or + * @bottom_half_value: notification ID used for bottom half signalling or * U32_MAX if unused - * @mutex Serializes access to @global_ids - * @global_ids FF-A shared memory global handle translation + * @mutex: serializes access to @global_ids + * @global_ids: FF-A shared memory global handle translation + * @notif_wq: workqueue for FF-A asynchronous notification + * @notif_work: work for FF-A asynchronous notification */ struct optee_ffa { struct ffa_device *ffa_dev; @@ -222,26 +224,32 @@ struct optee_ops { /** * struct optee - main service struct - * @supp_teedev: supplicant device - * @teedev: client device - * @ops: internal callbacks for different ways to reach secure - * world - * @ctx: driver internal TEE context - * @smc: specific to SMC ABI - * @ffa: specific to FF-A ABI - * @call_queue: queue of threads waiting to call @invoke_fn - * @notif: notification synchronization struct - * @supp: supplicant synchronization struct for RPC to supplicant - * @pool: shared memory pool - * @mutex: mutex protecting @rpmb_dev - * @rpmb_dev: current RPMB device or NULL - * @rpmb_scan_bus_done flag if device registation of RPMB dependent devices - * was already done - * @rpmb_scan_bus_work workq to for an RPMB device and to scan optee bus - * and register RPMB dependent optee drivers - * @rpc_param_count: If > 0 number of RPC parameters to make room for - * @scan_bus_done flag if device registation was already done. - * @scan_bus_work workq to scan optee bus and register optee drivers + * @supp_teedev: supplicant device + * @teedev: client device + * @ops: internal callbacks for different ways to reach + * secure world + * @ctx: driver internal TEE context + * @smc: specific to SMC ABI + * @ffa: specific to FF-A ABI + * @shm_arg_cache: shared memory cache argument + * @call_queue: queue of threads waiting to call @invoke_fn + * @notif: notification synchronization struct + * @supp: supplicant synchronization struct for RPC to + * supplicant + * @pool: shared memory pool + * @rpmb_dev_mutex: mutex protecting @rpmb_dev + * @rpmb_dev: current RPMB device or NULL + * @rpmb_intf: RPMB notifier block + * @rpc_param_count: if > 0 number of RPC parameters to make room for + * @scan_bus_done: flag if device registation was already done + * @rpmb_scan_bus_done: flag if device registation of RPMB dependent + * devices was already done + * @in_kernel_rpmb_routing: flag if OP-TEE supports in-kernel RPMB routing + * @scan_bus_work: workq to scan optee bus and register optee + * drivers + * @rpmb_scan_bus_work: workq to for an RPMB device and to scan optee + * bus and register RPMB dependent optee drivers + * @revision: OP-TEE OS revision */ struct optee { struct tee_device *supp_teedev; diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c index a3d11b1f90fa..06747e90c230 100644 --- a/drivers/tee/optee/supp.c +++ b/drivers/tee/optee/supp.c @@ -10,7 +10,11 @@ struct optee_supp_req { struct list_head link; + int id; + bool in_queue; + bool processed; + u32 func; u32 ret; size_t num_params; @@ -19,6 +23,9 @@ struct optee_supp_req { struct completion c; }; +/* It is temporary request used for revoked pending request in supp->idr. */ +#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF)) + void optee_supp_init(struct optee_supp *supp) { memset(supp, 0, sizeof(*supp)); @@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp) { int id; struct optee_supp_req *req; - struct optee_supp_req *req_tmp; mutex_lock(&supp->mutex); - /* Abort all request retrieved by supplicant */ + /* Abort all request */ idr_for_each_entry(&supp->idr, req, id) { idr_remove(&supp->idr, id); - req->ret = TEEC_ERROR_COMMUNICATION; - complete(&req->c); - } + /* Skip if request was already marked invalid */ + if (IS_ERR(req)) + continue; - /* Abort all queued requests */ - list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { - list_del(&req->link); - req->in_queue = false; + /* For queued requests where supplicant has not seen it */ + if (req->in_queue) { + list_del(&req->link); + req->in_queue = false; + } + + req->processed = true; req->ret = TEEC_ERROR_COMMUNICATION; complete(&req->c); } @@ -100,8 +109,16 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, /* Insert the request in the request list */ mutex_lock(&supp->mutex); + req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); + if (req->id < 0) { + mutex_unlock(&supp->mutex); + kfree(req); + return TEEC_ERROR_OUT_OF_MEMORY; + } + list_add_tail(&req->link, &supp->reqs); req->in_queue = true; + req->processed = false; mutex_unlock(&supp->mutex); /* Tell an eventual waiter there's a new request */ @@ -117,21 +134,43 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, if (wait_for_completion_killable(&req->c)) { mutex_lock(&supp->mutex); if (req->in_queue) { + /* Supplicant has not seen this request yet. */ + idr_remove(&supp->idr, req->id); list_del(&req->link); req->in_queue = false; + + ret = TEEC_ERROR_COMMUNICATION; + } else if (req->processed) { + /* + * Supplicant has processed this request. Ignore the + * kill signal for now and submit the result. req is not + * in supp->reqs (removed by supp_pop_entry()) nor in + * supp->idr (removed by supp_pop_req()). + */ + ret = req->ret; + } else { + /* + * Supplicant is in the middle of processing this + * request. Replace req with INVALID_REQ_PTR so that + * the ID remains busy, causing optee_supp_send() to + * fail on the next call to supp_pop_req() with this ID. + */ + idr_replace(&supp->idr, INVALID_REQ_PTR, req->id); + ret = TEEC_ERROR_COMMUNICATION; } + mutex_unlock(&supp->mutex); - req->ret = TEEC_ERROR_COMMUNICATION; + } else { + ret = req->ret; } - ret = req->ret; kfree(req); return ret; } static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, - int num_params, int *id) + int num_params) { struct optee_supp_req *req; @@ -153,10 +192,6 @@ static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, return ERR_PTR(-EINVAL); } - *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); - if (*id < 0) - return ERR_PTR(-ENOMEM); - list_del(&req->link); req->in_queue = false; @@ -214,7 +249,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, struct optee *optee = tee_get_drvdata(teedev); struct optee_supp *supp = &optee->supp; struct optee_supp_req *req = NULL; - int id; size_t num_meta; int rc; @@ -224,15 +258,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, while (true) { mutex_lock(&supp->mutex); - req = supp_pop_entry(supp, *num_params - num_meta, &id); + req = supp_pop_entry(supp, *num_params - num_meta); + if (req) + break; /* Keep mutex held. */ mutex_unlock(&supp->mutex); - if (req) { - if (IS_ERR(req)) - return PTR_ERR(req); - break; - } - /* * If we didn't get a request we'll block in * wait_for_completion() to avoid needless spinning. @@ -245,6 +275,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, return -ERESTARTSYS; } + /* supp->mutex held and req != NULL. */ + + if (IS_ERR(req)) { + mutex_unlock(&supp->mutex); + return PTR_ERR(req); + } + if (num_meta) { /* * tee-supplicant support meta parameters -> requsts can be @@ -252,13 +289,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, */ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | TEE_IOCTL_PARAM_ATTR_META; - param->u.value.a = id; + param->u.value.a = req->id; param->u.value.b = 0; param->u.value.c = 0; } else { - mutex_lock(&supp->mutex); - supp->req_id = id; - mutex_unlock(&supp->mutex); + supp->req_id = req->id; } *func = req->func; @@ -266,6 +301,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, memcpy(param + num_meta, req->param, sizeof(struct tee_param) * req->num_params); + mutex_unlock(&supp->mutex); return 0; } @@ -297,12 +333,17 @@ static struct optee_supp_req *supp_pop_req(struct optee_supp *supp, if (!req) return ERR_PTR(-ENOENT); + /* optee_supp_thrd_req() already returned to optee. */ + if (IS_ERR(req)) + goto failed_req; + if ((num_params - nm) != req->num_params) return ERR_PTR(-EINVAL); + *num_meta = nm; +failed_req: idr_remove(&supp->idr, id); supp->req_id = -1; - *num_meta = nm; return req; } @@ -328,10 +369,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, mutex_lock(&supp->mutex); req = supp_pop_req(supp, num_params, param, &num_meta); - mutex_unlock(&supp->mutex); - if (IS_ERR(req)) { - /* Something is wrong, let supplicant restart. */ + mutex_unlock(&supp->mutex); + /* Something is wrong, let supplicant handel it. */ return PTR_ERR(req); } @@ -355,9 +395,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, } } req->ret = ret; - + req->processed = true; /* Let the requesting thread continue */ complete(&req->c); + mutex_unlock(&supp->mutex); return 0; } diff --git a/drivers/tee/qcomtee/core.c b/drivers/tee/qcomtee/core.c index b1cb50e434f0..60fe3b5776e3 100644 --- a/drivers/tee/qcomtee/core.c +++ b/drivers/tee/qcomtee/core.c @@ -306,8 +306,10 @@ int qcomtee_object_user_init(struct qcomtee_object *object, break; case QCOMTEE_OBJECT_TYPE_CB: object->ops = ops; - if (!object->ops->dispatch) - return -EINVAL; + if (!object->ops->dispatch) { + ret = -EINVAL; + break; + } /* If failed, "no-name". */ object->name = kvasprintf_const(GFP_KERNEL, fmt, ap); diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index ef9642d72672..1aac50c7c1de 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -530,11 +530,24 @@ static int params_to_user(struct tee_ioctl_param __user *uparams, return 0; } +static void free_params(struct tee_param *params, size_t num_params) +{ + size_t n; + + if (!params) + return; + + for (n = 0; n < num_params; n++) + if (tee_param_is_memref(params + n) && params[n].u.memref.shm) + tee_shm_put(params[n].u.memref.shm); + + kfree(params); +} + static int tee_ioctl_open_session(struct tee_context *ctx, struct tee_ioctl_buf_data __user *ubuf) { int rc; - size_t n; struct tee_ioctl_buf_data buf; struct tee_ioctl_open_session_arg __user *uarg; struct tee_ioctl_open_session_arg arg; @@ -595,16 +608,7 @@ out: */ if (rc && have_session && ctx->teedev->desc->ops->close_session) ctx->teedev->desc->ops->close_session(ctx, arg.session); - - if (params) { - /* Decrease ref count for all valid shared memory pointers */ - for (n = 0; n < arg.num_params; n++) - if (tee_param_is_memref(params + n) && - params[n].u.memref.shm) - tee_shm_put(params[n].u.memref.shm); - kfree(params); - } - + free_params(params, arg.num_params); return rc; } @@ -612,7 +616,6 @@ static int tee_ioctl_invoke(struct tee_context *ctx, struct tee_ioctl_buf_data __user *ubuf) { int rc; - size_t n; struct tee_ioctl_buf_data buf; struct tee_ioctl_invoke_arg __user *uarg; struct tee_ioctl_invoke_arg arg; @@ -657,14 +660,7 @@ static int tee_ioctl_invoke(struct tee_context *ctx, } rc = params_to_user(uparams, arg.num_params, params); out: - if (params) { - /* Decrease ref count for all valid shared memory pointers */ - for (n = 0; n < arg.num_params; n++) - if (tee_param_is_memref(params + n) && - params[n].u.memref.shm) - tee_shm_put(params[n].u.memref.shm); - kfree(params); - } + free_params(params, arg.num_params); return rc; } @@ -672,7 +668,6 @@ static int tee_ioctl_object_invoke(struct tee_context *ctx, struct tee_ioctl_buf_data __user *ubuf) { int rc; - size_t n; struct tee_ioctl_buf_data buf; struct tee_ioctl_object_invoke_arg __user *uarg; struct tee_ioctl_object_invoke_arg arg; @@ -716,14 +711,7 @@ static int tee_ioctl_object_invoke(struct tee_context *ctx, } rc = params_to_user(uparams, arg.num_params, params); out: - if (params) { - /* Decrease ref count for all valid shared memory pointers */ - for (n = 0; n < arg.num_params; n++) - if (tee_param_is_memref(params + n) && - params[n].u.memref.shm) - tee_shm_put(params[n].u.memref.shm); - kfree(params); - } + free_params(params, arg.num_params); return rc; } @@ -846,9 +834,15 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx, return -ENOMEM; rc = params_from_user(ctx, params, num_params, uarg->params); - if (rc) - goto out; + if (rc) { + free_params(params, num_params); + return rc; + } + /* + * supp_recv() may consume and replace the supplied parameters, so the + * final cleanup cannot use free_params() like the other ioctl paths. + */ rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params); if (rc) goto out; diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index e9ea9f80cfd9..6742b3579c86 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -435,7 +435,7 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags, num_pages = iov_iter_npages(iter, INT_MAX); if (!num_pages) { ret = ERR_PTR(-ENOMEM); - goto err_ctx_put; + goto err_free_shm; } shm->pages = kzalloc_objs(*shm->pages, num_pages); |
