// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #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; struct qcomtee_ureq *ureq __free(kfree) = NULL; int errno; ureq = kzalloc(sizeof(*ureq), GFP_KERNEL); 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(sizeof(*ureq), GFP_KERNEL); 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) { struct qcomtee_user_object *user_object __free(kfree) = NULL; int err; user_object = kzalloc(sizeof(*user_object), GFP_KERNEL); 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(¶ms[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(¶ms[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. * * Return: On success, returns 0; on failure, returns < 0. */ static int qcomtee_cb_params_to_args(struct qcomtee_arg *u, struct tee_param *params, int num_params, struct tee_context *ctx) { int i; qcomtee_arg_for_each(i, u) { switch (u[i].type) { case QCOMTEE_ARG_TYPE_IB: if (params[i].attr != TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT) goto out_failed; break; case QCOMTEE_ARG_TYPE_OB: if (params[i].attr != TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT) goto out_failed; /* Client can not send more data than requested. */ if (params[i].u.ubuf.size > u[i].b.size) goto out_failed; if (copy_from_user(u[i].b.addr, params[i].u.ubuf.uaddr, params[i].u.ubuf.size)) goto out_failed; u[i].b.size = params[i].u.ubuf.size; break; case QCOMTEE_ARG_TYPE_IO: if (params[i].attr != TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT) goto out_failed; break; case QCOMTEE_ARG_TYPE_OO: if (params[i].attr != TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT) goto out_failed; if (qcomtee_objref_to_arg(&u[i], ¶ms[i], ctx)) goto out_failed; break; default: /* Never get here! */ goto out_failed; } } return 0; out_failed: /* Undo qcomtee_objref_to_arg(). */ for (i--; i >= 0; i--) { if (u[i].type != QCOMTEE_ARG_TYPE_OO) continue; qcomtee_user_object_set_notify(u[i].o, false); if (typeof_qcomtee_object(u[i].o) == QCOMTEE_OBJECT_TYPE_CB) qcomtee_object_put(u[i].o); qcomtee_object_put(u[i].o); } return -EINVAL; } /** * qcomtee_user_object_select() - Select a request for a user object. * @ctx: context to look for a user object. * @params: parameters for @op. * @num_params: number of elements in the parameter array. * @uaddr: user buffer for output UBUF parameters. * @size: size of user buffer @uaddr. * @data: information for the selected request. * * @params is filled along with @data for the selected request. * * Return: On success, returns 0; on failure, returns < 0. */ int qcomtee_user_object_select(struct tee_context *ctx, struct tee_param *params, int num_params, void __user *uaddr, size_t size, struct qcomtee_user_object_request_data *data) { struct qcomtee_context_data *ctxdata = ctx->data; struct qcomtee_ureq *ureq; int ret; /* * Hold the reqs_lock not only for ureq_select() and updating the ureq * state to PROCESSING but for the entire duration of ureq access. * This prevents qcomtee_user_object_dispatch() from freeing * ureq while it is still in use, if client dies. */ while (1) { scoped_guard(mutex, &ctxdata->reqs_lock) { ureq = ureq_select(ctxdata, size, num_params); if (!ureq) goto wait_for_request; if (IS_ERR(ureq)) return PTR_ERR(ureq); /* Processing the request 'QUEUED -> PROCESSING'. */ ureq->state = QCOMTEE_REQ_PROCESSING; /* ''Prepare user request:'' */ data->id = ureq->req_id; data->object_id = ureq->object_id; data->op = ureq->op; ret = qcomtee_cb_params_from_args(params, ureq->args, num_params, uaddr, size, ctx); if (ret >= 0) goto done_request; /* Something is wrong with the request: */ ureq_dequeue(ctxdata, data->id); /* Send error to QTEE. */ ureq->state = QCOMTEE_REQ_PROCESSED; ureq->errno = ret; complete(&ureq->c); } continue; wait_for_request: /* Wait for a new QUEUED request. */ if (wait_for_completion_interruptible(&ctxdata->req_c)) return -ERESTARTSYS; } done_request: /* No one is waiting for the response. */ if (data->op == QCOMTEE_MSG_OBJECT_OP_RELEASE) { scoped_guard(mutex, &ctxdata->reqs_lock) ureq_dequeue(ctxdata, data->id); kfree(ureq); } data->np = ret; return 0; } /** * qcomtee_user_object_submit() - Submit a response for a user object. * @ctx: context to look for a user object. * @params: returned parameters. * @num_params: number of elements in the parameter array. * @req_id: request ID for the response. * @errno: result of user object invocation. * * Return: On success, returns 0; on failure, returns < 0. */ int qcomtee_user_object_submit(struct tee_context *ctx, struct tee_param *params, int num_params, int req_id, int errno) { struct qcomtee_context_data *ctxdata = ctx->data; struct qcomtee_ureq *ureq; /* See comments for reqs_lock in qcomtee_user_object_select(). */ guard(mutex)(&ctxdata->reqs_lock); ureq = ureq_dequeue(ctxdata, req_id); if (!ureq) return -EINVAL; ureq->state = QCOMTEE_REQ_PROCESSED; if (!errno) ureq->errno = qcomtee_cb_params_to_args(ureq->args, params, num_params, ctx); else ureq->errno = errno; /* Return errno if qcomtee_cb_params_to_args() failed; otherwise 0. */ if (!errno && ureq->errno) errno = ureq->errno; else errno = 0; /* Send result to QTEE. */ complete(&ureq->c); return errno; }