[PATCH v5 06/12] KEYS: trusted: TEE: Synchronize session lifetime
Sumit Garg
sumit.garg at kernel.org
Sun Nov 8 22:55:05 PST 2026
Hey Jarkko,
On Mon, 09 Nov 2026 at 00:27:12 +0200, Jarkko Sakkinen wrote:
>The parent TEE device can remove the client device while live instances
>keep trusted.ko loaded.
>
>Update the static calls before invoking backend init() and reset them in
>the case of a failure.
>
>In the TEE backend, guard session context state with a mutex, publish
>pvt_data.dev before registering key_type_trusted and sanitize pvt_data on
>probe failure and removal.
>
>When an active TEE has not been bound, reject seal, unseal and get_random
>with -ENODEV.
>
>Signed-off-by: Jarkko Sakkinen <jarkko at kernel.org>
>---
> security/keys/trusted-keys/trusted_core.c | 15 ++--
> security/keys/trusted-keys/trusted_tee.c | 86 +++++++++++++++++------
> 2 files changed, 75 insertions(+), 26 deletions(-)
>
Looks reasonable to me, FWIW:
Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>
-Sumit
>diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c
>index 0509d9955f2a..11d7d296d063 100644
>--- a/security/keys/trusted-keys/trusted_core.c
>+++ b/security/keys/trusted-keys/trusted_core.c
>@@ -373,14 +373,19 @@ static int __init init_trusted(void)
> if (!get_random)
> get_random = kernel_get_random;
>
>+ static_call_update(trusted_key_seal, trusted_key_sources[i].ops->seal);
>+ static_call_update(trusted_key_unseal, trusted_key_sources[i].ops->unseal);
>+ static_call_update(trusted_key_get_random, get_random);
>+ migratable = trusted_key_sources[i].ops->migratable;
>+
> ret = trusted_key_sources[i].ops->init();
> if (!ret) {
>- static_call_update(trusted_key_seal, trusted_key_sources[i].ops->seal);
>- static_call_update(trusted_key_unseal, trusted_key_sources[i].ops->unseal);
>- static_call_update(trusted_key_get_random, get_random);
>-
> trusted_key_exit = trusted_key_sources[i].ops->exit;
>- migratable = trusted_key_sources[i].ops->migratable;
>+ } else {
>+ static_call_update(trusted_key_seal, NULL);
>+ static_call_update(trusted_key_unseal, NULL);
>+ static_call_update(trusted_key_get_random, NULL);
>+ migratable = 0;
> }
>
> if (!ret || ret != -ENODEV)
>diff --git a/security/keys/trusted-keys/trusted_tee.c b/security/keys/trusted-keys/trusted_tee.c
>index 6e465c8bef5e..ad9c7baddcef 100644
>--- a/security/keys/trusted-keys/trusted_tee.c
>+++ b/security/keys/trusted-keys/trusted_tee.c
>@@ -9,6 +9,7 @@
> #include <linux/err.h>
> #include <linux/key-type.h>
> #include <linux/module.h>
>+#include <linux/mutex.h>
> #include <linux/slab.h>
> #include <linux/string.h>
> #include <linux/tee_drv.h>
>@@ -56,6 +57,8 @@ struct trusted_key_tee_private {
> };
>
> static struct trusted_key_tee_private pvt_data;
>+/* Do not hold this mutex across key type registration or unregistration. */
>+static DEFINE_MUTEX(trusted_key_tee_mutex);
>
> /*
> * Have the TEE seal(encrypt) the symmetric key
>@@ -67,6 +70,12 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob)
> struct tee_param param[4];
> struct tee_shm *reg_shm = NULL;
>
>+ mutex_lock(&trusted_key_tee_mutex);
>+ if (!pvt_data.ctx) {
>+ ret = -ENODEV;
>+ goto out_unlock;
>+ }
>+
> memset(&inv_arg, 0, sizeof(inv_arg));
> memset(¶m, 0, sizeof(param));
>
>@@ -74,7 +83,8 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob)
> sizeof(p->key) + sizeof(p->blob));
> if (IS_ERR(reg_shm)) {
> dev_err(pvt_data.dev, "shm register failed\n");
>- return PTR_ERR(reg_shm);
>+ ret = PTR_ERR(reg_shm);
>+ goto out_unlock;
> }
>
> inv_arg.func = TA_CMD_SEAL;
>@@ -100,7 +110,8 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob)
> }
>
> tee_shm_free(reg_shm);
>-
>+out_unlock:
>+ mutex_unlock(&trusted_key_tee_mutex);
> return ret;
> }
>
>@@ -114,6 +125,12 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob)
> struct tee_param param[4];
> struct tee_shm *reg_shm = NULL;
>
>+ mutex_lock(&trusted_key_tee_mutex);
>+ if (!pvt_data.ctx) {
>+ ret = -ENODEV;
>+ goto out_unlock;
>+ }
>+
> memset(&inv_arg, 0, sizeof(inv_arg));
> memset(¶m, 0, sizeof(param));
>
>@@ -121,7 +138,8 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob)
> sizeof(p->key) + sizeof(p->blob));
> if (IS_ERR(reg_shm)) {
> dev_err(pvt_data.dev, "shm register failed\n");
>- return PTR_ERR(reg_shm);
>+ ret = PTR_ERR(reg_shm);
>+ goto out_unlock;
> }
>
> inv_arg.func = TA_CMD_UNSEAL;
>@@ -147,7 +165,8 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob)
> }
>
> tee_shm_free(reg_shm);
>-
>+out_unlock:
>+ mutex_unlock(&trusted_key_tee_mutex);
> return ret;
> }
>
>@@ -161,13 +180,20 @@ static int trusted_tee_get_random(unsigned char *key, size_t key_len)
> struct tee_param param[4];
> struct tee_shm *reg_shm = NULL;
>
>+ mutex_lock(&trusted_key_tee_mutex);
>+ if (!pvt_data.ctx) {
>+ ret = -ENODEV;
>+ goto out_unlock;
>+ }
>+
> memset(&inv_arg, 0, sizeof(inv_arg));
> memset(¶m, 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);
>+ ret = PTR_ERR(reg_shm);
>+ goto out_unlock;
> }
>
> inv_arg.func = TA_CMD_GET_RANDOM;
>@@ -189,7 +215,8 @@ static int trusted_tee_get_random(unsigned char *key, size_t key_len)
> }
>
> tee_shm_free(reg_shm);
>-
>+out_unlock:
>+ mutex_unlock(&trusted_key_tee_mutex);
> return ret;
> }
>
>@@ -205,50 +232,67 @@ static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> static int trusted_key_probe(struct tee_client_device *rng_device)
> {
> struct device *dev = &rng_device->dev;
>+ struct tee_context *ctx;
> int ret;
> struct tee_ioctl_open_session_arg sess_arg;
>
>+ mutex_lock(&trusted_key_tee_mutex);
>+ if (pvt_data.ctx) {
>+ ret = -EBUSY;
>+ goto out_unlock;
>+ }
>+
> memset(&sess_arg, 0, sizeof(sess_arg));
>
>- pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL,
>- NULL);
>- if (IS_ERR(pvt_data.ctx))
>- return -ENODEV;
>+ ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
>+ if (IS_ERR(ctx)) {
>+ ret = -ENODEV;
>+ goto out_unlock;
>+ }
>
> memcpy(sess_arg.uuid, rng_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
> sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
> sess_arg.num_params = 0;
>
>- ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL);
>+ ret = tee_client_open_session(ctx, &sess_arg, NULL);
> if ((ret < 0) || (sess_arg.ret != 0)) {
> dev_err(dev, "tee_client_open_session failed, err: %x\n",
> sess_arg.ret);
> ret = -EINVAL;
> goto out_ctx;
> }
>+ pvt_data.ctx = ctx;
> pvt_data.session_id = sess_arg.session;
>-
>- ret = register_key_type(&key_type_trusted);
>- if (ret < 0)
>- goto out_sess;
>-
> pvt_data.dev = dev;
>+ mutex_unlock(&trusted_key_tee_mutex);
>
>- return 0;
>+ ret = register_key_type(&key_type_trusted);
>+ if (!ret)
>+ return 0;
>
>-out_sess:
>- tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
>+ mutex_lock(&trusted_key_tee_mutex);
>+ tee_client_close_session(ctx, pvt_data.session_id);
> out_ctx:
>- tee_client_close_context(pvt_data.ctx);
>-
>+ tee_client_close_context(ctx);
>+ pvt_data.ctx = NULL;
>+ pvt_data.dev = NULL;
>+ pvt_data.session_id = 0;
>+out_unlock:
>+ mutex_unlock(&trusted_key_tee_mutex);
> return ret;
> }
>
> static void trusted_key_remove(struct tee_client_device *dev)
> {
> unregister_key_type(&key_type_trusted);
>+
>+ mutex_lock(&trusted_key_tee_mutex);
> tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
> tee_client_close_context(pvt_data.ctx);
>+ pvt_data.ctx = NULL;
>+ pvt_data.dev = NULL;
>+ pvt_data.session_id = 0;
>+ mutex_unlock(&trusted_key_tee_mutex);
> }
>
> static const struct tee_client_device_id trusted_key_id_table[] = {
>--
>2.47.3
>
More information about the linux-afs
mailing list