summaryrefslogtreecommitdiff
path: root/drivers/tee
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tee')
-rw-r--r--drivers/tee/amdtee/amdtee_private.h16
-rw-r--r--drivers/tee/amdtee/call.c2
-rw-r--r--drivers/tee/amdtee/core.c52
-rw-r--r--drivers/tee/optee/call.c3
-rw-r--r--drivers/tee/optee/optee_msg.h50
-rw-r--r--drivers/tee/optee/optee_private.h120
-rw-r--r--drivers/tee/optee/supp.c107
-rw-r--r--drivers/tee/qcomtee/core.c6
-rw-r--r--drivers/tee/tee_core.c56
-rw-r--r--drivers/tee/tee_shm.c2
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);