691 lines · 18.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/slab.h>#include <linux/uaccess.h> #include "qcomtee.h" /** * DOC: User Objects aka Supplicants * * Any userspace process with access to the TEE device file can behave as a * supplicant by creating a user object. Any TEE parameter of type OBJREF with * %QCOMTEE_OBJREF_FLAG_USER flag set is considered a user object. * * A supplicant uses qcomtee_user_object_select() (i.e. TEE_IOC_SUPPL_RECV) to * receive a QTEE user object request and qcomtee_user_object_submit() * (i.e. TEE_IOC_SUPPL_SEND) to submit a response. QTEE expects to receive the * response, including OB and OO in a specific order in the message; parameters * submitted with qcomtee_user_object_submit() should maintain this order. */ /** * struct qcomtee_user_object - User object. * @object: &struct qcomtee_object representing the user object. * @ctx: context for which the user object is defined. * @object_id: object ID in @ctx. * @notify: notify on release. * * Any object managed in userspace is represented by this struct. * If @notify is set, a notification message is sent back to userspace * upon release. */struct qcomtee_user_object {	struct qcomtee_object object;	struct tee_context *ctx;	u64 object_id;	bool notify;}; #define to_qcomtee_user_object(o) \	container_of((o), struct qcomtee_user_object, object) static struct qcomtee_object_operations qcomtee_user_object_ops; /* Is it a user object? */int is_qcomtee_user_object(struct qcomtee_object *object){	return object != NULL_QCOMTEE_OBJECT &&	       typeof_qcomtee_object(object) == QCOMTEE_OBJECT_TYPE_CB &&	       object->ops == &qcomtee_user_object_ops;} /* Set the user object's 'notify on release' flag. */void qcomtee_user_object_set_notify(struct qcomtee_object *object, bool notify){	if (is_qcomtee_user_object(object))		to_qcomtee_user_object(object)->notify = notify;} /* Supplicant Requests: */ /** * enum qcomtee_req_state - Current state of request. * @QCOMTEE_REQ_QUEUED: Request is waiting for supplicant. * @QCOMTEE_REQ_PROCESSING: Request has been picked by the supplicant. * @QCOMTEE_REQ_PROCESSED: Response has been submitted for the request. */enum qcomtee_req_state {	QCOMTEE_REQ_QUEUED = 1,	QCOMTEE_REQ_PROCESSING,	QCOMTEE_REQ_PROCESSED,}; /* User requests sent to supplicants. */struct qcomtee_ureq {	enum qcomtee_req_state state; 	/* User Request: */	int req_id;	u64 object_id;	u32 op;	struct qcomtee_arg *args;	int errno; 	struct list_head node;	struct completion c; /* Completion for whoever wait. */}; /* * Placeholder for a PROCESSING request in qcomtee_context.reqs_idr. * * If the thread that calls qcomtee_object_invoke() dies and the supplicant * is processing the request, replace the entry in qcomtee_context.reqs_idr * with empty_ureq. This ensures that (1) the req_id remains busy and is not * reused, and (2) the supplicant fails to submit the response and performs * the necessary rollback. */static struct qcomtee_ureq empty_ureq = { .state = QCOMTEE_REQ_PROCESSING }; /* Enqueue a user request for a context and assign a request ID. */static int ureq_enqueue(struct qcomtee_context_data *ctxdata,			struct qcomtee_ureq *ureq){	int ret; 	guard(mutex)(&ctxdata->reqs_lock);	/* Supplicant is dying. */	if (ctxdata->released)		return -ENODEV; 	/* Allocate an ID and queue the request. */	ret = idr_alloc(&ctxdata->reqs_idr, ureq, 0, 0, GFP_KERNEL);	if (ret < 0)		return ret; 	ureq->req_id = ret;	ureq->state = QCOMTEE_REQ_QUEUED;	list_add_tail(&ureq->node, &ctxdata->reqs_list); 	return 0;} /** * ureq_dequeue() - Dequeue a user request from a context. * @ctxdata: context data for a context to dequeue the request. * @req_id: ID of the request to be dequeued. * * It dequeues a user request and releases its request ID. * * Context: The caller should hold &qcomtee_context_data->reqs_lock. * Return: Returns the user request associated with this ID; otherwise, NULL. */static struct qcomtee_ureq *ureq_dequeue(struct qcomtee_context_data *ctxdata,					 int req_id){	struct qcomtee_ureq *ureq; 	ureq = idr_remove(&ctxdata->reqs_idr, req_id);	if (ureq == &empty_ureq || !ureq)		return NULL; 	list_del(&ureq->node); 	return ureq;} /** * ureq_select() - Select the next request in a context. * @ctxdata: context data for a context to pop a request. * @ubuf_size: size of the available buffer for UBUF parameters. * @num_params: number of entries for the TEE parameter array. * * It checks if @num_params is large enough to fit the next request arguments. * It checks if @ubuf_size is large enough to fit IB buffer arguments. * * Context: The caller should hold &qcomtee_context_data->reqs_lock. * Return: On success, returns a request; *         on failure, returns NULL and ERR_PTR. */static struct qcomtee_ureq *ureq_select(struct qcomtee_context_data *ctxdata,					size_t ubuf_size, int num_params){	struct qcomtee_ureq *req, *ureq = NULL;	struct qcomtee_arg *u;	int i; 	/* Find the a queued request. */	list_for_each_entry(req, &ctxdata->reqs_list, node) {		if (req->state == QCOMTEE_REQ_QUEUED) {			ureq = req;			break;		}	} 	if (!ureq)		return NULL; 	u = ureq->args;	/* (1) Is there enough TEE parameters? */	if (num_params < qcomtee_args_len(u))		return ERR_PTR(-EINVAL);	/* (2) Is there enough space to pass input buffers? */	qcomtee_arg_for_each_input_buffer(i, u) {		ubuf_size = size_sub(ubuf_size, u[i].b.size);		if (ubuf_size == SIZE_MAX)			return ERR_PTR(-EINVAL); 		ubuf_size = round_down(ubuf_size, 8);	} 	return ureq;} /* Gets called when the user closes the device. */void qcomtee_requests_destroy(struct qcomtee_context_data *ctxdata){	struct qcomtee_ureq *req, *ureq; 	guard(mutex)(&ctxdata->reqs_lock);	/* So ureq_enqueue() refuses new requests from QTEE. */	ctxdata->released = true;	/* ureqs in reqs_list are in QUEUED or PROCESSING (!= empty_ureq) state. */	list_for_each_entry_safe(ureq, req, &ctxdata->reqs_list, node) {		ureq_dequeue(ctxdata, ureq->req_id); 		if (ureq->op != QCOMTEE_MSG_OBJECT_OP_RELEASE) {			ureq->state = QCOMTEE_REQ_PROCESSED;			ureq->errno = -ENODEV; 			complete(&ureq->c);		} else {			kfree(ureq);		}	}} /* User Object API. */ /* User object dispatcher. */static int qcomtee_user_object_dispatch(struct qcomtee_object_invoke_ctx *oic,					struct qcomtee_object *object, u32 op,					struct qcomtee_arg *args){	struct qcomtee_user_object *uo = to_qcomtee_user_object(object);	struct qcomtee_context_data *ctxdata = uo->ctx->data;	int errno; 	struct qcomtee_ureq *ureq __free(kfree) = kzalloc_obj(*ureq);	if (!ureq)		return -ENOMEM; 	init_completion(&ureq->c);	ureq->object_id = uo->object_id;	ureq->op = op;	ureq->args = args; 	/* Queue the request. */	if (ureq_enqueue(ctxdata, ureq))		return -ENODEV;	/* Wakeup supplicant to process it. */	complete(&ctxdata->req_c); 	/*	 * Wait for the supplicant to process the request. Wait as KILLABLE	 * in case the supplicant and invoke thread are both running from the	 * same process, the supplicant crashes, or the shutdown sequence	 * starts with supplicant dies first; otherwise, it stuck indefinitely.	 *	 * If the supplicant processes long-running requests, also use	 * TASK_FREEZABLE to allow the device to safely suspend if needed.	 */	if (!wait_for_completion_state(&ureq->c,				       TASK_KILLABLE | TASK_FREEZABLE)) {		errno = ureq->errno;		if (!errno)			oic->data = no_free_ptr(ureq);	} else {		enum qcomtee_req_state prev_state; 		errno = -ENODEV; 		scoped_guard(mutex, &ctxdata->reqs_lock) {			prev_state = ureq->state;			/* Replace with empty_ureq to keep req_id reserved. */			if (prev_state == QCOMTEE_REQ_PROCESSING) {				list_del(&ureq->node);				idr_replace(&ctxdata->reqs_idr,					    &empty_ureq, ureq->req_id); 			/* Remove as supplicant has never seen this request. */			} else if (prev_state == QCOMTEE_REQ_QUEUED) {				ureq_dequeue(ctxdata, ureq->req_id);			}		} 		/* Supplicant did some work, do not discard it. */		if (prev_state == QCOMTEE_REQ_PROCESSED) {			errno = ureq->errno;			if (!errno)				oic->data = no_free_ptr(ureq);		}	} 	return errno;} /* Gets called after submitting the dispatcher response. */static void qcomtee_user_object_notify(struct qcomtee_object_invoke_ctx *oic,				       struct qcomtee_object *unused_object,				       int err){	struct qcomtee_ureq *ureq = oic->data;	struct qcomtee_arg *u = ureq->args;	int i; 	/*	 * If err, there was a transport issue, and QTEE did not receive the	 * response for the dispatcher. Release the callback object created for	 * QTEE, in addition to the copies of objects kept for the drivers.	 */	qcomtee_arg_for_each_output_object(i, u) {		if (err &&		    (typeof_qcomtee_object(u[i].o) == QCOMTEE_OBJECT_TYPE_CB))			qcomtee_object_put(u[i].o);		qcomtee_object_put(u[i].o);	} 	kfree(ureq);} static void qcomtee_user_object_release(struct qcomtee_object *object){	struct qcomtee_user_object *uo = to_qcomtee_user_object(object);	struct qcomtee_context_data *ctxdata = uo->ctx->data;	struct qcomtee_ureq *ureq; 	/* RELEASE does not require any argument. */	static struct qcomtee_arg args[] = { { .type = QCOMTEE_ARG_TYPE_INV } }; 	if (!uo->notify)		goto out_no_notify; 	ureq = kzalloc_obj(*ureq);	if (!ureq)		goto out_no_notify; 	/* QUEUE a release request: */	ureq->object_id = uo->object_id;	ureq->op = QCOMTEE_MSG_OBJECT_OP_RELEASE;	ureq->args = args;	if (ureq_enqueue(ctxdata, ureq)) {		kfree(ureq);		/* Ignore the notification if it cannot be queued. */		goto out_no_notify;	} 	complete(&ctxdata->req_c); out_no_notify:	teedev_ctx_put(uo->ctx);	kfree(uo);} static struct qcomtee_object_operations qcomtee_user_object_ops = {	.release = qcomtee_user_object_release,	.notify = qcomtee_user_object_notify,	.dispatch = qcomtee_user_object_dispatch,}; /** * qcomtee_user_param_to_object() - OBJREF parameter to &struct qcomtee_object. * @object: object returned. * @param: TEE parameter. * @ctx: context in which the conversion should happen. * * @param is an OBJREF with %QCOMTEE_OBJREF_FLAG_USER flags. * * Return: On success, returns 0; on failure, returns < 0. */int qcomtee_user_param_to_object(struct qcomtee_object **object,				 struct tee_param *param,				 struct tee_context *ctx){	int err; 	struct qcomtee_user_object *user_object __free(kfree) =		kzalloc_obj(*user_object);	if (!user_object)		return -ENOMEM; 	user_object->ctx = ctx;	user_object->object_id = param->u.objref.id;	/* By default, always notify userspace upon release. */	user_object->notify = true;	err = qcomtee_object_user_init(&user_object->object,				       QCOMTEE_OBJECT_TYPE_CB,				       &qcomtee_user_object_ops, "uo-%llu",				       param->u.objref.id);	if (err)		return err;	/* Matching teedev_ctx_put() is in qcomtee_user_object_release(). */	teedev_ctx_get(ctx); 	*object = &no_free_ptr(user_object)->object; 	return 0;} /* Reverse what qcomtee_user_param_to_object() does. */int qcomtee_user_param_from_object(struct tee_param *param,				   struct qcomtee_object *object,				   struct tee_context *ctx){	struct qcomtee_user_object *uo; 	uo = to_qcomtee_user_object(object);	/* Ensure the object is in the same context as the caller. */	if (uo->ctx != ctx)		return -EINVAL; 	param->u.objref.id = uo->object_id;	param->u.objref.flags = QCOMTEE_OBJREF_FLAG_USER; 	/* User objects are valid in userspace; do not keep a copy. */	qcomtee_object_put(object); 	return 0;} /** * qcomtee_cb_params_from_args() - Convert QTEE arguments to TEE parameters. * @params: TEE parameters. * @u: QTEE arguments. * @num_params: number of elements in the parameter array. * @ubuf_addr: user buffer for arguments of type %QCOMTEE_ARG_TYPE_IB. * @ubuf_size: size of the user buffer. * @ctx: context in which the conversion should happen. * * It expects @params to have enough entries for @u. Entries in @params are of * %TEE_IOCTL_PARAM_ATTR_TYPE_NONE. * * Return: On success, returns the number of input parameters; *         on failure, returns < 0. */static int qcomtee_cb_params_from_args(struct tee_param *params,				       struct qcomtee_arg *u, int num_params,				       void __user *ubuf_addr, size_t ubuf_size,				       struct tee_context *ctx){	int i, np;	void __user *uaddr; 	qcomtee_arg_for_each(i, u) {		switch (u[i].type) {		case QCOMTEE_ARG_TYPE_IB:			params[i].attr = TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT; 			/* Underflow already checked in ureq_select(). */			ubuf_size = round_down(ubuf_size - u[i].b.size, 8);			uaddr = (void __user *)(ubuf_addr + ubuf_size); 			params[i].u.ubuf.uaddr = uaddr;			params[i].u.ubuf.size = u[i].b.size;			if (copy_to_user(params[i].u.ubuf.uaddr, u[i].b.addr,					 u[i].b.size))				goto out_failed; 			break;		case QCOMTEE_ARG_TYPE_OB:			params[i].attr = TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT;			/* Let the user knows the maximum size QTEE expects. */			params[i].u.ubuf.size = u[i].b.size; 			break;		case QCOMTEE_ARG_TYPE_IO:			params[i].attr = TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT;			if (qcomtee_objref_from_arg(&params[i], &u[i], ctx))				goto out_failed; 			break;		case QCOMTEE_ARG_TYPE_OO:			params[i].attr =				TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT; 			break;		default: /* Never get here! */			goto out_failed;		}	} 	return i; out_failed:	/* Undo qcomtee_objref_from_arg(). */	for (np = i; np >= 0; np--) {		if (params[np].attr == TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT)			qcomtee_context_del_qtee_object(&params[np], ctx);	} 	/* Release any IO objects not processed. */	for (; u[i].type; i++) {		if (u[i].type == QCOMTEE_ARG_TYPE_IO)			qcomtee_object_put(u[i].o);	} 	return -EINVAL;} /** * qcomtee_cb_params_to_args() - Convert TEE parameters to QTEE arguments. * @u: QTEE arguments. * @params: TEE parameters. * @num_params: number of elements in the parameter array. * @ctx: context in which the conversion should happen. *

Lines 1–500 of 691.