Commit d5b8b0fa authored by Amirreza Zarrabi's avatar Amirreza Zarrabi Committed by Jens Wiklander
Browse files

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: default avatarSumit Garg <sumit.garg@oss.qualcomm.com>
Tested-by: default avatarNeil Armstrong <neil.armstrong@linaro.org>
Tested-by: default avatarHarshal Dev <quic_hdev@quicinc.com>
Signed-off-by: default avatarAmirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
Signed-off-by: default avatarJens Wiklander <jens.wiklander@linaro.org>
parent 54a53e95
Loading
Loading
Loading
Loading
+85 −0
Original line number Diff line number Diff line
@@ -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 @@ static int tee_ioctl_invoke(struct tee_context *ctx,
	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:
+4 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ struct tee_device {
 * @close_session:	close a session
 * @system_session:	declare session as a system session
 * @invoke_func:	invoke a trusted function
 * @object_invoke_func:	invoke a TEE object
 * @cancel_req:		request cancel of an ongoing invoke or open
 * @supp_recv:		called for supplicant to get a command
 * @supp_send:		called for supplicant to send a response
@@ -108,6 +109,9 @@ struct tee_driver_ops {
	int (*invoke_func)(struct tee_context *ctx,
			   struct tee_ioctl_invoke_arg *arg,
			   struct tee_param *param);
	int (*object_invoke_func)(struct tee_context *ctx,
				  struct tee_ioctl_object_invoke_arg *arg,
				  struct tee_param *param);
	int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session);
	int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params,
			 struct tee_param *param);
+6 −0
Original line number Diff line number Diff line
@@ -87,6 +87,11 @@ struct tee_param_ubuf {
	size_t size;
};

struct tee_param_objref {
	u64 id;
	u64 flags;
};

struct tee_param_value {
	u64 a;
	u64 b;
@@ -97,6 +102,7 @@ struct tee_param {
	u64 attr;
	union {
		struct tee_param_memref memref;
		struct tee_param_objref objref;
		struct tee_param_ubuf ubuf;
		struct tee_param_value value;
	} u;
+35 −6
Original line number Diff line number Diff line
@@ -48,8 +48,10 @@
#define TEE_GEN_CAP_PRIVILEGED	(1 << 1)/* Privileged device (for supplicant) */
#define TEE_GEN_CAP_REG_MEM	(1 << 2)/* Supports registering shared memory */
#define TEE_GEN_CAP_MEMREF_NULL	(1 << 3)/* NULL MemRef support */
#define TEE_GEN_CAP_OBJREF	(1 << 4)/* Supports generic object reference */

#define TEE_MEMREF_NULL		(__u64)(-1) /* NULL MemRef Buffer */
#define TEE_MEMREF_NULL		((__u64)(-1)) /* NULL MemRef Buffer */
#define TEE_OBJREF_NULL		((__u64)(-1)) /* NULL ObjRef Object */

/*
 * TEE Implementation ID
@@ -158,6 +160,13 @@ struct tee_ioctl_buf_data {
#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT	9
#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT	10	/* input and output */

/*
 * These defines object reference parameters.
 */
#define TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT	11
#define TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT	12
#define TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT	13

/*
 * Mask for the type part of the attribute, leaves room for more types
 */
@@ -195,15 +204,16 @@ struct tee_ioctl_buf_data {
 * @attr: attributes
 * @a: if a memref, offset into the shared memory object,
 *     else if a ubuf, address of the user buffer,
 *     else a value parameter
 * @b: if a memref or ubuf, size of the buffer, else a value parameter
 *     else if an objref, object identifier, else a value parameter
 * @b: if a memref or ubuf, size of the buffer,
 *     else if objref, flags for the object, else a value parameter
 * @c: if a memref, shared memory identifier, else a value parameter
 *
 * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref, ubuf, 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_UBUF_*
 * indicates ubuf. TEE_PARAM_ATTR_TYPE_NONE indicates that none of the members
 * are used.
 * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref, TEE_PARAM_ATTR_TYPE_UBUF_*
 * indicates ubuf, and TEE_PARAM_ATTR_TYPE_OBJREF_* indicates objref.
 * 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
@@ -442,4 +452,23 @@ struct tee_ioctl_shm_register_fd_data {
 * munmap(): unmaps previously shared memory
 */

/**
 * struct tee_ioctl_invoke_func_arg - Invokes an object in a Trusted Application
 * @id:		[in] Object id
 * @op:		[in] Object operation, specific to the object
 * @ret:	[out] return value
 * @num_params:	[in] number of parameters following this struct
 */
struct tee_ioctl_object_invoke_arg {
	__u64 id;
	__u32 op;
	__u32 ret;
	__u32 num_params;
	/* num_params tells the actual number of element in params */
	struct tee_ioctl_param params[];
};

#define TEE_IOC_OBJECT_INVOKE	_IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 10, \
				     struct tee_ioctl_buf_data)

#endif /*__TEE_H*/