OP-TEE Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [REPORT] tee: tee_ioctl_supp_recv() missing tee_shm_put() cleanup for memref params
@ 2026-04-29  3:07 Qihang
  2026-04-29  6:34 ` Jens Wiklander
  0 siblings, 1 reply; 13+ messages in thread
From: Qihang @ 2026-04-29  3:07 UTC (permalink / raw)
  To: Jens Wiklander; +Cc: Sumit Garg, op-tee

Hi,

I would like to report a likely shared-memory reference leak in
drivers/tee/tee_core.c, in tee_ioctl_supp_recv().

The issue is that tee_ioctl_supp_recv() calls params_from_user(), which
acquires references for MEMREF-type parameters via tee_shm_get_from_id(),
but the cleanup path only frees the params array and does not drop the
acquired shm references.

Relevant code in tee_ioctl_supp_recv():

  rc = params_from_user(ctx, params, num_params, uarg->params);
  if (rc)
          goto out;

  rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params);
  if (rc)
          goto out;
  ...
out:
  kfree(params);
  return rc;

By contrast, other callers of params_from_user() in tee_core.c do release
MEMREF references on cleanup, for example:
- tee_ioctl_open_session()
- tee_ioctl_invoke()
- tee_ioctl_object_invoke()

The helper comment in param_from_user_memref() also states that the caller
is responsible for calling tee_shm_put() on all resolved pointers.

Reachability / trigger paths:

1. qcomtee backend:
   qcomtee registers .supp_recv = qcomtee_supp_recv on a non-privileged
   tee device path. qcomtee_supp_recv() rejects any non-meta parameter
   after the first one:
     for (i = 1; i < *num_params; i++)
             if (params[i].attr)
                     return -EINVAL;
   This allows a path where params_from_user() has already acquired a shm
   reference for a MEMREF parameter, then qcomtee_supp_recv() returns an
   error, and tee_ioctl_supp_recv() exits without tee_shm_put().

2. Partial failure before backend callback:
   if params_from_user() successfully resolves an earlier MEMREF parameter
   and then fails on a later parameter, tee_ioctl_supp_recv() still goes
   to the same cleanup path without dropping already acquired shm refs.

This means the issue is not just a backend-specific quirk: the core ioctl
cleanup path itself is missing tee_shm_put() handling.

Impact:
- leaked shared-memory references
- shared-memory objects may remain pinned and never reach final release
- repeated triggering can cause resource exhaustion / DoS

This does not appear to be a UAF, since refcount_t saturation prevents
wraparound. The impact looks limited to resource leakage and availability.

If useful, I can also prepare a patch.

Thanks,
Qihang

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [REPORT] tee: tee_ioctl_supp_recv() missing tee_shm_put() cleanup for memref params
  2026-04-29  3:07 [REPORT] tee: tee_ioctl_supp_recv() missing tee_shm_put() cleanup for memref params Qihang
@ 2026-04-29  6:34 ` Jens Wiklander
  2026-04-29 11:32   ` [PATCH] tee: fix missing shm reference cleanup in tee_ioctl_supp_recv Qihang
  0 siblings, 1 reply; 13+ messages in thread
From: Jens Wiklander @ 2026-04-29  6:34 UTC (permalink / raw)
  To: Qihang; +Cc: Sumit Garg, op-tee

Hi Qihang,

On Wed, Apr 29, 2026 at 5:07 AM Qihang <q.h.hack.winter@gmail.com> wrote:
>
> Hi,
>
> I would like to report a likely shared-memory reference leak in
> drivers/tee/tee_core.c, in tee_ioctl_supp_recv().
>
> The issue is that tee_ioctl_supp_recv() calls params_from_user(), which
> acquires references for MEMREF-type parameters via tee_shm_get_from_id(),
> but the cleanup path only frees the params array and does not drop the
> acquired shm references.
>
> Relevant code in tee_ioctl_supp_recv():
>
>   rc = params_from_user(ctx, params, num_params, uarg->params);
>   if (rc)
>           goto out;
>
>   rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params);
>   if (rc)
>           goto out;
>   ...
> out:
>   kfree(params);
>   return rc;
>
> By contrast, other callers of params_from_user() in tee_core.c do release
> MEMREF references on cleanup, for example:
> - tee_ioctl_open_session()
> - tee_ioctl_invoke()
> - tee_ioctl_object_invoke()
>
> The helper comment in param_from_user_memref() also states that the caller
> is responsible for calling tee_shm_put() on all resolved pointers.
>
> Reachability / trigger paths:
>
> 1. qcomtee backend:
>    qcomtee registers .supp_recv = qcomtee_supp_recv on a non-privileged
>    tee device path. qcomtee_supp_recv() rejects any non-meta parameter
>    after the first one:
>      for (i = 1; i < *num_params; i++)
>              if (params[i].attr)
>                      return -EINVAL;
>    This allows a path where params_from_user() has already acquired a shm
>    reference for a MEMREF parameter, then qcomtee_supp_recv() returns an
>    error, and tee_ioctl_supp_recv() exits without tee_shm_put().
>
> 2. Partial failure before backend callback:
>    if params_from_user() successfully resolves an earlier MEMREF parameter
>    and then fails on a later parameter, tee_ioctl_supp_recv() still goes
>    to the same cleanup path without dropping already acquired shm refs.
>
> This means the issue is not just a backend-specific quirk: the core ioctl
> cleanup path itself is missing tee_shm_put() handling.
>
> Impact:
> - leaked shared-memory references
> - shared-memory objects may remain pinned and never reach final release
> - repeated triggering can cause resource exhaustion / DoS
>
> This does not appear to be a UAF, since refcount_t saturation prevents
> wraparound. The impact looks limited to resource leakage and availability.
>
> If useful, I can also prepare a patch.

Thanks for the detailed report. If possible, please prepare a patch to fix this.

Cheers,
Jens

>
> Thanks,
> Qihang

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] tee: fix missing shm reference cleanup in tee_ioctl_supp_recv
  2026-04-29  6:34 ` Jens Wiklander
@ 2026-04-29 11:32   ` Qihang
  2026-05-01 14:31     ` Sumit Garg via OP-TEE
  0 siblings, 1 reply; 13+ messages in thread
From: Qihang @ 2026-04-29 11:32 UTC (permalink / raw)
  To: jens.wiklander; +Cc: sumit.garg, op-tee, Qihang

params_from_user() acquires tee_shm references for MEMREF parameters and
expects the caller to release those references with tee_shm_put() during
cleanup.

tee_ioctl_open_session(), tee_ioctl_invoke(), and
tee_ioctl_object_invoke() all do this, but tee_ioctl_supp_recv() only
frees the parameter array and does not drop any acquired shared-memory
references.

Fix this by using a common helper to release MEMREF references before
freeing the parameter array, and apply it to tee_ioctl_supp_recv() as
well.

Since supp_recv backends may update num_params, preserve the original
allocated parameter count for cleanup.

Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
---
 drivers/tee/tee_core.c | 49 +++++++++++++++++++-----------------------
 1 file changed, 22 insertions(+), 27 deletions(-)

diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index ef9642d72672..adad1ea8e31b 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -530,6 +530,21 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
 	return 0;
 }
 
+static void params_free_decref(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)
 {
@@ -595,16 +610,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
 	 */
 	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);
-	}
-
+	params_free_decref(params, arg.num_params);
 	return rc;
 }
 
@@ -657,14 +663,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);
-	}
+	params_free_decref(params, arg.num_params);
 	return rc;
 }
 
@@ -716,14 +715,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);
-	}
+	params_free_decref(params, arg.num_params);
 	return rc;
 }
 
@@ -822,6 +814,7 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
 	struct tee_iocl_supp_recv_arg __user *uarg;
 	struct tee_param *params;
 	u32 num_params;
+	u32 alloc_num_params;
 	u32 func;
 
 	if (!ctx->teedev->desc->ops->supp_recv)
@@ -838,6 +831,8 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
 	if (get_user(num_params, &uarg->num_params))
 		return -EFAULT;
 
+	alloc_num_params = num_params;
+
 	if (size_add(sizeof(*uarg), TEE_IOCTL_PARAM_SIZE(num_params)) != buf.buf_len)
 		return -EINVAL;
 
@@ -861,7 +856,7 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
 
 	rc = params_to_supp(ctx, uarg->params, num_params, params);
 out:
-	kfree(params);
+	params_free_decref(params, alloc_num_params);
 	return rc;
 }
 
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] tee: fix missing shm reference cleanup in tee_ioctl_supp_recv
  2026-04-29 11:32   ` [PATCH] tee: fix missing shm reference cleanup in tee_ioctl_supp_recv Qihang
@ 2026-05-01 14:31     ` Sumit Garg via OP-TEE
  2026-05-05 15:08       ` Qihang
  2026-05-05 15:30       ` [PATCH v2] " Qihang
  0 siblings, 2 replies; 13+ messages in thread
From: Sumit Garg via OP-TEE @ 2026-05-01 14:31 UTC (permalink / raw)
  To: Qihang; +Cc: op-tee

On Wed, Apr 29, 2026 at 07:32:19PM +0800, Qihang wrote:
> params_from_user() acquires tee_shm references for MEMREF parameters and
> expects the caller to release those references with tee_shm_put() during
> cleanup.
> 
> tee_ioctl_open_session(), tee_ioctl_invoke(), and
> tee_ioctl_object_invoke() all do this, but tee_ioctl_supp_recv() only
> frees the parameter array and does not drop any acquired shared-memory
> references.
> 
> Fix this by using a common helper to release MEMREF references before
> freeing the parameter array, and apply it to tee_ioctl_supp_recv() as
> well.
> 
> Since supp_recv backends may update num_params, preserve the original
> allocated parameter count for cleanup.
> 
> Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
> ---
>  drivers/tee/tee_core.c | 49 +++++++++++++++++++-----------------------
>  1 file changed, 22 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index ef9642d72672..adad1ea8e31b 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -530,6 +530,21 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
>  	return 0;
>  }
>  
> +static void params_free_decref(struct tee_param *params, size_t num_params)

I would rather rename this API as free_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)
>  {
> @@ -595,16 +610,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
>  	 */
>  	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);
> -	}
> -
> +	params_free_decref(params, arg.num_params);
>  	return rc;
>  }
>  
> @@ -657,14 +663,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);
> -	}
> +	params_free_decref(params, arg.num_params);
>  	return rc;
>  }
>  
> @@ -716,14 +715,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);
> -	}
> +	params_free_decref(params, arg.num_params);
>  	return rc;
>  }
>  
> @@ -822,6 +814,7 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
>  	struct tee_iocl_supp_recv_arg __user *uarg;
>  	struct tee_param *params;
>  	u32 num_params;
> +	u32 alloc_num_params;
>  	u32 func;
>  
>  	if (!ctx->teedev->desc->ops->supp_recv)
> @@ -838,6 +831,8 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
>  	if (get_user(num_params, &uarg->num_params))
>  		return -EFAULT;
>  
> +	alloc_num_params = num_params;

Why is this needed? Shouldn't the updated num_params will point to size
of params array?

-Sumit

> +
>  	if (size_add(sizeof(*uarg), TEE_IOCTL_PARAM_SIZE(num_params)) != buf.buf_len)
>  		return -EINVAL;
>  
> @@ -861,7 +856,7 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
>  
>  	rc = params_to_supp(ctx, uarg->params, num_params, params);
>  out:
> -	kfree(params);
> +	params_free_decref(params, alloc_num_params);
>  	return rc;
>  }
>  
> -- 
> 2.39.5 (Apple Git-154)
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] tee: fix missing shm reference cleanup in tee_ioctl_supp_recv
  2026-05-01 14:31     ` Sumit Garg via OP-TEE
@ 2026-05-05 15:08       ` Qihang
  2026-05-05 15:30       ` [PATCH v2] " Qihang
  1 sibling, 0 replies; 13+ messages in thread
From: Qihang @ 2026-05-05 15:08 UTC (permalink / raw)
  To: Sumit Garg; +Cc: op-tee

Hi Sumit,

Thanks, that makes sense.

I had been conservative about the possibility of num_params being updated
by supp_recv backends, but looking again at the current paths, I agree
that alloc_num_params is unnecessary here.

I'll drop that, rename the helper to free_params(), and send a v2.

Thanks,
Qihang

On Fri, May 1, 2026 at 10:32 PM Sumit Garg <sumit.garg@kernel.org> wrote:
>
> On Wed, Apr 29, 2026 at 07:32:19PM +0800, Qihang wrote:
> > params_from_user() acquires tee_shm references for MEMREF parameters and
> > expects the caller to release those references with tee_shm_put() during
> > cleanup.
> >
> > tee_ioctl_open_session(), tee_ioctl_invoke(), and
> > tee_ioctl_object_invoke() all do this, but tee_ioctl_supp_recv() only
> > frees the parameter array and does not drop any acquired shared-memory
> > references.
> >
> > Fix this by using a common helper to release MEMREF references before
> > freeing the parameter array, and apply it to tee_ioctl_supp_recv() as
> > well.
> >
> > Since supp_recv backends may update num_params, preserve the original
> > allocated parameter count for cleanup.
> >
> > Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
> > ---
> >  drivers/tee/tee_core.c | 49 +++++++++++++++++++-----------------------
> >  1 file changed, 22 insertions(+), 27 deletions(-)
> >
> > diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> > index ef9642d72672..adad1ea8e31b 100644
> > --- a/drivers/tee/tee_core.c
> > +++ b/drivers/tee/tee_core.c
> > @@ -530,6 +530,21 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
> >       return 0;
> >  }
> >
> > +static void params_free_decref(struct tee_param *params, size_t num_params)
>
> I would rather rename this API as free_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)
> >  {
> > @@ -595,16 +610,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
> >        */
> >       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);
> > -     }
> > -
> > +     params_free_decref(params, arg.num_params);
> >       return rc;
> >  }
> >
> > @@ -657,14 +663,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);
> > -     }
> > +     params_free_decref(params, arg.num_params);
> >       return rc;
> >  }
> >
> > @@ -716,14 +715,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);
> > -     }
> > +     params_free_decref(params, arg.num_params);
> >       return rc;
> >  }
> >
> > @@ -822,6 +814,7 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
> >       struct tee_iocl_supp_recv_arg __user *uarg;
> >       struct tee_param *params;
> >       u32 num_params;
> > +     u32 alloc_num_params;
> >       u32 func;
> >
> >       if (!ctx->teedev->desc->ops->supp_recv)
> > @@ -838,6 +831,8 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
> >       if (get_user(num_params, &uarg->num_params))
> >               return -EFAULT;
> >
> > +     alloc_num_params = num_params;
>
> Why is this needed? Shouldn't the updated num_params will point to size
> of params array?
>
> -Sumit
>
> > +
> >       if (size_add(sizeof(*uarg), TEE_IOCTL_PARAM_SIZE(num_params)) != buf.buf_len)
> >               return -EINVAL;
> >
> > @@ -861,7 +856,7 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
> >
> >       rc = params_to_supp(ctx, uarg->params, num_params, params);
> >  out:
> > -     kfree(params);
> > +     params_free_decref(params, alloc_num_params);
> >       return rc;
> >  }
> >
> > --
> > 2.39.5 (Apple Git-154)
> >

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2] tee: fix missing shm reference cleanup in tee_ioctl_supp_recv
  2026-05-01 14:31     ` Sumit Garg via OP-TEE
  2026-05-05 15:08       ` Qihang
@ 2026-05-05 15:30       ` Qihang
  2026-05-06  2:18         ` Qihang
                           ` (2 more replies)
  1 sibling, 3 replies; 13+ messages in thread
From: Qihang @ 2026-05-05 15:30 UTC (permalink / raw)
  To: jens.wiklander; +Cc: sumit.garg, op-tee, Qihang

params_from_user() acquires tee_shm references for MEMREF parameters and
expects the caller to release those references with tee_shm_put() during
cleanup.

tee_ioctl_open_session(), tee_ioctl_invoke(), and
tee_ioctl_object_invoke() all do this, but tee_ioctl_supp_recv() only
frees the parameter array and does not drop any acquired shared-memory
references.

Fix this by using a common helper to release MEMREF references before
freeing the parameter array, and apply it to tee_ioctl_supp_recv() as
well.

Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
---
v2:
- rename helper to free_params()
- drop alloc_num_params and use num_params directly

 drivers/tee/tee_core.c | 46 +++++++++++++++++-------------------------
 1 file changed, 19 insertions(+), 27 deletions(-)

diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index ef9642d72672..8cdf2ec7e74f 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -530,6 +530,21 @@ 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)
 {
@@ -595,16 +610,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
 	 */
 	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;
 }
 
@@ -657,14 +663,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;
 }
 
@@ -716,14 +715,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;
 }
 
@@ -861,7 +853,7 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
 
 	rc = params_to_supp(ctx, uarg->params, num_params, params);
 out:
-	kfree(params);
+	free_params(params, num_params);
 	return rc;
 }
 
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] tee: fix missing shm reference cleanup in tee_ioctl_supp_recv
  2026-05-05 15:30       ` [PATCH v2] " Qihang
@ 2026-05-06  2:18         ` Qihang
  2026-05-07  7:31           ` Jens Wiklander
  2026-05-07  7:47         ` Jens Wiklander
  2026-05-07  9:45         ` [PATCH v3] tee: fix params_from_user() error path " Qihang
  2 siblings, 1 reply; 13+ messages in thread
From: Qihang @ 2026-05-06  2:18 UTC (permalink / raw)
  To: jens.wiklander, sumit.garg; +Cc: op-tee

Hi Jens, Sumit,

While reworking this, I noticed that there may be two slightly
different cleanup issues involved here.

One appears to be in tee_ioctl_supp_recv() itself. Another may be in a
qcomtee-specific error path where MEMREF references can already have
been acquired before the backend rejects the parameters.

I am not entirely sure where you would prefer the boundary between the
core fix and any backend-specific fix to be.

Would you prefer that I keep the current patch strictly focused on the
tee_ioctl_supp_recv() cleanup path first, and handle any qcomtee-side
issue separately if needed?

Thanks,
Qihang

On Tue, May 5, 2026 at 11:30 PM Qihang <q.h.hack.winter@gmail.com> wrote:
>
> params_from_user() acquires tee_shm references for MEMREF parameters and
> expects the caller to release those references with tee_shm_put() during
> cleanup.
>
> tee_ioctl_open_session(), tee_ioctl_invoke(), and
> tee_ioctl_object_invoke() all do this, but tee_ioctl_supp_recv() only
> frees the parameter array and does not drop any acquired shared-memory
> references.
>
> Fix this by using a common helper to release MEMREF references before
> freeing the parameter array, and apply it to tee_ioctl_supp_recv() as
> well.
>
> Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
> ---
> v2:
> - rename helper to free_params()
> - drop alloc_num_params and use num_params directly
>
>  drivers/tee/tee_core.c | 46 +++++++++++++++++-------------------------
>  1 file changed, 19 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index ef9642d72672..8cdf2ec7e74f 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -530,6 +530,21 @@ 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)
>  {
> @@ -595,16 +610,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
>          */
>         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;
>  }
>
> @@ -657,14 +663,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;
>  }
>
> @@ -716,14 +715,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;
>  }
>
> @@ -861,7 +853,7 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
>
>         rc = params_to_supp(ctx, uarg->params, num_params, params);
>  out:
> -       kfree(params);
> +       free_params(params, num_params);
>         return rc;
>  }
>
> --
> 2.39.5 (Apple Git-154)
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] tee: fix missing shm reference cleanup in tee_ioctl_supp_recv
  2026-05-06  2:18         ` Qihang
@ 2026-05-07  7:31           ` Jens Wiklander
  0 siblings, 0 replies; 13+ messages in thread
From: Jens Wiklander @ 2026-05-07  7:31 UTC (permalink / raw)
  To: Qihang; +Cc: sumit.garg, op-tee

Hi Qihang,

On Wed, May 6, 2026 at 4:18 AM Qihang <q.h.hack.winter@gmail.com> wrote:
>
> Hi Jens, Sumit,
>
> While reworking this, I noticed that there may be two slightly
> different cleanup issues involved here.
>
> One appears to be in tee_ioctl_supp_recv() itself. Another may be in a
> qcomtee-specific error path where MEMREF references can already have
> been acquired before the backend rejects the parameters.
>
> I am not entirely sure where you would prefer the boundary between the
> core fix and any backend-specific fix to be.
>
> Would you prefer that I keep the current patch strictly focused on the
> tee_ioctl_supp_recv() cleanup path first, and handle any qcomtee-side
> issue separately if needed?

qcomtee-specific changes should preferably go into a separate patch.
In this case, I suspect the fix is to add a similar tee_shm_put() as
we have in supp_check_recv_params() in drivers/tee/optee/supp.c.

Cheers,
Jens

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] tee: fix missing shm reference cleanup in tee_ioctl_supp_recv
  2026-05-05 15:30       ` [PATCH v2] " Qihang
  2026-05-06  2:18         ` Qihang
@ 2026-05-07  7:47         ` Jens Wiklander
  2026-05-07  9:45         ` [PATCH v3] tee: fix params_from_user() error path " Qihang
  2 siblings, 0 replies; 13+ messages in thread
From: Jens Wiklander @ 2026-05-07  7:47 UTC (permalink / raw)
  To: Qihang; +Cc: sumit.garg, op-tee

Hi Qihang,

On Tue, May 5, 2026 at 5:30 PM Qihang <q.h.hack.winter@gmail.com> wrote:
>
> params_from_user() acquires tee_shm references for MEMREF parameters and
> expects the caller to release those references with tee_shm_put() during
> cleanup.
>
> tee_ioctl_open_session(), tee_ioctl_invoke(), and
> tee_ioctl_object_invoke() all do this, but tee_ioctl_supp_recv() only
> frees the parameter array and does not drop any acquired shared-memory
> references.
>
> Fix this by using a common helper to release MEMREF references before
> freeing the parameter array, and apply it to tee_ioctl_supp_recv() as
> well.
>
> Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
> ---
> v2:
> - rename helper to free_params()
> - drop alloc_num_params and use num_params directly
>
>  drivers/tee/tee_core.c | 46 +++++++++++++++++-------------------------
>  1 file changed, 19 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index ef9642d72672..8cdf2ec7e74f 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -530,6 +530,21 @@ 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)
>  {
> @@ -595,16 +610,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
>          */
>         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;
>  }
>
> @@ -657,14 +663,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;
>  }
>
> @@ -716,14 +715,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;
>  }
>
> @@ -861,7 +853,7 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
>
>         rc = params_to_supp(ctx, uarg->params, num_params, params);
>  out:
> -       kfree(params);
> +       free_params(params, num_params);

This doesn't work. The supp_recv() callback is special compared to
open_session(), invoke_func(), and object_invoke_func() callbacks.
supp_recv() replaces the supplied parameters with other parameters.
Eventually inserted memrefs are reference-counted separately, and
adding it here too would only add unnecessary updates (supp_recv()
would need to increase them, only so they can be decreased here).
However, I think a comment before the call to supp_recv() to remind us
of that would be nice.

However, there's a bug that needs to be fixed if params_from_user()
fails. One way of dealing with that is:
        rc = params_from_user(ctx, params, num_params, uarg->params);
        if (rc) {
                free_params(params, num_params);
                return rc;
        }

and then keep the end of tee_ioctl_supp_recv() unchanged.

Cheers,
Jens

>         return rc;
>  }
>
> --
> 2.39.5 (Apple Git-154)
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3] tee: fix params_from_user() error path in tee_ioctl_supp_recv
  2026-05-05 15:30       ` [PATCH v2] " Qihang
  2026-05-06  2:18         ` Qihang
  2026-05-07  7:47         ` Jens Wiklander
@ 2026-05-07  9:45         ` Qihang
  2026-05-07 10:40           ` Jens Wiklander
  2026-05-07 15:39           ` [PATCH v4] " Qihang
  2 siblings, 2 replies; 13+ messages in thread
From: Qihang @ 2026-05-07  9:45 UTC (permalink / raw)
  To: Jens Wiklander; +Cc: Sumit Garg, op-tee, Qihang

params_from_user() may acquire tee_shm references for MEMREF parameters
before failing after partially processing the supplied parameter array.

In tee_ioctl_supp_recv(), those references are currently not released on
that error path.

Fix this by freeing MEMREF references before returning when
params_from_user() fails.

Keep the final cleanup path in tee_ioctl_supp_recv() unchanged since
supp_recv() may consume and replace the supplied parameters, unlike the
other TEE ioctl callback paths.

Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
---
v3:
- only free MEMREF references when params_from_user() fails
- keep tee_ioctl_supp_recv() final cleanup unchanged
- follow Jens' review on supp_recv() parameter ownership semantics

v2:
- rename helper to free_params()
- drop alloc_num_params and use num_params directly

 drivers/tee/tee_core.c | 54 ++++++++++++++++++++----------------------
 1 file changed, 26 insertions(+), 28 deletions(-)

diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index ef9642d72672..2fd3a00b47c7 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -530,6 +530,21 @@ 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)
 {
@@ -595,16 +610,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
 	 */
 	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;
 }
 
@@ -657,14 +663,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;
 }
 
@@ -716,14 +715,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 +838,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;
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v3] tee: fix params_from_user() error path in tee_ioctl_supp_recv
  2026-05-07  9:45         ` [PATCH v3] tee: fix params_from_user() error path " Qihang
@ 2026-05-07 10:40           ` Jens Wiklander
  2026-05-07 15:39           ` [PATCH v4] " Qihang
  1 sibling, 0 replies; 13+ messages in thread
From: Jens Wiklander @ 2026-05-07 10:40 UTC (permalink / raw)
  To: Qihang; +Cc: Sumit Garg, op-tee

Hi,

On Thu, May 7, 2026 at 11:46 AM Qihang <q.h.hack.winter@gmail.com> wrote:
>
> params_from_user() may acquire tee_shm references for MEMREF parameters
> before failing after partially processing the supplied parameter array.
>
> In tee_ioctl_supp_recv(), those references are currently not released on
> that error path.
>
> Fix this by freeing MEMREF references before returning when
> params_from_user() fails.
>
> Keep the final cleanup path in tee_ioctl_supp_recv() unchanged since
> supp_recv() may consume and replace the supplied parameters, unlike the
> other TEE ioctl callback paths.
>
> Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
> ---
> v3:
> - only free MEMREF references when params_from_user() fails
> - keep tee_ioctl_supp_recv() final cleanup unchanged
> - follow Jens' review on supp_recv() parameter ownership semantics
>
> v2:
> - rename helper to free_params()
> - drop alloc_num_params and use num_params directly
>
>  drivers/tee/tee_core.c | 54 ++++++++++++++++++++----------------------
>  1 file changed, 26 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index ef9642d72672..2fd3a00b47c7 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -530,6 +530,21 @@ 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)

Please fold up. It fits on one line.

> +                       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)
>  {
> @@ -595,16 +610,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
>          */
>         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;
>  }
>
> @@ -657,14 +663,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;
>  }
>
> @@ -716,14 +715,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 +838,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;
> --
> 2.39.5 (Apple Git-154)
>

There are a few warnings:
  AR      drivers/base/firmware_loader/built-in.a
  AR      drivers/base/built-in.a
drivers/tee/tee_core.c: In function ‘tee_ioctl_open_session’:
drivers/tee/tee_core.c:552:16: warning: unused variable ‘n’ [-Wunused-variable]
  552 |         size_t n;
      |                ^
drivers/tee/tee_core.c: In function ‘tee_ioctl_invoke’:
drivers/tee/tee_core.c:622:16: warning: unused variable ‘n’ [-Wunused-variable]
  622 |         size_t n;
      |                ^
drivers/tee/tee_core.c: In function ‘tee_ioctl_object_invoke’:
drivers/tee/tee_core.c:676:16: warning: unused variable ‘n’ [-Wunused-variable]
  676 |         size_t n;
      |                ^

Cheers,
Jens

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v4] tee: fix params_from_user() error path in tee_ioctl_supp_recv
  2026-05-07  9:45         ` [PATCH v3] tee: fix params_from_user() error path " Qihang
  2026-05-07 10:40           ` Jens Wiklander
@ 2026-05-07 15:39           ` Qihang
  2026-05-11 13:18             ` Jens Wiklander
  1 sibling, 1 reply; 13+ messages in thread
From: Qihang @ 2026-05-07 15:39 UTC (permalink / raw)
  To: Jens Wiklander; +Cc: Sumit Garg, op-tee, Qihang

params_from_user() may acquire tee_shm references for MEMREF parameters
before failing after partially processing the supplied parameter array.

In tee_ioctl_supp_recv(), those references are currently not released on
that error path.

Fix this by freeing MEMREF references before returning when
params_from_user() fails.

Keep the final cleanup path in tee_ioctl_supp_recv() unchanged since
supp_recv() may consume and replace the supplied parameters, unlike the
other TEE ioctl callback paths.

Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
---
v4:
- fold free_params() memref check onto one line
- remove unused local variables left behind by the cleanup refactoring

v3:
- only free MEMREF references when params_from_user() fails
- keep tee_ioctl_supp_recv() final cleanup unchanged
- follow Jens' review on supp_recv() parameter ownership semantics

v2:
- rename helper to free_params()
- drop alloc_num_params and use num_params directly

 drivers/tee/tee_core.c | 56 +++++++++++++++++++-----------------------
 1 file changed, 25 insertions(+), 31 deletions(-)

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 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
 	 */
 	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;
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v4] tee: fix params_from_user() error path in tee_ioctl_supp_recv
  2026-05-07 15:39           ` [PATCH v4] " Qihang
@ 2026-05-11 13:18             ` Jens Wiklander
  0 siblings, 0 replies; 13+ messages in thread
From: Jens Wiklander @ 2026-05-11 13:18 UTC (permalink / raw)
  To: Qihang; +Cc: Sumit Garg, op-tee

Hi,

On Thu, May 7, 2026 at 5:39 PM Qihang <q.h.hack.winter@gmail.com> wrote:
>
> params_from_user() may acquire tee_shm references for MEMREF parameters
> before failing after partially processing the supplied parameter array.
>
> In tee_ioctl_supp_recv(), those references are currently not released on
> that error path.
>
> Fix this by freeing MEMREF references before returning when
> params_from_user() fails.
>
> Keep the final cleanup path in tee_ioctl_supp_recv() unchanged since
> supp_recv() may consume and replace the supplied parameters, unlike the
> other TEE ioctl callback paths.
>
> Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
> ---
> v4:
> - fold free_params() memref check onto one line
> - remove unused local variables left behind by the cleanup refactoring
>
> v3:
> - only free MEMREF references when params_from_user() fails
> - keep tee_ioctl_supp_recv() final cleanup unchanged
> - follow Jens' review on supp_recv() parameter ownership semantics
>
> v2:
> - rename helper to free_params()
> - drop alloc_num_params and use num_params directly
>
>  drivers/tee/tee_core.c | 56 +++++++++++++++++++-----------------------
>  1 file changed, 25 insertions(+), 31 deletions(-)

Looks good. I'm picking up this.

Cheers,
Jens

>
> 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 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
>          */
>         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;
> --
> 2.39.5 (Apple Git-154)
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-05-11 13:19 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-29  3:07 [REPORT] tee: tee_ioctl_supp_recv() missing tee_shm_put() cleanup for memref params Qihang
2026-04-29  6:34 ` Jens Wiklander
2026-04-29 11:32   ` [PATCH] tee: fix missing shm reference cleanup in tee_ioctl_supp_recv Qihang
2026-05-01 14:31     ` Sumit Garg via OP-TEE
2026-05-05 15:08       ` Qihang
2026-05-05 15:30       ` [PATCH v2] " Qihang
2026-05-06  2:18         ` Qihang
2026-05-07  7:31           ` Jens Wiklander
2026-05-07  7:47         ` Jens Wiklander
2026-05-07  9:45         ` [PATCH v3] tee: fix params_from_user() error path " Qihang
2026-05-07 10:40           ` Jens Wiklander
2026-05-07 15:39           ` [PATCH v4] " Qihang
2026-05-11 13:18             ` Jens Wiklander

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox