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>
This commit is contained in:
Amirreza Zarrabi
2025-09-11 21:07:45 -07:00
committed by Jens Wiklander
parent 54a53e95a9
commit d5b8b0fa17
4 changed files with 130 additions and 6 deletions

View File

@@ -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: