Re: [PATCH] KEYS: trusted: tee: use tee_shm_register_alloc_buf()

From: Jens Wiklander
Date: Tue Aug 08 2023 - 13:17:55 EST


Hi Sumit,

On Mon, Aug 7, 2023 at 9:58 AM Sumit Garg <sumit.garg@xxxxxxxxxx> wrote:
>
> Hi Jens,
>
> On Thu, 3 Aug 2023 at 18:05, Jens Wiklander <jens.wiklander@xxxxxxxxxx> wrote:
> >
> > Prior to this patch was trusted_tee_seal() and trusted_tee_get_random()
> > relying on tee_shm_register_kernel_buf() to share memory with the TEE.
> > Depending on the memory allocation pattern the pages holding the
> > registered buffers overlap with other buffers also shared with the TEE.
> >
>
> The overlap here is due to the fact that we are registering two array
> members of the same struct. This overlap can be removed by registering
> the overall structure at once. But that sounds unnecessary data
> structure type sharing with trusted keys TA.
>
> > The OP-TEE driver using the old SMC based ABI permits overlapping shared
> > buffers, but with the new FF-A based ABI each physical page may only
> > be registered once.
>
> Would it be possible for OP-TEE FF-A ABI to check if a page is already
> registered?

No, there's no such ABI in the FF-A specification.

> If it is then just return success with appropriate page
> offset.

It's more complicated than that. What if only there's a partial registration?

> As otherwise this sounds like an unnecessary restriction for
> users. I don't think the problem is only particular to the trusted
> keys driver but can be reproduced for user-space clients as well.

Indeed, we're dealing with it by using a temporary buffer in the client lib.

>
> >
> > Fix this problem by allocating a temporary page aligned shared memory
> > buffer to be used as a bounce buffer for the needed data buffers.
> >
> > Since TEE trusted keys doesn't depend on registered shared memory
> > support any longer remove that explicit dependency when opening a
> > context to the TEE.
> >
> > Signed-off-by: Jens Wiklander <jens.wiklander@xxxxxxxxxx>
> > ---
> > security/keys/trusted-keys/trusted_tee.c | 68 +++++++++++++-----------
> > 1 file changed, 36 insertions(+), 32 deletions(-)
> >
> > diff --git a/security/keys/trusted-keys/trusted_tee.c b/security/keys/trusted-keys/trusted_tee.c
> > index ac3e270ade69..3085343c489a 100644
> > --- a/security/keys/trusted-keys/trusted_tee.c
> > +++ b/security/keys/trusted-keys/trusted_tee.c
> > @@ -8,6 +8,7 @@
> >
> > #include <linux/err.h>
> > #include <linux/key-type.h>
> > +#include <linux/minmax.h>
> > #include <linux/module.h>
> > #include <linux/slab.h>
> > #include <linux/string.h>
> > @@ -65,38 +66,37 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob)
> > int ret;
> > struct tee_ioctl_invoke_arg inv_arg;
> > struct tee_param param[4];
> > - struct tee_shm *reg_shm_in = NULL, *reg_shm_out = NULL;
> > + struct tee_shm *shm;
> > + uint8_t *buf;
> >
> > memset(&inv_arg, 0, sizeof(inv_arg));
> > memset(&param, 0, sizeof(param));
> >
> > - reg_shm_in = tee_shm_register_kernel_buf(pvt_data.ctx, p->key,
> > - p->key_len);
> > - if (IS_ERR(reg_shm_in)) {
> > - dev_err(pvt_data.dev, "key shm register failed\n");
> > - return PTR_ERR(reg_shm_in);
> > + shm = tee_shm_alloc_kernel_buf(pvt_data.ctx,
> > + p->key_len + sizeof(p->blob));
> > + if (IS_ERR(shm)) {
> > + dev_err(pvt_data.dev, "key shm alloc failed\n");
> > + return PTR_ERR(shm);
> > }
> > -
> > - reg_shm_out = tee_shm_register_kernel_buf(pvt_data.ctx, p->blob,
> > - sizeof(p->blob));
> > - if (IS_ERR(reg_shm_out)) {
> > - dev_err(pvt_data.dev, "blob shm register failed\n");
> > - ret = PTR_ERR(reg_shm_out);
> > + buf = tee_shm_get_va(shm, 0);
> > + if (IS_ERR(buf)) {
> > + ret = PTR_ERR(buf);
> > goto out;
> > }
> > + memcpy(buf, p->key, p->key_len);
>
> These memcpy()'s here and below are undue overheads if we change to
> tee_shm_alloc_kernel_buf().

There's a bit of overhead when entering and exiting the secure world
too, just to save and restore registers. Anyway, trusted_tee_seal()
doesn't together with FF-A without this patch.

Thanks,
Jens

>
> -Sumit
>
> >
> > inv_arg.func = TA_CMD_SEAL;
> > inv_arg.session = pvt_data.session_id;
> > inv_arg.num_params = 4;
> >
> > param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
> > - param[0].u.memref.shm = reg_shm_in;
> > + param[0].u.memref.shm = shm;
> > param[0].u.memref.size = p->key_len;
> > param[0].u.memref.shm_offs = 0;
> > param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
> > - param[1].u.memref.shm = reg_shm_out;
> > + param[1].u.memref.shm = shm;
> > param[1].u.memref.size = sizeof(p->blob);
> > - param[1].u.memref.shm_offs = 0;
> > + param[1].u.memref.shm_offs = p->key_len;
> >
> > ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param);
> > if ((ret < 0) || (inv_arg.ret != 0)) {
> > @@ -104,14 +104,13 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob)
> > inv_arg.ret);
> > ret = -EFAULT;
> > } else {
> > + memcpy(p->blob, buf + p->key_len,
> > + min(param[1].u.memref.size, sizeof(p->blob)));
> > p->blob_len = param[1].u.memref.size;
> > }
> >
> > out:
> > - if (reg_shm_out)
> > - tee_shm_free(reg_shm_out);
> > - if (reg_shm_in)
> > - tee_shm_free(reg_shm_in);
> > + tee_shm_free(shm);
> >
> > return ret;
> > }
> > @@ -166,11 +165,9 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob)
> > p->key_len = param[1].u.memref.size;
> > }
> >
> > + tee_shm_free(reg_shm_out);
> > out:
> > - if (reg_shm_out)
> > - tee_shm_free(reg_shm_out);
> > - if (reg_shm_in)
> > - tee_shm_free(reg_shm_in);
> > + tee_shm_free(reg_shm_in);
> >
> > return ret;
> > }
> > @@ -183,15 +180,21 @@ static int trusted_tee_get_random(unsigned char *key, size_t key_len)
> > int ret;
> > struct tee_ioctl_invoke_arg inv_arg;
> > struct tee_param param[4];
> > - struct tee_shm *reg_shm = NULL;
> > + struct tee_shm *shm;
> > + void *buf;
> >
> > memset(&inv_arg, 0, sizeof(inv_arg));
> > memset(&param, 0, sizeof(param));
> >
> > - reg_shm = tee_shm_register_kernel_buf(pvt_data.ctx, key, key_len);
> > - if (IS_ERR(reg_shm)) {
> > - dev_err(pvt_data.dev, "key shm register failed\n");
> > - return PTR_ERR(reg_shm);
> > + shm = tee_shm_alloc_kernel_buf(pvt_data.ctx, key_len);
> > + if (IS_ERR(shm)) {
> > + dev_err(pvt_data.dev, "key shm alloc failed\n");
> > + return PTR_ERR(shm);
> > + }
> > + buf = tee_shm_get_va(shm, 0);
> > + if (IS_ERR(buf)) {
> > + ret = PTR_ERR(buf);
> > + goto out;
> > }
> >
> > inv_arg.func = TA_CMD_GET_RANDOM;
> > @@ -199,7 +202,7 @@ static int trusted_tee_get_random(unsigned char *key, size_t key_len)
> > inv_arg.num_params = 4;
> >
> > param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
> > - param[0].u.memref.shm = reg_shm;
> > + param[0].u.memref.shm = shm;
> > param[0].u.memref.size = key_len;
> > param[0].u.memref.shm_offs = 0;
> >
> > @@ -209,18 +212,19 @@ static int trusted_tee_get_random(unsigned char *key, size_t key_len)
> > inv_arg.ret);
> > ret = -EFAULT;
> > } else {
> > + memcpy(key, buf, min(param[0].u.memref.size, key_len));
> > ret = param[0].u.memref.size;
> > }
> >
> > - tee_shm_free(reg_shm);
> > +out:
> > + tee_shm_free(shm);
> >
> > return ret;
> > }
> >
> > static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> > {
> > - if (ver->impl_id == TEE_IMPL_ID_OPTEE &&
> > - ver->gen_caps & TEE_GEN_CAP_REG_MEM)
> > + if (ver->impl_id == TEE_IMPL_ID_OPTEE)
> > return 1;
> > else
> > return 0;
> > --
> > 2.34.1
> >