Skip to content

Commit

Permalink
optee: use driver internal tee_context for some rpc
Browse files Browse the repository at this point in the history
commit aceeafe upstream.

Adds a driver private tee_context by moving the tee_context in struct
optee_notif to struct optee. This tee_context was previously used when
doing internal calls to secure world to deliver notification.

The new driver internal tee_context is now also when allocating driver
private shared memory. This decouples the shared memory object from its
original tee_context. This is needed when the life time of such a memory
allocation outlives the client tee_context.

This patch fixes the problem described below:

The addition of a shutdown hook by commit f25889f ("optee: fix tee out
of memory failure seen during kexec reboot") introduced a kernel shutdown
regression that can be triggered after running the OP-TEE xtest suites.

Once the shutdown hook is called it is not possible to communicate any more
with the supplicant process because the system is not scheduling task any
longer. Thus if the optee driver shutdown path receives a supplicant RPC
request from the OP-TEE we will deadlock the kernel's shutdown.

Fixes: f25889f ("optee: fix tee out of memory failure seen during kexec reboot")
Fixes: 217e025 ("tee: use reference counting for tee_context")
Reported-by: Lars Persson <larper@axis.com>
Cc: stable@vger.kernel.org
Reviewed-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
[JW: backport to 5.15-stable + update commit message]
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
jenswi-linaro authored and gregkh committed Mar 2, 2022
1 parent 0efdc03 commit 2922aff
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 3 deletions.
8 changes: 8 additions & 0 deletions drivers/tee/optee/core.c
Expand Up @@ -588,6 +588,7 @@ static int optee_remove(struct platform_device *pdev)
/* Unregister OP-TEE specific client devices on TEE bus */
optee_unregister_devices();

teedev_close_context(optee->ctx);
/*
* Ask OP-TEE to free all cached shared memory objects to decrease
* reference counters and also avoid wild pointers in secure world
Expand Down Expand Up @@ -633,6 +634,7 @@ static int optee_probe(struct platform_device *pdev)
struct optee *optee = NULL;
void *memremaped_shm = NULL;
struct tee_device *teedev;
struct tee_context *ctx;
u32 sec_caps;
int rc;

Expand Down Expand Up @@ -719,6 +721,12 @@ static int optee_probe(struct platform_device *pdev)
optee_supp_init(&optee->supp);
optee->memremaped_shm = memremaped_shm;
optee->pool = pool;
ctx = teedev_open(optee->teedev);
if (IS_ERR(ctx)) {
rc = PTR_ERR(ctx);
goto err;
}
optee->ctx = ctx;

/*
* Ensure that there are no pre-existing shm objects before enabling
Expand Down
2 changes: 2 additions & 0 deletions drivers/tee/optee/optee_private.h
Expand Up @@ -70,6 +70,7 @@ struct optee_supp {
* struct optee - main service struct
* @supp_teedev: supplicant device
* @teedev: client device
* @ctx: driver internal TEE context
* @invoke_fn: function to issue smc or hvc
* @call_queue: queue of threads waiting to call @invoke_fn
* @wait_queue: queue of threads from secure world waiting for a
Expand All @@ -87,6 +88,7 @@ struct optee {
struct tee_device *supp_teedev;
struct tee_device *teedev;
optee_invoke_fn *invoke_fn;
struct tee_context *ctx;
struct optee_call_queue call_queue;
struct optee_wait_queue wait_queue;
struct optee_supp supp;
Expand Down
8 changes: 5 additions & 3 deletions drivers/tee/optee/rpc.c
Expand Up @@ -285,6 +285,7 @@ static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
}

static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
struct optee *optee,
struct optee_msg_arg *arg,
struct optee_call_ctx *call_ctx)
{
Expand Down Expand Up @@ -314,7 +315,8 @@ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
shm = cmd_alloc_suppl(ctx, sz);
break;
case OPTEE_RPC_SHM_TYPE_KERNEL:
shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED | TEE_SHM_PRIV);
shm = tee_shm_alloc(optee->ctx, sz,
TEE_SHM_MAPPED | TEE_SHM_PRIV);
break;
default:
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
Expand Down Expand Up @@ -471,7 +473,7 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
break;
case OPTEE_RPC_CMD_SHM_ALLOC:
free_pages_list(call_ctx);
handle_rpc_func_cmd_shm_alloc(ctx, arg, call_ctx);
handle_rpc_func_cmd_shm_alloc(ctx, optee, arg, call_ctx);
break;
case OPTEE_RPC_CMD_SHM_FREE:
handle_rpc_func_cmd_shm_free(ctx, arg);
Expand Down Expand Up @@ -502,7 +504,7 @@ void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param,

switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
case OPTEE_SMC_RPC_FUNC_ALLOC:
shm = tee_shm_alloc(ctx, param->a1,
shm = tee_shm_alloc(optee->ctx, param->a1,
TEE_SHM_MAPPED | TEE_SHM_PRIV);
if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
reg_pair_from_64(&param->a1, &param->a2, pa);
Expand Down

0 comments on commit 2922aff

Please sign in to comment.