diff mbox series

[02/10] tee: add TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF

Message ID 20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-2-f502ef01e016@quicinc.com (mailing list archive)
State Not Applicable
Headers show
Series Trusted Execution Environment (TEE) driver for Qualcomm TEE (QTEE) | expand

Commit Message

Amirreza Zarrabi Dec. 3, 2024, 4:19 a.m. UTC
For drivers that can transfer data to the TEE without needing shared
memory from client, it is necessary to receive the user address
directly, bypassing any processing by the TEE subsystem. Introduce
TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT/OUTPUT/INOUT to represent
userspace buffers.

Signed-off-by: Amirreza Zarrabi <quic_azarrabi@quicinc.com>
---
 drivers/tee/tee_core.c   | 26 ++++++++++++++++++++++++++
 include/linux/tee_drv.h  |  6 ++++++
 include/uapi/linux/tee.h | 22 ++++++++++++++++------
 3 files changed, 48 insertions(+), 6 deletions(-)

Comments

kernel test robot Dec. 3, 2024, 8:01 a.m. UTC | #1
Hi Amirreza,

kernel test robot noticed the following build warnings:

[auto build test WARNING on f486c8aa16b8172f63bddc70116a0c897a7f3f02]

url:    https://github.com/intel-lab-lkp/linux/commits/Amirreza-Zarrabi/tee-allow-a-driver-to-allocate-a-tee_device-without-a-pool/20241203-122412
base:   f486c8aa16b8172f63bddc70116a0c897a7f3f02
patch link:    https://lore.kernel.org/r/20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-2-f502ef01e016%40quicinc.com
patch subject: [PATCH 02/10] tee: add TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF
config: i386-buildonly-randconfig-002-20241203 (https://download.01.org/0day-ci/archive/20241203/202412031510.Oh9kNGeK-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241203/202412031510.Oh9kNGeK-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202412031510.Oh9kNGeK-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/tee/tee_core.c: In function 'params_to_supp':
>> drivers/tee/tee_core.c:669:32: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     669 |                         ip.a = (u64)p->u.membuf.uaddr;
         |                                ^


vim +669 drivers/tee/tee_core.c

   648	
   649	static int params_to_supp(struct tee_context *ctx,
   650				  struct tee_ioctl_param __user *uparams,
   651				  size_t num_params, struct tee_param *params)
   652	{
   653		size_t n;
   654	
   655		for (n = 0; n < num_params; n++) {
   656			struct tee_ioctl_param ip;
   657			struct tee_param *p = params + n;
   658	
   659			ip.attr = p->attr;
   660			switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
   661			case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
   662			case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
   663				ip.a = p->u.value.a;
   664				ip.b = p->u.value.b;
   665				ip.c = p->u.value.c;
   666				break;
   667			case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT:
   668			case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
 > 669				ip.a = (u64)p->u.membuf.uaddr;
   670				ip.b = p->u.membuf.size;
   671				ip.c = 0;
   672				break;
   673			case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
   674			case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
   675			case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
   676				ip.b = p->u.memref.size;
   677				if (!p->u.memref.shm) {
   678					ip.a = 0;
   679					ip.c = (u64)-1; /* invalid shm id */
   680					break;
   681				}
   682				ip.a = p->u.memref.shm_offs;
   683				ip.c = p->u.memref.shm->id;
   684				break;
   685			default:
   686				ip.a = 0;
   687				ip.b = 0;
   688				ip.c = 0;
   689				break;
   690			}
   691	
   692			if (copy_to_user(uparams + n, &ip, sizeof(ip)))
   693				return -EFAULT;
   694		}
   695	
   696		return 0;
   697	}
   698
Jens Wiklander Dec. 9, 2024, 3:46 p.m. UTC | #2
Hi Amirreza,

On Tue, Dec 3, 2024 at 5:20 AM Amirreza Zarrabi
<quic_azarrabi@quicinc.com> wrote:
>
> For drivers that can transfer data to the TEE without needing shared
> memory from client, it is necessary to receive the user address
> directly, bypassing any processing by the TEE subsystem. Introduce
> TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT/OUTPUT/INOUT to represent
> userspace buffers.

Internally you allocate a bounce buffer from the pool of shared memory
and copy the content of the user space buffer into that.
Wouldn't it be fair to replace "without needing shared memory" with
"without using shared memory"?

>
> Signed-off-by: Amirreza Zarrabi <quic_azarrabi@quicinc.com>
> ---
>  drivers/tee/tee_core.c   | 26 ++++++++++++++++++++++++++
>  include/linux/tee_drv.h  |  6 ++++++
>  include/uapi/linux/tee.h | 22 ++++++++++++++++------
>  3 files changed, 48 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index 24edce4cdbaa..942ff5b359b2 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -381,6 +381,16 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
>                         params[n].u.value.b = ip.b;
>                         params[n].u.value.c = ip.c;
>                         break;
> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT:
> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT:
> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
> +                       params[n].u.membuf.uaddr = u64_to_user_ptr(ip.a);
> +                       params[n].u.membuf.size = ip.b;
> +
> +                       if (!access_ok(params[n].u.membuf.uaddr, params[n].u.membuf.size))
> +                               return -EFAULT;
> +
> +                       break;
>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
> @@ -449,6 +459,11 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
>                             put_user(p->u.value.c, &up->c))
>                                 return -EFAULT;
>                         break;
> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT:
> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
> +                       if (put_user((u64)p->u.membuf.size, &up->b))
> +                               return -EFAULT;
> +                       break;
>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
>                         if (put_user((u64)p->u.memref.size, &up->b))
> @@ -649,6 +664,12 @@ static int params_to_supp(struct tee_context *ctx,
>                         ip.b = p->u.value.b;
>                         ip.c = p->u.value.c;
>                         break;
> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT:
> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
> +                       ip.a = (u64)p->u.membuf.uaddr;
> +                       ip.b = p->u.membuf.size;
> +                       ip.c = 0;
> +                       break;
>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
> @@ -751,6 +772,11 @@ static int params_from_supp(struct tee_param *params, size_t num_params,
>                         p->u.value.b = ip.b;
>                         p->u.value.c = ip.c;
>                         break;
> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT:
> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
> +                       p->u.membuf.uaddr = u64_to_user_ptr(ip.a);
> +                       p->u.membuf.size = ip.b;
> +                       break;
>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
>                         /*
> diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
> index a54c203000ed..b66e611fece4 100644
> --- a/include/linux/tee_drv.h
> +++ b/include/linux/tee_drv.h
> @@ -82,6 +82,11 @@ struct tee_param_memref {
>         struct tee_shm *shm;
>  };
>
> +struct tee_param_membuf {

I would prefer tee_param_ubuf to better describe what it is.

> +       void * __user uaddr;
> +       size_t size;
> +};
> +
>  struct tee_param_value {
>         u64 a;
>         u64 b;
> @@ -92,6 +97,7 @@ struct tee_param {
>         u64 attr;
>         union {
>                 struct tee_param_memref memref;
> +               struct tee_param_membuf membuf;
>                 struct tee_param_value value;
>         } u;
>  };
> diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h
> index d0430bee8292..fae68386968a 100644
> --- a/include/uapi/linux/tee.h
> +++ b/include/uapi/linux/tee.h
> @@ -151,6 +151,13 @@ struct tee_ioctl_buf_data {
>  #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT        6
>  #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7       /* input and output */
>
> +/*
> + * These defines memory buffer parameters.

user space buffer

> + */
> +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT 8
> +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT        9
> +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT 10      /* input and output */

TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_*

> +
>  /*
>   * Mask for the type part of the attribute, leaves room for more types
>   */
> @@ -186,14 +193,17 @@ struct tee_ioctl_buf_data {
>  /**
>   * struct tee_ioctl_param - parameter
>   * @attr: attributes
> - * @a: if a memref, offset into the shared memory object, else a value parameter
> - * @b: if a memref, size of the buffer, else a value parameter
> + * @a: if a memref, offset into the shared memory object,
> + *     else if a membuf, address into the user buffer,
> + *     else a value parameter
> + * @b: if a memref or membuf, size of the buffer, else a value parameter
>   * @c: if a memref, shared memory identifier, else a value parameter
>   *
> - * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in
> - * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and
> - * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE
> - * indicates that none of the members are used.
> + * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref, membuf, or value is
> + * used in the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value,
> + * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref, and TEE_PARAM_ATTR_TYPE_MEMBUF_*
> + * indicates membuf. TEE_PARAM_ATTR_TYPE_NONE indicates that none of the members
> + * are used.
>   *
>   * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an
>   * identifier representing the shared memory object. A memref can reference

Please update the comment above with UBUF and ubuf as needed.

Cheers,
Jens

>
> --
> 2.34.1
>
Amirreza Zarrabi Dec. 9, 2024, 11 p.m. UTC | #3
Hi Jens.

On 12/10/2024 2:46 AM, Jens Wiklander wrote:
> Hi Amirreza,
> 
> On Tue, Dec 3, 2024 at 5:20 AM Amirreza Zarrabi
> <quic_azarrabi@quicinc.com> wrote:
>>
>> For drivers that can transfer data to the TEE without needing shared
>> memory from client, it is necessary to receive the user address
>> directly, bypassing any processing by the TEE subsystem. Introduce
>> TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT/OUTPUT/INOUT to represent
>> userspace buffers.
> 
> Internally you allocate a bounce buffer from the pool of shared memory
> and copy the content of the user space buffer into that.
> Wouldn't it be fair to replace "without needing shared memory" with
> "without using shared memory"?
> 

You are right. I'll update it.

>>
>> Signed-off-by: Amirreza Zarrabi <quic_azarrabi@quicinc.com>
>> ---
>>  drivers/tee/tee_core.c   | 26 ++++++++++++++++++++++++++
>>  include/linux/tee_drv.h  |  6 ++++++
>>  include/uapi/linux/tee.h | 22 ++++++++++++++++------
>>  3 files changed, 48 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
>> index 24edce4cdbaa..942ff5b359b2 100644
>> --- a/drivers/tee/tee_core.c
>> +++ b/drivers/tee/tee_core.c
>> @@ -381,6 +381,16 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
>>                         params[n].u.value.b = ip.b;
>>                         params[n].u.value.c = ip.c;
>>                         break;
>> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT:
>> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT:
>> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
>> +                       params[n].u.membuf.uaddr = u64_to_user_ptr(ip.a);
>> +                       params[n].u.membuf.size = ip.b;
>> +
>> +                       if (!access_ok(params[n].u.membuf.uaddr, params[n].u.membuf.size))
>> +                               return -EFAULT;
>> +
>> +                       break;
>>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
>>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
>>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
>> @@ -449,6 +459,11 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
>>                             put_user(p->u.value.c, &up->c))
>>                                 return -EFAULT;
>>                         break;
>> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT:
>> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
>> +                       if (put_user((u64)p->u.membuf.size, &up->b))
>> +                               return -EFAULT;
>> +                       break;
>>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
>>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
>>                         if (put_user((u64)p->u.memref.size, &up->b))
>> @@ -649,6 +664,12 @@ static int params_to_supp(struct tee_context *ctx,
>>                         ip.b = p->u.value.b;
>>                         ip.c = p->u.value.c;
>>                         break;
>> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT:
>> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
>> +                       ip.a = (u64)p->u.membuf.uaddr;
>> +                       ip.b = p->u.membuf.size;
>> +                       ip.c = 0;
>> +                       break;
>>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
>>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
>>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
>> @@ -751,6 +772,11 @@ static int params_from_supp(struct tee_param *params, size_t num_params,
>>                         p->u.value.b = ip.b;
>>                         p->u.value.c = ip.c;
>>                         break;
>> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT:
>> +               case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
>> +                       p->u.membuf.uaddr = u64_to_user_ptr(ip.a);
>> +                       p->u.membuf.size = ip.b;
>> +                       break;
>>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
>>                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
>>                         /*
>> diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
>> index a54c203000ed..b66e611fece4 100644
>> --- a/include/linux/tee_drv.h
>> +++ b/include/linux/tee_drv.h
>> @@ -82,6 +82,11 @@ struct tee_param_memref {
>>         struct tee_shm *shm;
>>  };
>>
>> +struct tee_param_membuf {
> 
> I would prefer tee_param_ubuf to better describe what it is.
> 

Ack.

>> +       void * __user uaddr;
>> +       size_t size;
>> +};
>> +
>>  struct tee_param_value {
>>         u64 a;
>>         u64 b;
>> @@ -92,6 +97,7 @@ struct tee_param {
>>         u64 attr;
>>         union {
>>                 struct tee_param_memref memref;
>> +               struct tee_param_membuf membuf;
>>                 struct tee_param_value value;
>>         } u;
>>  };
>> diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h
>> index d0430bee8292..fae68386968a 100644
>> --- a/include/uapi/linux/tee.h
>> +++ b/include/uapi/linux/tee.h
>> @@ -151,6 +151,13 @@ struct tee_ioctl_buf_data {
>>  #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT        6
>>  #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7       /* input and output */
>>
>> +/*
>> + * These defines memory buffer parameters.
> 
> user space buffer
> 
>> + */
>> +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT 8
>> +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT        9
>> +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT 10      /* input and output */
> 
> TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_*
> 

Ack.

>> +
>>  /*
>>   * Mask for the type part of the attribute, leaves room for more types
>>   */
>> @@ -186,14 +193,17 @@ struct tee_ioctl_buf_data {
>>  /**
>>   * struct tee_ioctl_param - parameter
>>   * @attr: attributes
>> - * @a: if a memref, offset into the shared memory object, else a value parameter
>> - * @b: if a memref, size of the buffer, else a value parameter
>> + * @a: if a memref, offset into the shared memory object,
>> + *     else if a membuf, address into the user buffer,
>> + *     else a value parameter
>> + * @b: if a memref or membuf, size of the buffer, else a value parameter
>>   * @c: if a memref, shared memory identifier, else a value parameter
>>   *
>> - * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in
>> - * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and
>> - * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE
>> - * indicates that none of the members are used.
>> + * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref, membuf, or value is
>> + * used in the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value,
>> + * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref, and TEE_PARAM_ATTR_TYPE_MEMBUF_*
>> + * indicates membuf. TEE_PARAM_ATTR_TYPE_NONE indicates that none of the members
>> + * are used.
>>   *
>>   * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an
>>   * identifier representing the shared memory object. A memref can reference
> 
> Please update the comment above with UBUF and ubuf as needed.
> 

Ack.

> Cheers,
> Jens
> 

Best Regadrs,
Amir

>>
>> --
>> 2.34.1
>>
diff mbox series

Patch

diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 24edce4cdbaa..942ff5b359b2 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -381,6 +381,16 @@  static int params_from_user(struct tee_context *ctx, struct tee_param *params,
 			params[n].u.value.b = ip.b;
 			params[n].u.value.c = ip.c;
 			break;
+		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT:
+		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT:
+		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
+			params[n].u.membuf.uaddr = u64_to_user_ptr(ip.a);
+			params[n].u.membuf.size = ip.b;
+
+			if (!access_ok(params[n].u.membuf.uaddr, params[n].u.membuf.size))
+				return -EFAULT;
+
+			break;
 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
@@ -449,6 +459,11 @@  static int params_to_user(struct tee_ioctl_param __user *uparams,
 			    put_user(p->u.value.c, &up->c))
 				return -EFAULT;
 			break;
+		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT:
+		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
+			if (put_user((u64)p->u.membuf.size, &up->b))
+				return -EFAULT;
+			break;
 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
 			if (put_user((u64)p->u.memref.size, &up->b))
@@ -649,6 +664,12 @@  static int params_to_supp(struct tee_context *ctx,
 			ip.b = p->u.value.b;
 			ip.c = p->u.value.c;
 			break;
+		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT:
+		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
+			ip.a = (u64)p->u.membuf.uaddr;
+			ip.b = p->u.membuf.size;
+			ip.c = 0;
+			break;
 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
@@ -751,6 +772,11 @@  static int params_from_supp(struct tee_param *params, size_t num_params,
 			p->u.value.b = ip.b;
 			p->u.value.c = ip.c;
 			break;
+		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT:
+		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT:
+			p->u.membuf.uaddr = u64_to_user_ptr(ip.a);
+			p->u.membuf.size = ip.b;
+			break;
 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
 			/*
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index a54c203000ed..b66e611fece4 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -82,6 +82,11 @@  struct tee_param_memref {
 	struct tee_shm *shm;
 };
 
+struct tee_param_membuf {
+	void * __user uaddr;
+	size_t size;
+};
+
 struct tee_param_value {
 	u64 a;
 	u64 b;
@@ -92,6 +97,7 @@  struct tee_param {
 	u64 attr;
 	union {
 		struct tee_param_memref memref;
+		struct tee_param_membuf membuf;
 		struct tee_param_value value;
 	} u;
 };
diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h
index d0430bee8292..fae68386968a 100644
--- a/include/uapi/linux/tee.h
+++ b/include/uapi/linux/tee.h
@@ -151,6 +151,13 @@  struct tee_ioctl_buf_data {
 #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT	6
 #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT	7	/* input and output */
 
+/*
+ * These defines memory buffer parameters.
+ */
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INPUT	8
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT	9
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT	10	/* input and output */
+
 /*
  * Mask for the type part of the attribute, leaves room for more types
  */
@@ -186,14 +193,17 @@  struct tee_ioctl_buf_data {
 /**
  * struct tee_ioctl_param - parameter
  * @attr: attributes
- * @a: if a memref, offset into the shared memory object, else a value parameter
- * @b: if a memref, size of the buffer, else a value parameter
+ * @a: if a memref, offset into the shared memory object,
+ *     else if a membuf, address into the user buffer,
+ *     else a value parameter
+ * @b: if a memref or membuf, size of the buffer, else a value parameter
  * @c: if a memref, shared memory identifier, else a value parameter
  *
- * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in
- * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and
- * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE
- * indicates that none of the members are used.
+ * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref, membuf, or value is
+ * used in the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value,
+ * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref, and TEE_PARAM_ATTR_TYPE_MEMBUF_*
+ * indicates membuf. TEE_PARAM_ATTR_TYPE_NONE indicates that none of the members
+ * are used.
  *
  * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an
  * identifier representing the shared memory object. A memref can reference