driver: tee: Handle NULL pointer indication from client
authorCedric Neveux <cedric.neveux@nxp.com>
Mon, 4 Mar 2019 07:54:23 +0000 (08:54 +0100)
committerJens Wiklander <jens.wiklander@linaro.org>
Fri, 21 Aug 2020 06:55:13 +0000 (08:55 +0200)
TEE Client introduce a new capability "TEE_GEN_CAP_MEMREF_NULL"
to handle the support of the shared memory buffer with a NULL pointer.

This capability depends on TEE Capabilities and driver support.
Driver and TEE exchange capabilities at driver initialization.

Signed-off-by: Michael Whitfield <michael.whitfield@nxp.com>
Signed-off-by: Cedric Neveux <cedric.neveux@nxp.com>
Reviewed-by: Joakim Bech <joakim.bech@linaro.org>
Tested-by: Joakim Bech <joakim.bech@linaro.org> (QEMU)
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
drivers/tee/optee/core.c
drivers/tee/optee/optee_smc.h
drivers/tee/tee_core.c
include/linux/tee_drv.h
include/uapi/linux/tee.h

index b373b1b08b6deecc9823c530462a7d08c065a351..cf4718c6d35dacc946bee65ce7549ba7daf5a2db 100644 (file)
@@ -216,6 +216,8 @@ static void optee_get_version(struct tee_device *teedev,
 
        if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
                v.gen_caps |= TEE_GEN_CAP_REG_MEM;
+       if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
+               v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL;
        *vers = v;
 }
 
@@ -262,6 +264,11 @@ static int optee_open(struct tee_context *ctx)
        mutex_init(&ctxdata->mutex);
        INIT_LIST_HEAD(&ctxdata->sess_list);
 
+       if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
+               ctx->cap_memref_null  = true;
+       else
+               ctx->cap_memref_null = false;
+
        ctx->data = ctxdata;
        return 0;
 }
index c72122d9c9972446017643df9988a8d160919788..777ad54d4c2c2077fba3aa490274149fd70e3d02 100644 (file)
@@ -215,6 +215,9 @@ struct optee_smc_get_shm_config_result {
  */
 #define OPTEE_SMC_SEC_CAP_DYNAMIC_SHM          BIT(2)
 
+/* Secure world supports Shared Memory with a NULL buffer reference */
+#define OPTEE_SMC_SEC_CAP_MEMREF_NULL          BIT(4)
+
 #define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
 #define OPTEE_SMC_EXCHANGE_CAPABILITIES \
        OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES)
index 64637e09a09536a4659c43f4b2aef8c783c81d1c..ce0f0309b6ac2a1941c9e06ff65fcc7a46da9f9e 100644 (file)
@@ -383,25 +383,38 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
                        /*
-                        * If we fail to get a pointer to a shared memory
-                        * object (and increase the ref count) from an
-                        * identifier we return an error. All pointers that
-                        * has been added in params have an increased ref
-                        * count. It's the callers responibility to do
-                        * tee_shm_put() on all resolved pointers.
+                        * If a NULL pointer is passed to a TA in the TEE,
+                        * the ip.c IOCTL parameters is set to TEE_MEMREF_NULL
+                        * indicating a NULL memory reference.
                         */
-                       shm = tee_shm_get_from_id(ctx, ip.c);
-                       if (IS_ERR(shm))
-                               return PTR_ERR(shm);
-
-                       /*
-                        * Ensure offset + size does not overflow offset
-                        * and does not overflow the size of the referred
-                        * shared memory object.
-                        */
-                       if ((ip.a + ip.b) < ip.a ||
-                           (ip.a + ip.b) > shm->size) {
-                               tee_shm_put(shm);
+                       if (ip.c != TEE_MEMREF_NULL) {
+                               /*
+                                * If we fail to get a pointer to a shared
+                                * memory object (and increase the ref count)
+                                * from an identifier we return an error. All
+                                * pointers that has been added in params have
+                                * an increased ref count. It's the callers
+                                * responibility to do tee_shm_put() on all
+                                * resolved pointers.
+                                */
+                               shm = tee_shm_get_from_id(ctx, ip.c);
+                               if (IS_ERR(shm))
+                                       return PTR_ERR(shm);
+
+                               /*
+                                * Ensure offset + size does not overflow
+                                * offset and does not overflow the size of
+                                * the referred shared memory object.
+                                */
+                               if ((ip.a + ip.b) < ip.a ||
+                                   (ip.a + ip.b) > shm->size) {
+                                       tee_shm_put(shm);
+                                       return -EINVAL;
+                               }
+                       } else if (ctx->cap_memref_null) {
+                               /* Pass NULL pointer to OP-TEE */
+                               shm = NULL;
+                       } else {
                                return -EINVAL;
                        }
 
index d074302989ddd2fe09145f7200bcc8fdccc2b7a5..cdd049a724b10b5808aafbc09710d8ce81deebd3 100644 (file)
@@ -47,6 +47,8 @@ struct tee_shm_pool;
  *              and just return with an error code. It is needed for requests
  *              that arises from TEE based kernel drivers that should be
  *              non-blocking in nature.
+ * @cap_memref_null: flag indicating if the TEE Client support shared
+ *                   memory buffer with a NULL pointer.
  */
 struct tee_context {
        struct tee_device *teedev;
@@ -54,6 +56,7 @@ struct tee_context {
        struct kref refcount;
        bool releasing;
        bool supp_nowait;
+       bool cap_memref_null;
 };
 
 struct tee_param_memref {
index b619f37ee03e5376b8452e92d7821d395a8107d3..d67cadf221fc21632f6cdab5b9c73b0a42c8df6a 100644 (file)
@@ -51,6 +51,9 @@
 #define TEE_GEN_CAP_GP         (1 << 0)/* GlobalPlatform compliant TEE */
 #define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplicant) */
 #define TEE_GEN_CAP_REG_MEM    (1 << 2)/* Supports registering shared memory */
+#define TEE_GEN_CAP_MEMREF_NULL        (1 << 3)/* NULL MemRef support */
+
+#define TEE_MEMREF_NULL                (__u64)(-1) /* NULL MemRef Buffer */
 
 /*
  * TEE Implementation ID
@@ -200,6 +203,16 @@ struct tee_ioctl_buf_data {
  * a part of a shared memory by specifying an offset (@a) and size (@b) of
  * the object. To supply the entire shared memory object set the offset
  * (@a) to 0 and size (@b) to the previously returned size of the object.
+ *
+ * A client may need to present a NULL pointer in the argument
+ * passed to a trusted application in the TEE.
+ * This is also a requirement in GlobalPlatform Client API v1.0c
+ * (section 3.2.5 memory references), which can be found at
+ * http://www.globalplatform.org/specificationsdevice.asp
+ *
+ * If a NULL pointer is passed to a TA in the TEE, the (@c)
+ * IOCTL parameters value must be set to TEE_MEMREF_NULL indicating a NULL
+ * memory reference.
  */
 struct tee_ioctl_param {
        __u64 attr;