Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2015, Linaro Limited
0004  */
0005 #include <linux/device.h>
0006 #include <linux/slab.h>
0007 #include <linux/uaccess.h>
0008 #include "optee_private.h"
0009 
0010 struct optee_supp_req {
0011     struct list_head link;
0012 
0013     bool in_queue;
0014     u32 func;
0015     u32 ret;
0016     size_t num_params;
0017     struct tee_param *param;
0018 
0019     struct completion c;
0020 };
0021 
0022 void optee_supp_init(struct optee_supp *supp)
0023 {
0024     memset(supp, 0, sizeof(*supp));
0025     mutex_init(&supp->mutex);
0026     init_completion(&supp->reqs_c);
0027     idr_init(&supp->idr);
0028     INIT_LIST_HEAD(&supp->reqs);
0029     supp->req_id = -1;
0030 }
0031 
0032 void optee_supp_uninit(struct optee_supp *supp)
0033 {
0034     mutex_destroy(&supp->mutex);
0035     idr_destroy(&supp->idr);
0036 }
0037 
0038 void optee_supp_release(struct optee_supp *supp)
0039 {
0040     int id;
0041     struct optee_supp_req *req;
0042     struct optee_supp_req *req_tmp;
0043 
0044     mutex_lock(&supp->mutex);
0045 
0046     /* Abort all request retrieved by supplicant */
0047     idr_for_each_entry(&supp->idr, req, id) {
0048         idr_remove(&supp->idr, id);
0049         req->ret = TEEC_ERROR_COMMUNICATION;
0050         complete(&req->c);
0051     }
0052 
0053     /* Abort all queued requests */
0054     list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) {
0055         list_del(&req->link);
0056         req->in_queue = false;
0057         req->ret = TEEC_ERROR_COMMUNICATION;
0058         complete(&req->c);
0059     }
0060 
0061     supp->ctx = NULL;
0062     supp->req_id = -1;
0063 
0064     mutex_unlock(&supp->mutex);
0065 }
0066 
0067 /**
0068  * optee_supp_thrd_req() - request service from supplicant
0069  * @ctx:    context doing the request
0070  * @func:   function requested
0071  * @num_params: number of elements in @param array
0072  * @param:  parameters for function
0073  *
0074  * Returns result of operation to be passed to secure world
0075  */
0076 u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
0077             struct tee_param *param)
0078 
0079 {
0080     struct optee *optee = tee_get_drvdata(ctx->teedev);
0081     struct optee_supp *supp = &optee->supp;
0082     struct optee_supp_req *req;
0083     bool interruptable;
0084     u32 ret;
0085 
0086     /*
0087      * Return in case there is no supplicant available and
0088      * non-blocking request.
0089      */
0090     if (!supp->ctx && ctx->supp_nowait)
0091         return TEEC_ERROR_COMMUNICATION;
0092 
0093     req = kzalloc(sizeof(*req), GFP_KERNEL);
0094     if (!req)
0095         return TEEC_ERROR_OUT_OF_MEMORY;
0096 
0097     init_completion(&req->c);
0098     req->func = func;
0099     req->num_params = num_params;
0100     req->param = param;
0101 
0102     /* Insert the request in the request list */
0103     mutex_lock(&supp->mutex);
0104     list_add_tail(&req->link, &supp->reqs);
0105     req->in_queue = true;
0106     mutex_unlock(&supp->mutex);
0107 
0108     /* Tell an eventual waiter there's a new request */
0109     complete(&supp->reqs_c);
0110 
0111     /*
0112      * Wait for supplicant to process and return result, once we've
0113      * returned from wait_for_completion(&req->c) successfully we have
0114      * exclusive access again.
0115      */
0116     while (wait_for_completion_interruptible(&req->c)) {
0117         mutex_lock(&supp->mutex);
0118         interruptable = !supp->ctx;
0119         if (interruptable) {
0120             /*
0121              * There's no supplicant available and since the
0122              * supp->mutex currently is held none can
0123              * become available until the mutex released
0124              * again.
0125              *
0126              * Interrupting an RPC to supplicant is only
0127              * allowed as a way of slightly improving the user
0128              * experience in case the supplicant hasn't been
0129              * started yet. During normal operation the supplicant
0130              * will serve all requests in a timely manner and
0131              * interrupting then wouldn't make sense.
0132              */
0133             if (req->in_queue) {
0134                 list_del(&req->link);
0135                 req->in_queue = false;
0136             }
0137         }
0138         mutex_unlock(&supp->mutex);
0139 
0140         if (interruptable) {
0141             req->ret = TEEC_ERROR_COMMUNICATION;
0142             break;
0143         }
0144     }
0145 
0146     ret = req->ret;
0147     kfree(req);
0148 
0149     return ret;
0150 }
0151 
0152 static struct optee_supp_req  *supp_pop_entry(struct optee_supp *supp,
0153                           int num_params, int *id)
0154 {
0155     struct optee_supp_req *req;
0156 
0157     if (supp->req_id != -1) {
0158         /*
0159          * Supplicant should not mix synchronous and asnynchronous
0160          * requests.
0161          */
0162         return ERR_PTR(-EINVAL);
0163     }
0164 
0165     if (list_empty(&supp->reqs))
0166         return NULL;
0167 
0168     req = list_first_entry(&supp->reqs, struct optee_supp_req, link);
0169 
0170     if (num_params < req->num_params) {
0171         /* Not enough room for parameters */
0172         return ERR_PTR(-EINVAL);
0173     }
0174 
0175     *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
0176     if (*id < 0)
0177         return ERR_PTR(-ENOMEM);
0178 
0179     list_del(&req->link);
0180     req->in_queue = false;
0181 
0182     return req;
0183 }
0184 
0185 static int supp_check_recv_params(size_t num_params, struct tee_param *params,
0186                   size_t *num_meta)
0187 {
0188     size_t n;
0189 
0190     if (!num_params)
0191         return -EINVAL;
0192 
0193     /*
0194      * If there's memrefs we need to decrease those as they where
0195      * increased earlier and we'll even refuse to accept any below.
0196      */
0197     for (n = 0; n < num_params; n++)
0198         if (tee_param_is_memref(params + n) && params[n].u.memref.shm)
0199             tee_shm_put(params[n].u.memref.shm);
0200 
0201     /*
0202      * We only expect parameters as TEE_IOCTL_PARAM_ATTR_TYPE_NONE with
0203      * or without the TEE_IOCTL_PARAM_ATTR_META bit set.
0204      */
0205     for (n = 0; n < num_params; n++)
0206         if (params[n].attr &&
0207             params[n].attr != TEE_IOCTL_PARAM_ATTR_META)
0208             return -EINVAL;
0209 
0210     /* At most we'll need one meta parameter so no need to check for more */
0211     if (params->attr == TEE_IOCTL_PARAM_ATTR_META)
0212         *num_meta = 1;
0213     else
0214         *num_meta = 0;
0215 
0216     return 0;
0217 }
0218 
0219 /**
0220  * optee_supp_recv() - receive request for supplicant
0221  * @ctx:    context receiving the request
0222  * @func:   requested function in supplicant
0223  * @num_params: number of elements allocated in @param, updated with number
0224  *      used elements
0225  * @param:  space for parameters for @func
0226  *
0227  * Returns 0 on success or <0 on failure
0228  */
0229 int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
0230             struct tee_param *param)
0231 {
0232     struct tee_device *teedev = ctx->teedev;
0233     struct optee *optee = tee_get_drvdata(teedev);
0234     struct optee_supp *supp = &optee->supp;
0235     struct optee_supp_req *req = NULL;
0236     int id;
0237     size_t num_meta;
0238     int rc;
0239 
0240     rc = supp_check_recv_params(*num_params, param, &num_meta);
0241     if (rc)
0242         return rc;
0243 
0244     while (true) {
0245         mutex_lock(&supp->mutex);
0246         req = supp_pop_entry(supp, *num_params - num_meta, &id);
0247         mutex_unlock(&supp->mutex);
0248 
0249         if (req) {
0250             if (IS_ERR(req))
0251                 return PTR_ERR(req);
0252             break;
0253         }
0254 
0255         /*
0256          * If we didn't get a request we'll block in
0257          * wait_for_completion() to avoid needless spinning.
0258          *
0259          * This is where supplicant will be hanging most of
0260          * the time, let's make this interruptable so we
0261          * can easily restart supplicant if needed.
0262          */
0263         if (wait_for_completion_interruptible(&supp->reqs_c))
0264             return -ERESTARTSYS;
0265     }
0266 
0267     if (num_meta) {
0268         /*
0269          * tee-supplicant support meta parameters -> requsts can be
0270          * processed asynchronously.
0271          */
0272         param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
0273                   TEE_IOCTL_PARAM_ATTR_META;
0274         param->u.value.a = id;
0275         param->u.value.b = 0;
0276         param->u.value.c = 0;
0277     } else {
0278         mutex_lock(&supp->mutex);
0279         supp->req_id = id;
0280         mutex_unlock(&supp->mutex);
0281     }
0282 
0283     *func = req->func;
0284     *num_params = req->num_params + num_meta;
0285     memcpy(param + num_meta, req->param,
0286            sizeof(struct tee_param) * req->num_params);
0287 
0288     return 0;
0289 }
0290 
0291 static struct optee_supp_req *supp_pop_req(struct optee_supp *supp,
0292                        size_t num_params,
0293                        struct tee_param *param,
0294                        size_t *num_meta)
0295 {
0296     struct optee_supp_req *req;
0297     int id;
0298     size_t nm;
0299     const u32 attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
0300              TEE_IOCTL_PARAM_ATTR_META;
0301 
0302     if (!num_params)
0303         return ERR_PTR(-EINVAL);
0304 
0305     if (supp->req_id == -1) {
0306         if (param->attr != attr)
0307             return ERR_PTR(-EINVAL);
0308         id = param->u.value.a;
0309         nm = 1;
0310     } else {
0311         id = supp->req_id;
0312         nm = 0;
0313     }
0314 
0315     req = idr_find(&supp->idr, id);
0316     if (!req)
0317         return ERR_PTR(-ENOENT);
0318 
0319     if ((num_params - nm) != req->num_params)
0320         return ERR_PTR(-EINVAL);
0321 
0322     idr_remove(&supp->idr, id);
0323     supp->req_id = -1;
0324     *num_meta = nm;
0325 
0326     return req;
0327 }
0328 
0329 /**
0330  * optee_supp_send() - send result of request from supplicant
0331  * @ctx:    context sending result
0332  * @ret:    return value of request
0333  * @num_params: number of parameters returned
0334  * @param:  returned parameters
0335  *
0336  * Returns 0 on success or <0 on failure.
0337  */
0338 int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
0339             struct tee_param *param)
0340 {
0341     struct tee_device *teedev = ctx->teedev;
0342     struct optee *optee = tee_get_drvdata(teedev);
0343     struct optee_supp *supp = &optee->supp;
0344     struct optee_supp_req *req;
0345     size_t n;
0346     size_t num_meta;
0347 
0348     mutex_lock(&supp->mutex);
0349     req = supp_pop_req(supp, num_params, param, &num_meta);
0350     mutex_unlock(&supp->mutex);
0351 
0352     if (IS_ERR(req)) {
0353         /* Something is wrong, let supplicant restart. */
0354         return PTR_ERR(req);
0355     }
0356 
0357     /* Update out and in/out parameters */
0358     for (n = 0; n < req->num_params; n++) {
0359         struct tee_param *p = req->param + n;
0360 
0361         switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
0362         case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
0363         case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
0364             p->u.value.a = param[n + num_meta].u.value.a;
0365             p->u.value.b = param[n + num_meta].u.value.b;
0366             p->u.value.c = param[n + num_meta].u.value.c;
0367             break;
0368         case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
0369         case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
0370             p->u.memref.size = param[n + num_meta].u.memref.size;
0371             break;
0372         default:
0373             break;
0374         }
0375     }
0376     req->ret = ret;
0377 
0378     /* Let the requesting thread continue */
0379     complete(&req->c);
0380 
0381     return 0;
0382 }