.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2015-2016, Linaro Limited |
---|
3 | | - * |
---|
4 | | - * This software is licensed under the terms of the GNU General Public |
---|
5 | | - * License version 2, as published by the Free Software Foundation, and |
---|
6 | | - * may be copied, distributed, and modified under those terms. |
---|
7 | | - * |
---|
8 | | - * This program is distributed in the hope that it will be useful, |
---|
9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
11 | | - * GNU General Public License for more details. |
---|
12 | | - * |
---|
13 | 4 | */ |
---|
14 | 5 | |
---|
15 | 6 | #define pr_fmt(fmt) "%s: " fmt, __func__ |
---|
16 | 7 | |
---|
17 | 8 | #include <linux/cdev.h> |
---|
18 | | -#include <linux/device.h> |
---|
| 9 | +#include <linux/cred.h> |
---|
19 | 10 | #include <linux/fs.h> |
---|
20 | 11 | #include <linux/idr.h> |
---|
21 | 12 | #include <linux/module.h> |
---|
22 | 13 | #include <linux/slab.h> |
---|
23 | 14 | #include <linux/tee_drv.h> |
---|
24 | 15 | #include <linux/uaccess.h> |
---|
| 16 | +#include <crypto/hash.h> |
---|
| 17 | +#include <crypto/sha.h> |
---|
25 | 18 | #include "tee_private.h" |
---|
26 | 19 | |
---|
27 | 20 | #define TEE_NUM_DEVICES 32 |
---|
28 | 21 | |
---|
29 | 22 | #define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x)) |
---|
| 23 | + |
---|
| 24 | +#define TEE_UUID_NS_NAME_SIZE 128 |
---|
| 25 | + |
---|
| 26 | +/* |
---|
| 27 | + * TEE Client UUID name space identifier (UUIDv4) |
---|
| 28 | + * |
---|
| 29 | + * Value here is random UUID that is allocated as name space identifier for |
---|
| 30 | + * forming Client UUID's for TEE environment using UUIDv5 scheme. |
---|
| 31 | + */ |
---|
| 32 | +static const uuid_t tee_client_uuid_ns = UUID_INIT(0x58ac9ca0, 0x2086, 0x4683, |
---|
| 33 | + 0xa1, 0xb8, 0xec, 0x4b, |
---|
| 34 | + 0xc0, 0x8e, 0x01, 0xb6); |
---|
30 | 35 | |
---|
31 | 36 | /* |
---|
32 | 37 | * Unprivileged devices in the lower half range and privileged devices in |
---|
.. | .. |
---|
38 | 43 | static struct class *tee_class; |
---|
39 | 44 | static dev_t tee_devt; |
---|
40 | 45 | |
---|
41 | | -static int tee_open(struct inode *inode, struct file *filp) |
---|
| 46 | +struct tee_context *teedev_open(struct tee_device *teedev) |
---|
42 | 47 | { |
---|
43 | 48 | int rc; |
---|
44 | | - struct tee_device *teedev; |
---|
45 | 49 | struct tee_context *ctx; |
---|
46 | 50 | |
---|
47 | | - teedev = container_of(inode->i_cdev, struct tee_device, cdev); |
---|
48 | 51 | if (!tee_device_get(teedev)) |
---|
49 | | - return -EINVAL; |
---|
| 52 | + return ERR_PTR(-EINVAL); |
---|
50 | 53 | |
---|
51 | 54 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
---|
52 | 55 | if (!ctx) { |
---|
.. | .. |
---|
56 | 59 | |
---|
57 | 60 | kref_init(&ctx->refcount); |
---|
58 | 61 | ctx->teedev = teedev; |
---|
59 | | - INIT_LIST_HEAD(&ctx->list_shm); |
---|
60 | | - filp->private_data = ctx; |
---|
61 | 62 | rc = teedev->desc->ops->open(ctx); |
---|
62 | 63 | if (rc) |
---|
63 | 64 | goto err; |
---|
64 | 65 | |
---|
65 | | - return 0; |
---|
| 66 | + return ctx; |
---|
66 | 67 | err: |
---|
67 | 68 | kfree(ctx); |
---|
68 | 69 | tee_device_put(teedev); |
---|
69 | | - return rc; |
---|
| 70 | + return ERR_PTR(rc); |
---|
| 71 | + |
---|
70 | 72 | } |
---|
| 73 | +EXPORT_SYMBOL_GPL(teedev_open); |
---|
71 | 74 | |
---|
72 | 75 | void teedev_ctx_get(struct tee_context *ctx) |
---|
73 | 76 | { |
---|
.. | .. |
---|
94 | 97 | kref_put(&ctx->refcount, teedev_ctx_release); |
---|
95 | 98 | } |
---|
96 | 99 | |
---|
97 | | -static void teedev_close_context(struct tee_context *ctx) |
---|
| 100 | +void teedev_close_context(struct tee_context *ctx) |
---|
98 | 101 | { |
---|
99 | 102 | struct tee_device *teedev = ctx->teedev; |
---|
100 | 103 | |
---|
101 | 104 | teedev_ctx_put(ctx); |
---|
102 | 105 | tee_device_put(teedev); |
---|
| 106 | +} |
---|
| 107 | +EXPORT_SYMBOL_GPL(teedev_close_context); |
---|
| 108 | + |
---|
| 109 | +static int tee_open(struct inode *inode, struct file *filp) |
---|
| 110 | +{ |
---|
| 111 | + struct tee_context *ctx; |
---|
| 112 | + |
---|
| 113 | + ctx = teedev_open(container_of(inode->i_cdev, struct tee_device, cdev)); |
---|
| 114 | + if (IS_ERR(ctx)) |
---|
| 115 | + return PTR_ERR(ctx); |
---|
| 116 | + |
---|
| 117 | + /* |
---|
| 118 | + * Default user-space behaviour is to wait for tee-supplicant |
---|
| 119 | + * if not present for any requests in this context. |
---|
| 120 | + */ |
---|
| 121 | + ctx->supp_nowait = false; |
---|
| 122 | + filp->private_data = ctx; |
---|
| 123 | + return 0; |
---|
103 | 124 | } |
---|
104 | 125 | |
---|
105 | 126 | static int tee_release(struct inode *inode, struct file *filp) |
---|
.. | .. |
---|
107 | 128 | teedev_close_context(filp->private_data); |
---|
108 | 129 | return 0; |
---|
109 | 130 | } |
---|
| 131 | + |
---|
| 132 | +/** |
---|
| 133 | + * uuid_v5() - Calculate UUIDv5 |
---|
| 134 | + * @uuid: Resulting UUID |
---|
| 135 | + * @ns: Name space ID for UUIDv5 function |
---|
| 136 | + * @name: Name for UUIDv5 function |
---|
| 137 | + * @size: Size of name |
---|
| 138 | + * |
---|
| 139 | + * UUIDv5 is specific in RFC 4122. |
---|
| 140 | + * |
---|
| 141 | + * This implements section (for SHA-1): |
---|
| 142 | + * 4.3. Algorithm for Creating a Name-Based UUID |
---|
| 143 | + */ |
---|
| 144 | +static int uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name, |
---|
| 145 | + size_t size) |
---|
| 146 | +{ |
---|
| 147 | + unsigned char hash[SHA1_DIGEST_SIZE]; |
---|
| 148 | + struct crypto_shash *shash = NULL; |
---|
| 149 | + struct shash_desc *desc = NULL; |
---|
| 150 | + int rc; |
---|
| 151 | + |
---|
| 152 | + shash = crypto_alloc_shash("sha1", 0, 0); |
---|
| 153 | + if (IS_ERR(shash)) { |
---|
| 154 | + rc = PTR_ERR(shash); |
---|
| 155 | + pr_err("shash(sha1) allocation failed\n"); |
---|
| 156 | + return rc; |
---|
| 157 | + } |
---|
| 158 | + |
---|
| 159 | + desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash), |
---|
| 160 | + GFP_KERNEL); |
---|
| 161 | + if (!desc) { |
---|
| 162 | + rc = -ENOMEM; |
---|
| 163 | + goto out_free_shash; |
---|
| 164 | + } |
---|
| 165 | + |
---|
| 166 | + desc->tfm = shash; |
---|
| 167 | + |
---|
| 168 | + rc = crypto_shash_init(desc); |
---|
| 169 | + if (rc < 0) |
---|
| 170 | + goto out_free_desc; |
---|
| 171 | + |
---|
| 172 | + rc = crypto_shash_update(desc, (const u8 *)ns, sizeof(*ns)); |
---|
| 173 | + if (rc < 0) |
---|
| 174 | + goto out_free_desc; |
---|
| 175 | + |
---|
| 176 | + rc = crypto_shash_update(desc, (const u8 *)name, size); |
---|
| 177 | + if (rc < 0) |
---|
| 178 | + goto out_free_desc; |
---|
| 179 | + |
---|
| 180 | + rc = crypto_shash_final(desc, hash); |
---|
| 181 | + if (rc < 0) |
---|
| 182 | + goto out_free_desc; |
---|
| 183 | + |
---|
| 184 | + memcpy(uuid->b, hash, UUID_SIZE); |
---|
| 185 | + |
---|
| 186 | + /* Tag for version 5 */ |
---|
| 187 | + uuid->b[6] = (hash[6] & 0x0F) | 0x50; |
---|
| 188 | + uuid->b[8] = (hash[8] & 0x3F) | 0x80; |
---|
| 189 | + |
---|
| 190 | +out_free_desc: |
---|
| 191 | + kfree(desc); |
---|
| 192 | + |
---|
| 193 | +out_free_shash: |
---|
| 194 | + crypto_free_shash(shash); |
---|
| 195 | + return rc; |
---|
| 196 | +} |
---|
| 197 | + |
---|
| 198 | +int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method, |
---|
| 199 | + const u8 connection_data[TEE_IOCTL_UUID_LEN]) |
---|
| 200 | +{ |
---|
| 201 | + gid_t ns_grp = (gid_t)-1; |
---|
| 202 | + kgid_t grp = INVALID_GID; |
---|
| 203 | + char *name = NULL; |
---|
| 204 | + int name_len; |
---|
| 205 | + int rc; |
---|
| 206 | + |
---|
| 207 | + if (connection_method == TEE_IOCTL_LOGIN_PUBLIC || |
---|
| 208 | + connection_method == TEE_IOCTL_LOGIN_REE_KERNEL) { |
---|
| 209 | + /* Nil UUID to be passed to TEE environment */ |
---|
| 210 | + uuid_copy(uuid, &uuid_null); |
---|
| 211 | + return 0; |
---|
| 212 | + } |
---|
| 213 | + |
---|
| 214 | + /* |
---|
| 215 | + * In Linux environment client UUID is based on UUIDv5. |
---|
| 216 | + * |
---|
| 217 | + * Determine client UUID with following semantics for 'name': |
---|
| 218 | + * |
---|
| 219 | + * For TEEC_LOGIN_USER: |
---|
| 220 | + * uid=<uid> |
---|
| 221 | + * |
---|
| 222 | + * For TEEC_LOGIN_GROUP: |
---|
| 223 | + * gid=<gid> |
---|
| 224 | + * |
---|
| 225 | + */ |
---|
| 226 | + |
---|
| 227 | + name = kzalloc(TEE_UUID_NS_NAME_SIZE, GFP_KERNEL); |
---|
| 228 | + if (!name) |
---|
| 229 | + return -ENOMEM; |
---|
| 230 | + |
---|
| 231 | + switch (connection_method) { |
---|
| 232 | + case TEE_IOCTL_LOGIN_USER: |
---|
| 233 | + name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "uid=%x", |
---|
| 234 | + current_euid().val); |
---|
| 235 | + if (name_len >= TEE_UUID_NS_NAME_SIZE) { |
---|
| 236 | + rc = -E2BIG; |
---|
| 237 | + goto out_free_name; |
---|
| 238 | + } |
---|
| 239 | + break; |
---|
| 240 | + |
---|
| 241 | + case TEE_IOCTL_LOGIN_GROUP: |
---|
| 242 | + memcpy(&ns_grp, connection_data, sizeof(gid_t)); |
---|
| 243 | + grp = make_kgid(current_user_ns(), ns_grp); |
---|
| 244 | + if (!gid_valid(grp) || !in_egroup_p(grp)) { |
---|
| 245 | + rc = -EPERM; |
---|
| 246 | + goto out_free_name; |
---|
| 247 | + } |
---|
| 248 | + |
---|
| 249 | + name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "gid=%x", |
---|
| 250 | + grp.val); |
---|
| 251 | + if (name_len >= TEE_UUID_NS_NAME_SIZE) { |
---|
| 252 | + rc = -E2BIG; |
---|
| 253 | + goto out_free_name; |
---|
| 254 | + } |
---|
| 255 | + break; |
---|
| 256 | + |
---|
| 257 | + default: |
---|
| 258 | + rc = -EINVAL; |
---|
| 259 | + goto out_free_name; |
---|
| 260 | + } |
---|
| 261 | + |
---|
| 262 | + rc = uuid_v5(uuid, &tee_client_uuid_ns, name, name_len); |
---|
| 263 | +out_free_name: |
---|
| 264 | + kfree(name); |
---|
| 265 | + |
---|
| 266 | + return rc; |
---|
| 267 | +} |
---|
| 268 | +EXPORT_SYMBOL_GPL(tee_session_calc_client_uuid); |
---|
110 | 269 | |
---|
111 | 270 | static int tee_ioctl_version(struct tee_context *ctx, |
---|
112 | 271 | struct tee_ioctl_version_data __user *uvers) |
---|
.. | .. |
---|
175 | 334 | if (data.flags) |
---|
176 | 335 | return -EINVAL; |
---|
177 | 336 | |
---|
| 337 | + if (!access_ok((void __user *)(unsigned long)data.addr, data.length)) |
---|
| 338 | + return -EFAULT; |
---|
| 339 | + |
---|
178 | 340 | shm = tee_shm_register(ctx, data.addr, data.length, |
---|
179 | 341 | TEE_SHM_DMA_BUF | TEE_SHM_USER_MAPPED); |
---|
180 | 342 | if (IS_ERR(shm)) |
---|
.. | .. |
---|
229 | 391 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: |
---|
230 | 392 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: |
---|
231 | 393 | /* |
---|
232 | | - * If we fail to get a pointer to a shared memory |
---|
233 | | - * object (and increase the ref count) from an |
---|
234 | | - * identifier we return an error. All pointers that |
---|
235 | | - * has been added in params have an increased ref |
---|
236 | | - * count. It's the callers responibility to do |
---|
237 | | - * tee_shm_put() on all resolved pointers. |
---|
| 394 | + * If a NULL pointer is passed to a TA in the TEE, |
---|
| 395 | + * the ip.c IOCTL parameters is set to TEE_MEMREF_NULL |
---|
| 396 | + * indicating a NULL memory reference. |
---|
238 | 397 | */ |
---|
239 | | - shm = tee_shm_get_from_id(ctx, ip.c); |
---|
240 | | - if (IS_ERR(shm)) |
---|
241 | | - return PTR_ERR(shm); |
---|
| 398 | + if (ip.c != TEE_MEMREF_NULL) { |
---|
| 399 | + /* |
---|
| 400 | + * If we fail to get a pointer to a shared |
---|
| 401 | + * memory object (and increase the ref count) |
---|
| 402 | + * from an identifier we return an error. All |
---|
| 403 | + * pointers that has been added in params have |
---|
| 404 | + * an increased ref count. It's the callers |
---|
| 405 | + * responibility to do tee_shm_put() on all |
---|
| 406 | + * resolved pointers. |
---|
| 407 | + */ |
---|
| 408 | + shm = tee_shm_get_from_id(ctx, ip.c); |
---|
| 409 | + if (IS_ERR(shm)) |
---|
| 410 | + return PTR_ERR(shm); |
---|
242 | 411 | |
---|
243 | | - /* |
---|
244 | | - * Ensure offset + size does not overflow offset |
---|
245 | | - * and does not overflow the size of the referred |
---|
246 | | - * shared memory object. |
---|
247 | | - */ |
---|
248 | | - if ((ip.a + ip.b) < ip.a || |
---|
249 | | - (ip.a + ip.b) > shm->size) { |
---|
250 | | - tee_shm_put(shm); |
---|
| 412 | + /* |
---|
| 413 | + * Ensure offset + size does not overflow |
---|
| 414 | + * offset and does not overflow the size of |
---|
| 415 | + * the referred shared memory object. |
---|
| 416 | + */ |
---|
| 417 | + if ((ip.a + ip.b) < ip.a || |
---|
| 418 | + (ip.a + ip.b) > shm->size) { |
---|
| 419 | + tee_shm_put(shm); |
---|
| 420 | + return -EINVAL; |
---|
| 421 | + } |
---|
| 422 | + } else if (ctx->cap_memref_null) { |
---|
| 423 | + /* Pass NULL pointer to OP-TEE */ |
---|
| 424 | + shm = NULL; |
---|
| 425 | + } else { |
---|
251 | 426 | return -EINVAL; |
---|
252 | 427 | } |
---|
253 | 428 | |
---|
.. | .. |
---|
329 | 504 | rc = params_from_user(ctx, params, arg.num_params, uparams); |
---|
330 | 505 | if (rc) |
---|
331 | 506 | goto out; |
---|
| 507 | + } |
---|
| 508 | + |
---|
| 509 | + if (arg.clnt_login >= TEE_IOCTL_LOGIN_REE_KERNEL_MIN && |
---|
| 510 | + arg.clnt_login <= TEE_IOCTL_LOGIN_REE_KERNEL_MAX) { |
---|
| 511 | + pr_debug("login method not allowed for user-space client\n"); |
---|
| 512 | + rc = -EPERM; |
---|
| 513 | + goto out; |
---|
332 | 514 | } |
---|
333 | 515 | |
---|
334 | 516 | rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params); |
---|
.. | .. |
---|
672 | 854 | .open = tee_open, |
---|
673 | 855 | .release = tee_release, |
---|
674 | 856 | .unlocked_ioctl = tee_ioctl, |
---|
675 | | - .compat_ioctl = tee_ioctl, |
---|
| 857 | + .compat_ioctl = compat_ptr_ioctl, |
---|
676 | 858 | }; |
---|
677 | 859 | |
---|
678 | 860 | static void tee_release_device(struct device *dev) |
---|
.. | .. |
---|
756 | 938 | |
---|
757 | 939 | cdev_init(&teedev->cdev, &tee_fops); |
---|
758 | 940 | teedev->cdev.owner = teedesc->owner; |
---|
759 | | - teedev->cdev.kobj.parent = &teedev->dev.kobj; |
---|
760 | 941 | |
---|
761 | 942 | dev_set_drvdata(&teedev->dev, driver_data); |
---|
762 | 943 | device_initialize(&teedev->dev); |
---|
.. | .. |
---|
802 | 983 | NULL |
---|
803 | 984 | }; |
---|
804 | 985 | |
---|
805 | | -static const struct attribute_group tee_dev_group = { |
---|
806 | | - .attrs = tee_dev_attrs, |
---|
807 | | -}; |
---|
| 986 | +ATTRIBUTE_GROUPS(tee_dev); |
---|
808 | 987 | |
---|
809 | 988 | /** |
---|
810 | 989 | * tee_device_register() - Registers a TEE device |
---|
.. | .. |
---|
824 | 1003 | return -EINVAL; |
---|
825 | 1004 | } |
---|
826 | 1005 | |
---|
827 | | - rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1); |
---|
| 1006 | + teedev->dev.groups = tee_dev_groups; |
---|
| 1007 | + |
---|
| 1008 | + rc = cdev_device_add(&teedev->cdev, &teedev->dev); |
---|
828 | 1009 | if (rc) { |
---|
829 | 1010 | dev_err(&teedev->dev, |
---|
830 | | - "unable to cdev_add() %s, major %d, minor %d, err=%d\n", |
---|
| 1011 | + "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", |
---|
831 | 1012 | teedev->name, MAJOR(teedev->dev.devt), |
---|
832 | 1013 | MINOR(teedev->dev.devt), rc); |
---|
833 | 1014 | return rc; |
---|
834 | 1015 | } |
---|
835 | 1016 | |
---|
836 | | - rc = device_add(&teedev->dev); |
---|
837 | | - if (rc) { |
---|
838 | | - dev_err(&teedev->dev, |
---|
839 | | - "unable to device_add() %s, major %d, minor %d, err=%d\n", |
---|
840 | | - teedev->name, MAJOR(teedev->dev.devt), |
---|
841 | | - MINOR(teedev->dev.devt), rc); |
---|
842 | | - goto err_device_add; |
---|
843 | | - } |
---|
844 | | - |
---|
845 | | - rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group); |
---|
846 | | - if (rc) { |
---|
847 | | - dev_err(&teedev->dev, |
---|
848 | | - "failed to create sysfs attributes, err=%d\n", rc); |
---|
849 | | - goto err_sysfs_create_group; |
---|
850 | | - } |
---|
851 | | - |
---|
852 | 1017 | teedev->flags |= TEE_DEVICE_FLAG_REGISTERED; |
---|
853 | 1018 | return 0; |
---|
854 | | - |
---|
855 | | -err_sysfs_create_group: |
---|
856 | | - device_del(&teedev->dev); |
---|
857 | | -err_device_add: |
---|
858 | | - cdev_del(&teedev->cdev); |
---|
859 | | - return rc; |
---|
860 | 1019 | } |
---|
861 | 1020 | EXPORT_SYMBOL_GPL(tee_device_register); |
---|
862 | 1021 | |
---|
.. | .. |
---|
899 | 1058 | if (!teedev) |
---|
900 | 1059 | return; |
---|
901 | 1060 | |
---|
902 | | - if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { |
---|
903 | | - sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group); |
---|
904 | | - cdev_del(&teedev->cdev); |
---|
905 | | - device_del(&teedev->dev); |
---|
906 | | - } |
---|
| 1061 | + if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) |
---|
| 1062 | + cdev_device_del(&teedev->cdev, &teedev->dev); |
---|
907 | 1063 | |
---|
908 | 1064 | tee_device_put(teedev); |
---|
909 | 1065 | wait_for_completion(&teedev->c_no_users); |
---|
.. | .. |
---|
930 | 1086 | } |
---|
931 | 1087 | EXPORT_SYMBOL_GPL(tee_get_drvdata); |
---|
932 | 1088 | |
---|
| 1089 | +struct match_dev_data { |
---|
| 1090 | + struct tee_ioctl_version_data *vers; |
---|
| 1091 | + const void *data; |
---|
| 1092 | + int (*match)(struct tee_ioctl_version_data *, const void *); |
---|
| 1093 | +}; |
---|
| 1094 | + |
---|
| 1095 | +static int match_dev(struct device *dev, const void *data) |
---|
| 1096 | +{ |
---|
| 1097 | + const struct match_dev_data *match_data = data; |
---|
| 1098 | + struct tee_device *teedev = container_of(dev, struct tee_device, dev); |
---|
| 1099 | + |
---|
| 1100 | + teedev->desc->ops->get_version(teedev, match_data->vers); |
---|
| 1101 | + return match_data->match(match_data->vers, match_data->data); |
---|
| 1102 | +} |
---|
| 1103 | + |
---|
| 1104 | +struct tee_context * |
---|
| 1105 | +tee_client_open_context(struct tee_context *start, |
---|
| 1106 | + int (*match)(struct tee_ioctl_version_data *, |
---|
| 1107 | + const void *), |
---|
| 1108 | + const void *data, struct tee_ioctl_version_data *vers) |
---|
| 1109 | +{ |
---|
| 1110 | + struct device *dev = NULL; |
---|
| 1111 | + struct device *put_dev = NULL; |
---|
| 1112 | + struct tee_context *ctx = NULL; |
---|
| 1113 | + struct tee_ioctl_version_data v; |
---|
| 1114 | + struct match_dev_data match_data = { vers ? vers : &v, data, match }; |
---|
| 1115 | + |
---|
| 1116 | + if (start) |
---|
| 1117 | + dev = &start->teedev->dev; |
---|
| 1118 | + |
---|
| 1119 | + do { |
---|
| 1120 | + dev = class_find_device(tee_class, dev, &match_data, match_dev); |
---|
| 1121 | + if (!dev) { |
---|
| 1122 | + ctx = ERR_PTR(-ENOENT); |
---|
| 1123 | + break; |
---|
| 1124 | + } |
---|
| 1125 | + |
---|
| 1126 | + put_device(put_dev); |
---|
| 1127 | + put_dev = dev; |
---|
| 1128 | + |
---|
| 1129 | + ctx = teedev_open(container_of(dev, struct tee_device, dev)); |
---|
| 1130 | + } while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM); |
---|
| 1131 | + |
---|
| 1132 | + put_device(put_dev); |
---|
| 1133 | + /* |
---|
| 1134 | + * Default behaviour for in kernel client is to not wait for |
---|
| 1135 | + * tee-supplicant if not present for any requests in this context. |
---|
| 1136 | + * Also this flag could be configured again before call to |
---|
| 1137 | + * tee_client_open_session() if any in kernel client requires |
---|
| 1138 | + * different behaviour. |
---|
| 1139 | + */ |
---|
| 1140 | + if (!IS_ERR(ctx)) |
---|
| 1141 | + ctx->supp_nowait = true; |
---|
| 1142 | + |
---|
| 1143 | + return ctx; |
---|
| 1144 | +} |
---|
| 1145 | +EXPORT_SYMBOL_GPL(tee_client_open_context); |
---|
| 1146 | + |
---|
| 1147 | +void tee_client_close_context(struct tee_context *ctx) |
---|
| 1148 | +{ |
---|
| 1149 | + teedev_close_context(ctx); |
---|
| 1150 | +} |
---|
| 1151 | +EXPORT_SYMBOL_GPL(tee_client_close_context); |
---|
| 1152 | + |
---|
| 1153 | +void tee_client_get_version(struct tee_context *ctx, |
---|
| 1154 | + struct tee_ioctl_version_data *vers) |
---|
| 1155 | +{ |
---|
| 1156 | + ctx->teedev->desc->ops->get_version(ctx->teedev, vers); |
---|
| 1157 | +} |
---|
| 1158 | +EXPORT_SYMBOL_GPL(tee_client_get_version); |
---|
| 1159 | + |
---|
| 1160 | +int tee_client_open_session(struct tee_context *ctx, |
---|
| 1161 | + struct tee_ioctl_open_session_arg *arg, |
---|
| 1162 | + struct tee_param *param) |
---|
| 1163 | +{ |
---|
| 1164 | + if (!ctx->teedev->desc->ops->open_session) |
---|
| 1165 | + return -EINVAL; |
---|
| 1166 | + return ctx->teedev->desc->ops->open_session(ctx, arg, param); |
---|
| 1167 | +} |
---|
| 1168 | +EXPORT_SYMBOL_GPL(tee_client_open_session); |
---|
| 1169 | + |
---|
| 1170 | +int tee_client_close_session(struct tee_context *ctx, u32 session) |
---|
| 1171 | +{ |
---|
| 1172 | + if (!ctx->teedev->desc->ops->close_session) |
---|
| 1173 | + return -EINVAL; |
---|
| 1174 | + return ctx->teedev->desc->ops->close_session(ctx, session); |
---|
| 1175 | +} |
---|
| 1176 | +EXPORT_SYMBOL_GPL(tee_client_close_session); |
---|
| 1177 | + |
---|
| 1178 | +int tee_client_invoke_func(struct tee_context *ctx, |
---|
| 1179 | + struct tee_ioctl_invoke_arg *arg, |
---|
| 1180 | + struct tee_param *param) |
---|
| 1181 | +{ |
---|
| 1182 | + if (!ctx->teedev->desc->ops->invoke_func) |
---|
| 1183 | + return -EINVAL; |
---|
| 1184 | + return ctx->teedev->desc->ops->invoke_func(ctx, arg, param); |
---|
| 1185 | +} |
---|
| 1186 | +EXPORT_SYMBOL_GPL(tee_client_invoke_func); |
---|
| 1187 | + |
---|
| 1188 | +int tee_client_cancel_req(struct tee_context *ctx, |
---|
| 1189 | + struct tee_ioctl_cancel_arg *arg) |
---|
| 1190 | +{ |
---|
| 1191 | + if (!ctx->teedev->desc->ops->cancel_req) |
---|
| 1192 | + return -EINVAL; |
---|
| 1193 | + return ctx->teedev->desc->ops->cancel_req(ctx, arg->cancel_id, |
---|
| 1194 | + arg->session); |
---|
| 1195 | +} |
---|
| 1196 | + |
---|
| 1197 | +static int tee_client_device_match(struct device *dev, |
---|
| 1198 | + struct device_driver *drv) |
---|
| 1199 | +{ |
---|
| 1200 | + const struct tee_client_device_id *id_table; |
---|
| 1201 | + struct tee_client_device *tee_device; |
---|
| 1202 | + |
---|
| 1203 | + id_table = to_tee_client_driver(drv)->id_table; |
---|
| 1204 | + tee_device = to_tee_client_device(dev); |
---|
| 1205 | + |
---|
| 1206 | + while (!uuid_is_null(&id_table->uuid)) { |
---|
| 1207 | + if (uuid_equal(&tee_device->id.uuid, &id_table->uuid)) |
---|
| 1208 | + return 1; |
---|
| 1209 | + id_table++; |
---|
| 1210 | + } |
---|
| 1211 | + |
---|
| 1212 | + return 0; |
---|
| 1213 | +} |
---|
| 1214 | + |
---|
| 1215 | +static int tee_client_device_uevent(struct device *dev, |
---|
| 1216 | + struct kobj_uevent_env *env) |
---|
| 1217 | +{ |
---|
| 1218 | + uuid_t *dev_id = &to_tee_client_device(dev)->id.uuid; |
---|
| 1219 | + |
---|
| 1220 | + return add_uevent_var(env, "MODALIAS=tee:%pUb", dev_id); |
---|
| 1221 | +} |
---|
| 1222 | + |
---|
| 1223 | +struct bus_type tee_bus_type = { |
---|
| 1224 | + .name = "tee", |
---|
| 1225 | + .match = tee_client_device_match, |
---|
| 1226 | + .uevent = tee_client_device_uevent, |
---|
| 1227 | +}; |
---|
| 1228 | +EXPORT_SYMBOL_GPL(tee_bus_type); |
---|
| 1229 | + |
---|
933 | 1230 | static int __init tee_init(void) |
---|
934 | 1231 | { |
---|
935 | 1232 | int rc; |
---|
.. | .. |
---|
943 | 1240 | rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee"); |
---|
944 | 1241 | if (rc) { |
---|
945 | 1242 | pr_err("failed to allocate char dev region\n"); |
---|
946 | | - class_destroy(tee_class); |
---|
947 | | - tee_class = NULL; |
---|
| 1243 | + goto out_unreg_class; |
---|
948 | 1244 | } |
---|
| 1245 | + |
---|
| 1246 | + rc = bus_register(&tee_bus_type); |
---|
| 1247 | + if (rc) { |
---|
| 1248 | + pr_err("failed to register tee bus\n"); |
---|
| 1249 | + goto out_unreg_chrdev; |
---|
| 1250 | + } |
---|
| 1251 | + |
---|
| 1252 | + return 0; |
---|
| 1253 | + |
---|
| 1254 | +out_unreg_chrdev: |
---|
| 1255 | + unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES); |
---|
| 1256 | +out_unreg_class: |
---|
| 1257 | + class_destroy(tee_class); |
---|
| 1258 | + tee_class = NULL; |
---|
949 | 1259 | |
---|
950 | 1260 | return rc; |
---|
951 | 1261 | } |
---|
952 | 1262 | |
---|
953 | 1263 | static void __exit tee_exit(void) |
---|
954 | 1264 | { |
---|
| 1265 | + bus_unregister(&tee_bus_type); |
---|
| 1266 | + unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES); |
---|
955 | 1267 | class_destroy(tee_class); |
---|
956 | 1268 | tee_class = NULL; |
---|
957 | | - unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES); |
---|
958 | 1269 | } |
---|
959 | 1270 | |
---|
960 | 1271 | subsys_initcall(tee_init); |
---|