OSDN Git Service

Merge tag 'optee-fixes-for-v5.17' of git://git.linaro.org/people/jens.wiklander/linux...
authorArnd Bergmann <arnd@arndb.de>
Tue, 8 Feb 2022 08:48:43 +0000 (09:48 +0100)
committerArnd Bergmann <arnd@arndb.de>
Tue, 8 Feb 2022 08:48:44 +0000 (09:48 +0100)
OP-TE fixes for v5.17

- Adds error checking in optee_ffa_do_call_with_arg()
- Reintroduces an accidentally lost fix for a memref size check
- Uses bitmap_free() to free memory obtained with bitmap_zalloc()

* tag 'optee-fixes-for-v5.17' of git://git.linaro.org/people/jens.wiklander/linux-tee:
  optee: add error checks in optee_ffa_do_call_with_arg()
  tee: optee: do not check memref size on return from Secure World
  optee: Use bitmap_free() to free bitmap

Link: https://lore.kernel.org/r/20220126102609.GA1516258@jade
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
1  2 
drivers/tee/optee/ffa_abi.c
drivers/tee/optee/smc_abi.c

@@@ -424,7 -424,6 +424,7 @@@ static struct tee_shm_pool_mgr *optee_f
   */
  
  static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
 +                                            struct optee *optee,
                                              struct optee_msg_arg *arg)
  {
        struct tee_shm *shm;
                shm = optee_rpc_cmd_alloc_suppl(ctx, arg->params[0].u.value.b);
                break;
        case OPTEE_RPC_SHM_TYPE_KERNEL:
 -              shm = tee_shm_alloc(ctx, arg->params[0].u.value.b,
 +              shm = tee_shm_alloc(optee->ctx, arg->params[0].u.value.b,
                                    TEE_SHM_MAPPED | TEE_SHM_PRIV);
                break;
        default:
@@@ -494,13 -493,14 +494,13 @@@ err_bad_param
  }
  
  static void handle_ffa_rpc_func_cmd(struct tee_context *ctx,
 +                                  struct optee *optee,
                                    struct optee_msg_arg *arg)
  {
 -      struct optee *optee = tee_get_drvdata(ctx->teedev);
 -
        arg->ret_origin = TEEC_ORIGIN_COMMS;
        switch (arg->cmd) {
        case OPTEE_RPC_CMD_SHM_ALLOC:
 -              handle_ffa_rpc_func_cmd_shm_alloc(ctx, arg);
 +              handle_ffa_rpc_func_cmd_shm_alloc(ctx, optee, arg);
                break;
        case OPTEE_RPC_CMD_SHM_FREE:
                handle_ffa_rpc_func_cmd_shm_free(ctx, optee, arg);
        }
  }
  
 -static void optee_handle_ffa_rpc(struct tee_context *ctx, u32 cmd,
 -                               struct optee_msg_arg *arg)
 +static void optee_handle_ffa_rpc(struct tee_context *ctx, struct optee *optee,
 +                               u32 cmd, struct optee_msg_arg *arg)
  {
        switch (cmd) {
        case OPTEE_FFA_YIELDING_CALL_RETURN_RPC_CMD:
 -              handle_ffa_rpc_func_cmd(ctx, arg);
 +              handle_ffa_rpc_func_cmd(ctx, optee, arg);
                break;
        case OPTEE_FFA_YIELDING_CALL_RETURN_INTERRUPT:
                /* Interrupt delivered by now */
@@@ -582,7 -582,7 +582,7 @@@ static int optee_ffa_yielding_call(stru
                 * above.
                 */
                cond_resched();
 -              optee_handle_ffa_rpc(ctx, data->data1, rpc_arg);
 +              optee_handle_ffa_rpc(ctx, optee, data->data1, rpc_arg);
                cmd = OPTEE_FFA_YIELDING_CALL_RESUME;
                data->data0 = cmd;
                data->data1 = 0;
@@@ -619,9 -619,18 +619,18 @@@ static int optee_ffa_do_call_with_arg(s
                .data2 = (u32)(shm->sec_world_id >> 32),
                .data3 = shm->offset,
        };
-       struct optee_msg_arg *arg = tee_shm_get_va(shm, 0);
-       unsigned int rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
-       struct optee_msg_arg *rpc_arg = tee_shm_get_va(shm, rpc_arg_offs);
+       struct optee_msg_arg *arg;
+       unsigned int rpc_arg_offs;
+       struct optee_msg_arg *rpc_arg;
+       arg = tee_shm_get_va(shm, 0);
+       if (IS_ERR(arg))
+               return PTR_ERR(arg);
+       rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
+       rpc_arg = tee_shm_get_va(shm, rpc_arg_offs);
+       if (IS_ERR(rpc_arg))
+               return PTR_ERR(rpc_arg);
  
        return optee_ffa_yielding_call(ctx, &data, rpc_arg);
  }
@@@ -793,9 -802,7 +802,9 @@@ static int optee_ffa_probe(struct ffa_d
  {
        const struct ffa_dev_ops *ffa_ops;
        unsigned int rpc_arg_count;
 +      struct tee_shm_pool *pool;
        struct tee_device *teedev;
 +      struct tee_context *ctx;
        struct optee *optee;
        int rc;
  
        if (!optee)
                return -ENOMEM;
  
 -      optee->pool = optee_ffa_config_dyn_shm();
 -      if (IS_ERR(optee->pool)) {
 -              rc = PTR_ERR(optee->pool);
 -              optee->pool = NULL;
 -              goto err;
 +      pool = optee_ffa_config_dyn_shm();
 +      if (IS_ERR(pool)) {
 +              rc = PTR_ERR(pool);
 +              goto err_free_optee;
        }
 +      optee->pool = pool;
  
        optee->ops = &optee_ffa_ops;
        optee->ffa.ffa_dev = ffa_dev;
                                  optee);
        if (IS_ERR(teedev)) {
                rc = PTR_ERR(teedev);
 -              goto err;
 +              goto err_free_pool;
        }
        optee->teedev = teedev;
  
                                  optee);
        if (IS_ERR(teedev)) {
                rc = PTR_ERR(teedev);
 -              goto err;
 +              goto err_unreg_teedev;
        }
        optee->supp_teedev = teedev;
  
        rc = tee_device_register(optee->teedev);
        if (rc)
 -              goto err;
 +              goto err_unreg_supp_teedev;
  
        rc = tee_device_register(optee->supp_teedev);
        if (rc)
 -              goto err;
 +              goto err_unreg_supp_teedev;
  
        rc = rhashtable_init(&optee->ffa.global_ids, &shm_rhash_params);
        if (rc)
 -              goto err;
 +              goto err_unreg_supp_teedev;
        mutex_init(&optee->ffa.mutex);
        mutex_init(&optee->call_queue.mutex);
        INIT_LIST_HEAD(&optee->call_queue.waiters);
        optee_supp_init(&optee->supp);
        ffa_dev_set_drvdata(ffa_dev, optee);
 +      ctx = teedev_open(optee->teedev);
 +      if (IS_ERR(ctx))
 +              goto err_rhashtable_free;
 +      optee->ctx = ctx;
        rc = optee_notif_init(optee, OPTEE_DEFAULT_MAX_NOTIF_VALUE);
 -      if (rc) {
 -              optee_ffa_remove(ffa_dev);
 -              return rc;
 -      }
 +      if (rc)
 +              goto err_close_ctx;
  
        rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
 -      if (rc) {
 -              optee_ffa_remove(ffa_dev);
 -              return rc;
 -      }
 +      if (rc)
 +              goto err_unregister_devices;
  
        pr_info("initialized driver\n");
        return 0;
 -err:
 -      /*
 -       * tee_device_unregister() is safe to call even if the
 -       * devices hasn't been registered with
 -       * tee_device_register() yet.
 -       */
 +
 +err_unregister_devices:
 +      optee_unregister_devices();
 +      optee_notif_uninit(optee);
 +err_close_ctx:
 +      teedev_close_context(ctx);
 +err_rhashtable_free:
 +      rhashtable_free_and_destroy(&optee->ffa.global_ids, rh_free_fn, NULL);
 +      optee_supp_uninit(&optee->supp);
 +      mutex_destroy(&optee->call_queue.mutex);
 +err_unreg_supp_teedev:
        tee_device_unregister(optee->supp_teedev);
 +err_unreg_teedev:
        tee_device_unregister(optee->teedev);
 -      if (optee->pool)
 -              tee_shm_pool_free(optee->pool);
 +err_free_pool:
 +      tee_shm_pool_free(pool);
 +err_free_optee:
        kfree(optee);
        return rc;
  }
@@@ -75,16 -75,6 +75,6 @@@ static int from_msg_param_tmp_mem(struc
        p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
        p->u.memref.shm = shm;
  
-       /* Check that the memref is covered by the shm object */
-       if (p->u.memref.size) {
-               size_t o = p->u.memref.shm_offs +
-                          p->u.memref.size - 1;
-               rc = tee_shm_get_pa(shm, o, NULL);
-               if (rc)
-                       return rc;
-       }
        return 0;
  }
  
@@@ -622,7 -612,6 +612,7 @@@ static void handle_rpc_func_cmd_shm_fre
  }
  
  static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
 +                                        struct optee *optee,
                                          struct optee_msg_arg *arg,
                                          struct optee_call_ctx *call_ctx)
  {
                shm = optee_rpc_cmd_alloc_suppl(ctx, sz);
                break;
        case OPTEE_RPC_SHM_TYPE_KERNEL:
 -              shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED | TEE_SHM_PRIV);
 +              shm = tee_shm_alloc(optee->ctx, sz,
 +                                  TEE_SHM_MAPPED | TEE_SHM_PRIV);
                break;
        default:
                arg->ret = TEEC_ERROR_BAD_PARAMETERS;
@@@ -749,7 -737,7 +739,7 @@@ static void handle_rpc_func_cmd(struct 
        switch (arg->cmd) {
        case OPTEE_RPC_CMD_SHM_ALLOC:
                free_pages_list(call_ctx);
 -              handle_rpc_func_cmd_shm_alloc(ctx, arg, call_ctx);
 +              handle_rpc_func_cmd_shm_alloc(ctx, optee, arg, call_ctx);
                break;
        case OPTEE_RPC_CMD_SHM_FREE:
                handle_rpc_func_cmd_shm_free(ctx, arg);
@@@ -778,7 -766,7 +768,7 @@@ static void optee_handle_rpc(struct tee
  
        switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
        case OPTEE_SMC_RPC_FUNC_ALLOC:
 -              shm = tee_shm_alloc(ctx, param->a1,
 +              shm = tee_shm_alloc(optee->ctx, param->a1,
                                    TEE_SHM_MAPPED | TEE_SHM_PRIV);
                if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
                        reg_pair_from_64(&param->a1, &param->a2, pa);
@@@ -956,34 -944,57 +946,34 @@@ static irqreturn_t notif_irq_thread_fn(
  {
        struct optee *optee = dev_id;
  
 -      optee_smc_do_bottom_half(optee->notif.ctx);
 +      optee_smc_do_bottom_half(optee->ctx);
  
        return IRQ_HANDLED;
  }
  
  static int optee_smc_notif_init_irq(struct optee *optee, u_int irq)
  {
 -      struct tee_context *ctx;
        int rc;
  
 -      ctx = teedev_open(optee->teedev);
 -      if (IS_ERR(ctx))
 -              return PTR_ERR(ctx);
 -
 -      optee->notif.ctx = ctx;
        rc = request_threaded_irq(irq, notif_irq_handler,
                                  notif_irq_thread_fn,
                                  0, "optee_notification", optee);
        if (rc)
 -              goto err_close_ctx;
 +              return rc;
  
        optee->smc.notif_irq = irq;
  
        return 0;
 -
 -err_close_ctx:
 -      teedev_close_context(optee->notif.ctx);
 -      optee->notif.ctx = NULL;
 -
 -      return rc;
  }
  
  static void optee_smc_notif_uninit_irq(struct optee *optee)
  {
 -      if (optee->notif.ctx) {
 -              optee_smc_stop_async_notif(optee->notif.ctx);
 +      if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
 +              optee_smc_stop_async_notif(optee->ctx);
                if (optee->smc.notif_irq) {
                        free_irq(optee->smc.notif_irq, optee);
                        irq_dispose_mapping(optee->smc.notif_irq);
                }
 -
 -              /*
 -               * The thread normally working with optee->notif.ctx was
 -               * stopped with free_irq() above.
 -               *
 -               * Note we're not using teedev_close_context() or
 -               * tee_client_close_context() since we have already called
 -               * tee_device_put() while initializing to avoid a circular
 -               * reference counting.
 -               */
 -              teedev_close_context(optee->notif.ctx);
        }
  }
  
@@@ -1345,7 -1356,6 +1335,7 @@@ static int optee_probe(struct platform_
        struct optee *optee = NULL;
        void *memremaped_shm = NULL;
        struct tee_device *teedev;
 +      struct tee_context *ctx;
        u32 max_notif_value;
        u32 sec_caps;
        int rc;
        optee->pool = pool;
  
        platform_set_drvdata(pdev, optee);
 +      ctx = teedev_open(optee->teedev);
 +      if (IS_ERR(ctx))
 +              goto err_supp_uninit;
 +      optee->ctx = ctx;
        rc = optee_notif_init(optee, max_notif_value);
        if (rc)
 -              goto err_supp_uninit;
 +              goto err_close_ctx;
  
        if (sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
                unsigned int irq;
@@@ -1480,8 -1486,6 +1470,8 @@@ err_disable_shm_cache
        optee_unregister_devices();
  err_notif_uninit:
        optee_notif_uninit(optee);
 +err_close_ctx:
 +      teedev_close_context(ctx);
  err_supp_uninit:
        optee_supp_uninit(&optee->supp);
        mutex_destroy(&optee->call_queue.mutex);