Re: [PATCH v2] tee: optee: Fix supplicant wait loop
From: Jens Wiklander
Date: Mon Feb 03 2025 - 04:32:07 EST
On Mon, Feb 3, 2025 at 9:00 AM Sumit Garg <sumit.garg@xxxxxxxxxx> wrote:
>
> OP-TEE supplicant is a user-space daemon and it's possible for it
> being hung or crashed or killed in the middle of processing an OP-TEE
> RPC call. It becomes more complicated when there is incorrect shutdown
> ordering of the supplicant process vs the OP-TEE client application which
> can eventually lead to system hang-up waiting for the closure of the
> client application.
>
> Allow the client process waiting in kernel for supplicant response to
> be killed rather than indefinitetly waiting in an unkillable state. This
> fixes issues observed during system reboot/shutdown when supplicant got
> hung for some reason or gets crashed/killed which lead to client getting
> hung in an unkillable state. It in turn lead to system being in hung up
> state requiring hard power off/on to recover.
>
> Fixes: 4fb0a5eb364d ("tee: add OP-TEE driver")
> Suggested-by: Arnd Bergmann <arnd@xxxxxxxx>
> Cc: <stable@xxxxxxxxxxxxxxx>
> Signed-off-by: Sumit Garg <sumit.garg@xxxxxxxxxx>
> ---
>
> Changes in v2:
> - Switch to killable wait instead as suggested by Arnd instead
> of supplicant timeout. It atleast allow the client to wait for
> supplicant in killable state which in turn allows system to reboot
> or shutdown gracefully.
>
> drivers/tee/optee/supp.c | 32 +++++++-------------------------
> 1 file changed, 7 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c
> index 322a543b8c27..3fbfa9751931 100644
> --- a/drivers/tee/optee/supp.c
> +++ b/drivers/tee/optee/supp.c
> @@ -80,7 +80,6 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
> struct optee *optee = tee_get_drvdata(ctx->teedev);
> struct optee_supp *supp = &optee->supp;
> struct optee_supp_req *req;
> - bool interruptable;
> u32 ret;
>
> /*
> @@ -111,36 +110,19 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
> /*
> * Wait for supplicant to process and return result, once we've
> * returned from wait_for_completion(&req->c) successfully we have
> - * exclusive access again.
> + * exclusive access again. Allow the wait to be killable such that
> + * the wait doesn't turn into an indefinite state if the supplicant
> + * gets hung for some reason.
> */
> - while (wait_for_completion_interruptible(&req->c)) {
> - mutex_lock(&supp->mutex);
> - interruptable = !supp->ctx;
> - if (interruptable) {
> - /*
> - * There's no supplicant available and since the
> - * supp->mutex currently is held none can
> - * become available until the mutex released
> - * again.
> - *
> - * Interrupting an RPC to supplicant is only
> - * allowed as a way of slightly improving the user
> - * experience in case the supplicant hasn't been
> - * started yet. During normal operation the supplicant
> - * will serve all requests in a timely manner and
> - * interrupting then wouldn't make sense.
> - */
> + if (wait_for_completion_killable(&req->c)) {
> + if (!mutex_lock_killable(&supp->mutex)) {
Why not mutex_lock()? If we fail to acquire the mutex here, we will
quite likely free the req list item below at the end of this function
while it remains in the list.
Cheers,
Jens
> if (req->in_queue) {
> list_del(&req->link);
> req->in_queue = false;
> }
> + mutex_unlock(&supp->mutex);
> }
> - mutex_unlock(&supp->mutex);
> -
> - if (interruptable) {
> - req->ret = TEEC_ERROR_COMMUNICATION;
> - break;
> - }
> + req->ret = TEEC_ERROR_COMMUNICATION;
> }
>
> ret = req->ret;
> --
> 2.43.0
>