linux/drivers/tee/optee/supp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2015, Linaro Limited
   4 */
   5#include <linux/device.h>
   6#include <linux/slab.h>
   7#include <linux/uaccess.h>
   8#include "optee_private.h"
   9
  10struct optee_supp_req {
  11        struct list_head link;
  12
  13        bool in_queue;
  14        u32 func;
  15        u32 ret;
  16        size_t num_params;
  17        struct tee_param *param;
  18
  19        struct completion c;
  20};
  21
  22void optee_supp_init(struct optee_supp *supp)
  23{
  24        memset(supp, 0, sizeof(*supp));
  25        mutex_init(&supp->mutex);
  26        init_completion(&supp->reqs_c);
  27        idr_init(&supp->idr);
  28        INIT_LIST_HEAD(&supp->reqs);
  29        supp->req_id = -1;
  30}
  31
  32void optee_supp_uninit(struct optee_supp *supp)
  33{
  34        mutex_destroy(&supp->mutex);
  35        idr_destroy(&supp->idr);
  36}
  37
  38void optee_supp_release(struct optee_supp *supp)
  39{
  40        int id;
  41        struct optee_supp_req *req;
  42        struct optee_supp_req *req_tmp;
  43
  44        mutex_lock(&supp->mutex);
  45
  46        /* Abort all request retrieved by supplicant */
  47        idr_for_each_entry(&supp->idr, req, id) {
  48                idr_remove(&supp->idr, id);
  49                req->ret = TEEC_ERROR_COMMUNICATION;
  50                complete(&req->c);
  51        }
  52
  53        /* Abort all queued requests */
  54        list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) {
  55                list_del(&req->link);
  56                req->in_queue = false;
  57                req->ret = TEEC_ERROR_COMMUNICATION;
  58                complete(&req->c);
  59        }
  60
  61        supp->ctx = NULL;
  62        supp->req_id = -1;
  63
  64        mutex_unlock(&supp->mutex);
  65}
  66
  67/**
  68 * optee_supp_thrd_req() - request service from supplicant
  69 * @ctx:        context doing the request
  70 * @func:       function requested
  71 * @num_params: number of elements in @param array
  72 * @param:      parameters for function
  73 *
  74 * Returns result of operation to be passed to secure world
  75 */
  76u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
  77                        struct tee_param *param)
  78
  79{
  80        struct optee *optee = tee_get_drvdata(ctx->teedev);
  81        struct optee_supp *supp = &optee->supp;
  82        struct optee_supp_req *req;
  83        bool interruptable;
  84        u32 ret;
  85
  86        /*
  87         * Return in case there is no supplicant available and
  88         * non-blocking request.
  89         */
  90        if (!supp->ctx && ctx->supp_nowait)
  91                return TEEC_ERROR_COMMUNICATION;
  92
  93        req = kzalloc(sizeof(*req), GFP_KERNEL);
  94        if (!req)
  95                return TEEC_ERROR_OUT_OF_MEMORY;
  96
  97        init_completion(&req->c);
  98        req->func = func;
  99        req->num_params = num_params;
 100        req->param = param;
 101
 102        /* Insert the request in the request list */
 103        mutex_lock(&supp->mutex);
 104        list_add_tail(&req->link, &supp->reqs);
 105        req->in_queue = true;
 106        mutex_unlock(&supp->mutex);
 107
 108        /* Tell an eventual waiter there's a new request */
 109        complete(&supp->reqs_c);
 110
 111        /*
 112         * Wait for supplicant to process and return result, once we've
 113         * returned from wait_for_completion(&req->c) successfully we have
 114         * exclusive access again.
 115         */
 116        while (wait_for_completion_interruptible(&req->c)) {
 117                mutex_lock(&supp->mutex);
 118                interruptable = !supp->ctx;
 119                if (interruptable) {
 120                        /*
 121                         * There's no supplicant available and since the
 122                         * supp->mutex currently is held none can
 123                         * become available until the mutex released
 124                         * again.
 125                         *
 126                         * Interrupting an RPC to supplicant is only
 127                         * allowed as a way of slightly improving the user
 128                         * experience in case the supplicant hasn't been
 129                         * started yet. During normal operation the supplicant
 130                         * will serve all requests in a timely manner and
 131                         * interrupting then wouldn't make sense.
 132                         */
 133                        if (req->in_queue) {
 134                                list_del(&req->link);
 135                                req->in_queue = false;
 136                        }
 137                }
 138                mutex_unlock(&supp->mutex);
 139
 140                if (interruptable) {
 141                        req->ret = TEEC_ERROR_COMMUNICATION;
 142                        break;
 143                }
 144        }
 145
 146        ret = req->ret;
 147        kfree(req);
 148
 149        return ret;
 150}
 151
 152static struct optee_supp_req  *supp_pop_entry(struct optee_supp *supp,
 153                                              int num_params, int *id)
 154{
 155        struct optee_supp_req *req;
 156
 157        if (supp->req_id != -1) {
 158                /*
 159                 * Supplicant should not mix synchronous and asnynchronous
 160                 * requests.
 161                 */
 162                return ERR_PTR(-EINVAL);
 163        }
 164
 165        if (list_empty(&supp->reqs))
 166                return NULL;
 167
 168        req = list_first_entry(&supp->reqs, struct optee_supp_req, link);
 169
 170        if (num_params < req->num_params) {
 171                /* Not enough room for parameters */
 172                return ERR_PTR(-EINVAL);
 173        }
 174
 175        *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
 176        if (*id < 0)
 177                return ERR_PTR(-ENOMEM);
 178
 179        list_del(&req->link);
 180        req->in_queue = false;
 181
 182        return req;
 183}
 184
 185static int supp_check_recv_params(size_t num_params, struct tee_param *params,
 186                                  size_t *num_meta)
 187{
 188        size_t n;
 189
 190        if (!num_params)
 191                return -EINVAL;
 192
 193        /*
 194         * If there's memrefs we need to decrease those as they where
 195         * increased earlier and we'll even refuse to accept any below.
 196         */
 197        for (n = 0; n < num_params; n++)
 198                if (tee_param_is_memref(params + n) && params[n].u.memref.shm)
 199                        tee_shm_put(params[n].u.memref.shm);
 200
 201        /*
 202         * We only expect parameters as TEE_IOCTL_PARAM_ATTR_TYPE_NONE with
 203         * or without the TEE_IOCTL_PARAM_ATTR_META bit set.
 204         */
 205        for (n = 0; n < num_params; n++)
 206                if (params[n].attr &&
 207                    params[n].attr != TEE_IOCTL_PARAM_ATTR_META)
 208                        return -EINVAL;
 209
 210        /* At most we'll need one meta parameter so no need to check for more */
 211        if (params->attr == TEE_IOCTL_PARAM_ATTR_META)
 212                *num_meta = 1;
 213        else
 214                *num_meta = 0;
 215
 216        return 0;
 217}
 218
 219/**
 220 * optee_supp_recv() - receive request for supplicant
 221 * @ctx:        context receiving the request
 222 * @func:       requested function in supplicant
 223 * @num_params: number of elements allocated in @param, updated with number
 224 *              used elements
 225 * @param:      space for parameters for @func
 226 *
 227 * Returns 0 on success or <0 on failure
 228 */
 229int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
 230                    struct tee_param *param)
 231{
 232        struct tee_device *teedev = ctx->teedev;
 233        struct optee *optee = tee_get_drvdata(teedev);
 234        struct optee_supp *supp = &optee->supp;
 235        struct optee_supp_req *req = NULL;
 236        int id;
 237        size_t num_meta;
 238        int rc;
 239
 240        rc = supp_check_recv_params(*num_params, param, &num_meta);
 241        if (rc)
 242                return rc;
 243
 244        while (true) {
 245                mutex_lock(&supp->mutex);
 246                req = supp_pop_entry(supp, *num_params - num_meta, &id);
 247                mutex_unlock(&supp->mutex);
 248
 249                if (req) {
 250                        if (IS_ERR(req))
 251                                return PTR_ERR(req);
 252                        break;
 253                }
 254
 255                /*
 256                 * If we didn't get a request we'll block in
 257                 * wait_for_completion() to avoid needless spinning.
 258                 *
 259                 * This is where supplicant will be hanging most of
 260                 * the time, let's make this interruptable so we
 261                 * can easily restart supplicant if needed.
 262                 */
 263                if (wait_for_completion_interruptible(&supp->reqs_c))
 264                        return -ERESTARTSYS;
 265        }
 266
 267        if (num_meta) {
 268                /*
 269                 * tee-supplicant support meta parameters -> requsts can be
 270                 * processed asynchronously.
 271                 */
 272                param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
 273                              TEE_IOCTL_PARAM_ATTR_META;
 274                param->u.value.a = id;
 275                param->u.value.b = 0;
 276                param->u.value.c = 0;
 277        } else {
 278                mutex_lock(&supp->mutex);
 279                supp->req_id = id;
 280                mutex_unlock(&supp->mutex);
 281        }
 282
 283        *func = req->func;
 284        *num_params = req->num_params + num_meta;
 285        memcpy(param + num_meta, req->param,
 286               sizeof(struct tee_param) * req->num_params);
 287
 288        return 0;
 289}
 290
 291static struct optee_supp_req *supp_pop_req(struct optee_supp *supp,
 292                                           size_t num_params,
 293                                           struct tee_param *param,
 294                                           size_t *num_meta)
 295{
 296        struct optee_supp_req *req;
 297        int id;
 298        size_t nm;
 299        const u32 attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
 300                         TEE_IOCTL_PARAM_ATTR_META;
 301
 302        if (!num_params)
 303                return ERR_PTR(-EINVAL);
 304
 305        if (supp->req_id == -1) {
 306                if (param->attr != attr)
 307                        return ERR_PTR(-EINVAL);
 308                id = param->u.value.a;
 309                nm = 1;
 310        } else {
 311                id = supp->req_id;
 312                nm = 0;
 313        }
 314
 315        req = idr_find(&supp->idr, id);
 316        if (!req)
 317                return ERR_PTR(-ENOENT);
 318
 319        if ((num_params - nm) != req->num_params)
 320                return ERR_PTR(-EINVAL);
 321
 322        idr_remove(&supp->idr, id);
 323        supp->req_id = -1;
 324        *num_meta = nm;
 325
 326        return req;
 327}
 328
 329/**
 330 * optee_supp_send() - send result of request from supplicant
 331 * @ctx:        context sending result
 332 * @ret:        return value of request
 333 * @num_params: number of parameters returned
 334 * @param:      returned parameters
 335 *
 336 * Returns 0 on success or <0 on failure.
 337 */
 338int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
 339                    struct tee_param *param)
 340{
 341        struct tee_device *teedev = ctx->teedev;
 342        struct optee *optee = tee_get_drvdata(teedev);
 343        struct optee_supp *supp = &optee->supp;
 344        struct optee_supp_req *req;
 345        size_t n;
 346        size_t num_meta;
 347
 348        mutex_lock(&supp->mutex);
 349        req = supp_pop_req(supp, num_params, param, &num_meta);
 350        mutex_unlock(&supp->mutex);
 351
 352        if (IS_ERR(req)) {
 353                /* Something is wrong, let supplicant restart. */
 354                return PTR_ERR(req);
 355        }
 356
 357        /* Update out and in/out parameters */
 358        for (n = 0; n < req->num_params; n++) {
 359                struct tee_param *p = req->param + n;
 360
 361                switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
 362                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
 363                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
 364                        p->u.value.a = param[n + num_meta].u.value.a;
 365                        p->u.value.b = param[n + num_meta].u.value.b;
 366                        p->u.value.c = param[n + num_meta].u.value.c;
 367                        break;
 368                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
 369                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
 370                        p->u.memref.size = param[n + num_meta].u.memref.size;
 371                        break;
 372                default:
 373                        break;
 374                }
 375        }
 376        req->ret = ret;
 377
 378        /* Let the requesting thread continue */
 379        complete(&req->c);
 380
 381        return 0;
 382}
 383