aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tee
diff options
context:
space:
mode:
authorAmirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>2025-09-11 21:07:45 -0700
committerJens Wiklander <jens.wiklander@linaro.org>2025-09-15 17:34:06 +0200
commitd5b8b0fa1775d8b59c3fc9e4aa2baa715d08f3ee (patch)
tree77c81e827b840b2a70db64ea58163e730e4a66fb /drivers/tee
parenttee: add TEE_IOCTL_PARAM_ATTR_TYPE_UBUF (diff)
downloadlinux-d5b8b0fa1775d8b59c3fc9e4aa2baa715d08f3ee.tar.gz
linux-d5b8b0fa1775d8b59c3fc9e4aa2baa715d08f3ee.zip
tee: add TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF
The TEE subsystem allows session-based access to trusted services, requiring a session to be established to receive a service. This is not suitable for an environment that represents services as objects. An object supports various operations that a client can invoke, potentially generating a result or a new object that can be invoked independently of the original object. Add TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT/OUTPUT/INOUT to represent an object. Objects may reside in either TEE or userspace. To invoke an object in TEE, introduce a new ioctl. Use the existing SUPPL_RECV and SUPPL_SEND to invoke an object in userspace. Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com> Tested-by: Neil Armstrong <neil.armstrong@linaro.org> Tested-by: Harshal Dev <quic_hdev@quicinc.com> Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Diffstat (limited to 'drivers/tee')
-rw-r--r--drivers/tee/tee_core.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 529738565ebd..71b1bd69f067 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -487,6 +487,7 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT:
break;
case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
@@ -505,6 +506,11 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
return -EFAULT;
break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT:
+ params[n].u.objref.id = ip.a;
+ params[n].u.objref.flags = ip.b;
+ 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:
@@ -543,6 +549,12 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
if (put_user((u64)p->u.ubuf.size, &up->b))
return -EFAULT;
break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT:
+ if (put_user(p->u.objref.id, &up->a) ||
+ put_user(p->u.objref.flags, &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))
@@ -695,6 +707,66 @@ out:
return rc;
}
+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;
+ struct tee_ioctl_param __user *uparams = NULL;
+ struct tee_param *params = NULL;
+
+ if (!ctx->teedev->desc->ops->object_invoke_func)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_ioctl_object_invoke_arg))
+ return -EINVAL;
+
+ uarg = u64_to_user_ptr(buf.buf_ptr);
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
+ return -EINVAL;
+
+ if (arg.num_params) {
+ params = kcalloc(arg.num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ uparams = uarg->params;
+ rc = params_from_user(ctx, params, arg.num_params, uparams);
+ if (rc)
+ goto out;
+ }
+
+ rc = ctx->teedev->desc->ops->object_invoke_func(ctx, &arg, params);
+ if (rc)
+ goto out;
+
+ if (put_user(arg.ret, &uarg->ret)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ 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);
+ }
+ return rc;
+}
+
static int tee_ioctl_cancel(struct tee_context *ctx,
struct tee_ioctl_cancel_arg __user *uarg)
{
@@ -750,6 +822,12 @@ static int params_to_supp(struct tee_context *ctx,
ip.b = p->u.ubuf.size;
ip.c = 0;
break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT:
+ ip.a = p->u.objref.id;
+ ip.b = p->u.objref.flags;
+ 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:
@@ -862,6 +940,11 @@ static int params_from_supp(struct tee_param *params, size_t num_params,
return -EFAULT;
break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT:
+ p->u.objref.id = ip.a;
+ p->u.objref.flags = ip.b;
+ break;
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
/*
@@ -944,6 +1027,8 @@ static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return tee_ioctl_open_session(ctx, uarg);
case TEE_IOC_INVOKE:
return tee_ioctl_invoke(ctx, uarg);
+ case TEE_IOC_OBJECT_INVOKE:
+ return tee_ioctl_object_invoke(ctx, uarg);
case TEE_IOC_CANCEL:
return tee_ioctl_cancel(ctx, uarg);
case TEE_IOC_CLOSE_SESSION: