| Thomas Gleixner | 9c92ab6 | 2019-05-29 07:17:56 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 2 | /* | 
|  | 3 | * Copyright (c) 2015-2016, Linaro Limited | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 4 | */ | 
|  | 5 |  | 
|  | 6 | #define pr_fmt(fmt) "%s: " fmt, __func__ | 
|  | 7 |  | 
|  | 8 | #include <linux/cdev.h> | 
| Vesa Jääskeläinen | e33bcba | 2020-04-30 15:37:09 +0300 | [diff] [blame] | 9 | #include <linux/cred.h> | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 10 | #include <linux/fs.h> | 
|  | 11 | #include <linux/idr.h> | 
|  | 12 | #include <linux/module.h> | 
|  | 13 | #include <linux/slab.h> | 
|  | 14 | #include <linux/tee_drv.h> | 
|  | 15 | #include <linux/uaccess.h> | 
| Vesa Jääskeläinen | e33bcba | 2020-04-30 15:37:09 +0300 | [diff] [blame] | 16 | #include <crypto/hash.h> | 
| Eric Biggers | a24d22b | 2020-11-12 21:20:21 -0800 | [diff] [blame] | 17 | #include <crypto/sha1.h> | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 18 | #include "tee_private.h" | 
|  | 19 |  | 
|  | 20 | #define TEE_NUM_DEVICES	32 | 
|  | 21 |  | 
|  | 22 | #define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x)) | 
|  | 23 |  | 
| Vesa Jääskeläinen | e33bcba | 2020-04-30 15:37:09 +0300 | [diff] [blame] | 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); | 
|  | 35 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 36 | /* | 
|  | 37 | * Unprivileged devices in the lower half range and privileged devices in | 
|  | 38 | * the upper half range. | 
|  | 39 | */ | 
|  | 40 | static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES); | 
|  | 41 | static DEFINE_SPINLOCK(driver_lock); | 
|  | 42 |  | 
|  | 43 | static struct class *tee_class; | 
|  | 44 | static dev_t tee_devt; | 
|  | 45 |  | 
| Jens Wiklander | 25559c2 | 2018-07-09 08:15:49 +0200 | [diff] [blame] | 46 | static struct tee_context *teedev_open(struct tee_device *teedev) | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 47 | { | 
|  | 48 | int rc; | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 49 | struct tee_context *ctx; | 
|  | 50 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 51 | if (!tee_device_get(teedev)) | 
| Jens Wiklander | 25559c2 | 2018-07-09 08:15:49 +0200 | [diff] [blame] | 52 | return ERR_PTR(-EINVAL); | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 53 |  | 
|  | 54 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | 
|  | 55 | if (!ctx) { | 
|  | 56 | rc = -ENOMEM; | 
|  | 57 | goto err; | 
|  | 58 | } | 
|  | 59 |  | 
| Volodymyr Babchuk | 217e0250 | 2017-11-29 14:48:37 +0200 | [diff] [blame] | 60 | kref_init(&ctx->refcount); | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 61 | ctx->teedev = teedev; | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 62 | rc = teedev->desc->ops->open(ctx); | 
|  | 63 | if (rc) | 
|  | 64 | goto err; | 
|  | 65 |  | 
| Jens Wiklander | 25559c2 | 2018-07-09 08:15:49 +0200 | [diff] [blame] | 66 | return ctx; | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 67 | err: | 
|  | 68 | kfree(ctx); | 
|  | 69 | tee_device_put(teedev); | 
| Jens Wiklander | 25559c2 | 2018-07-09 08:15:49 +0200 | [diff] [blame] | 70 | return ERR_PTR(rc); | 
|  | 71 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 72 | } | 
|  | 73 |  | 
| Volodymyr Babchuk | 217e0250 | 2017-11-29 14:48:37 +0200 | [diff] [blame] | 74 | void teedev_ctx_get(struct tee_context *ctx) | 
|  | 75 | { | 
|  | 76 | if (ctx->releasing) | 
|  | 77 | return; | 
|  | 78 |  | 
|  | 79 | kref_get(&ctx->refcount); | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | static void teedev_ctx_release(struct kref *ref) | 
|  | 83 | { | 
|  | 84 | struct tee_context *ctx = container_of(ref, struct tee_context, | 
|  | 85 | refcount); | 
|  | 86 | ctx->releasing = true; | 
|  | 87 | ctx->teedev->desc->ops->release(ctx); | 
|  | 88 | kfree(ctx); | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | void teedev_ctx_put(struct tee_context *ctx) | 
|  | 92 | { | 
|  | 93 | if (ctx->releasing) | 
|  | 94 | return; | 
|  | 95 |  | 
|  | 96 | kref_put(&ctx->refcount, teedev_ctx_release); | 
|  | 97 | } | 
|  | 98 |  | 
|  | 99 | static void teedev_close_context(struct tee_context *ctx) | 
|  | 100 | { | 
|  | 101 | tee_device_put(ctx->teedev); | 
|  | 102 | teedev_ctx_put(ctx); | 
|  | 103 | } | 
|  | 104 |  | 
| Jens Wiklander | 25559c2 | 2018-07-09 08:15:49 +0200 | [diff] [blame] | 105 | static int tee_open(struct inode *inode, struct file *filp) | 
|  | 106 | { | 
|  | 107 | struct tee_context *ctx; | 
|  | 108 |  | 
|  | 109 | ctx = teedev_open(container_of(inode->i_cdev, struct tee_device, cdev)); | 
|  | 110 | if (IS_ERR(ctx)) | 
|  | 111 | return PTR_ERR(ctx); | 
|  | 112 |  | 
| Sumit Garg | 42bf415 | 2019-01-29 11:19:36 +0530 | [diff] [blame] | 113 | /* | 
|  | 114 | * Default user-space behaviour is to wait for tee-supplicant | 
|  | 115 | * if not present for any requests in this context. | 
|  | 116 | */ | 
|  | 117 | ctx->supp_nowait = false; | 
| Jens Wiklander | 25559c2 | 2018-07-09 08:15:49 +0200 | [diff] [blame] | 118 | filp->private_data = ctx; | 
|  | 119 | return 0; | 
|  | 120 | } | 
|  | 121 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 122 | static int tee_release(struct inode *inode, struct file *filp) | 
|  | 123 | { | 
| Volodymyr Babchuk | 217e0250 | 2017-11-29 14:48:37 +0200 | [diff] [blame] | 124 | teedev_close_context(filp->private_data); | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 125 | return 0; | 
|  | 126 | } | 
|  | 127 |  | 
| Vesa Jääskeläinen | e33bcba | 2020-04-30 15:37:09 +0300 | [diff] [blame] | 128 | /** | 
|  | 129 | * uuid_v5() - Calculate UUIDv5 | 
|  | 130 | * @uuid: Resulting UUID | 
|  | 131 | * @ns: Name space ID for UUIDv5 function | 
|  | 132 | * @name: Name for UUIDv5 function | 
|  | 133 | * @size: Size of name | 
|  | 134 | * | 
|  | 135 | * UUIDv5 is specific in RFC 4122. | 
|  | 136 | * | 
|  | 137 | * This implements section (for SHA-1): | 
|  | 138 | * 4.3.  Algorithm for Creating a Name-Based UUID | 
|  | 139 | */ | 
|  | 140 | static int uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name, | 
|  | 141 | size_t size) | 
|  | 142 | { | 
|  | 143 | unsigned char hash[SHA1_DIGEST_SIZE]; | 
|  | 144 | struct crypto_shash *shash = NULL; | 
|  | 145 | struct shash_desc *desc = NULL; | 
|  | 146 | int rc; | 
|  | 147 |  | 
|  | 148 | shash = crypto_alloc_shash("sha1", 0, 0); | 
|  | 149 | if (IS_ERR(shash)) { | 
|  | 150 | rc = PTR_ERR(shash); | 
|  | 151 | pr_err("shash(sha1) allocation failed\n"); | 
|  | 152 | return rc; | 
|  | 153 | } | 
|  | 154 |  | 
|  | 155 | desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash), | 
|  | 156 | GFP_KERNEL); | 
|  | 157 | if (!desc) { | 
|  | 158 | rc = -ENOMEM; | 
|  | 159 | goto out_free_shash; | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | desc->tfm = shash; | 
|  | 163 |  | 
|  | 164 | rc = crypto_shash_init(desc); | 
|  | 165 | if (rc < 0) | 
|  | 166 | goto out_free_desc; | 
|  | 167 |  | 
|  | 168 | rc = crypto_shash_update(desc, (const u8 *)ns, sizeof(*ns)); | 
|  | 169 | if (rc < 0) | 
|  | 170 | goto out_free_desc; | 
|  | 171 |  | 
|  | 172 | rc = crypto_shash_update(desc, (const u8 *)name, size); | 
|  | 173 | if (rc < 0) | 
|  | 174 | goto out_free_desc; | 
|  | 175 |  | 
|  | 176 | rc = crypto_shash_final(desc, hash); | 
|  | 177 | if (rc < 0) | 
|  | 178 | goto out_free_desc; | 
|  | 179 |  | 
|  | 180 | memcpy(uuid->b, hash, UUID_SIZE); | 
|  | 181 |  | 
|  | 182 | /* Tag for version 5 */ | 
|  | 183 | uuid->b[6] = (hash[6] & 0x0F) | 0x50; | 
|  | 184 | uuid->b[8] = (hash[8] & 0x3F) | 0x80; | 
|  | 185 |  | 
|  | 186 | out_free_desc: | 
|  | 187 | kfree(desc); | 
|  | 188 |  | 
|  | 189 | out_free_shash: | 
|  | 190 | crypto_free_shash(shash); | 
|  | 191 | return rc; | 
|  | 192 | } | 
|  | 193 |  | 
|  | 194 | int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method, | 
|  | 195 | const u8 connection_data[TEE_IOCTL_UUID_LEN]) | 
|  | 196 | { | 
|  | 197 | gid_t ns_grp = (gid_t)-1; | 
|  | 198 | kgid_t grp = INVALID_GID; | 
|  | 199 | char *name = NULL; | 
|  | 200 | int name_len; | 
|  | 201 | int rc; | 
|  | 202 |  | 
| Sumit Garg | 7229395 | 2020-09-17 19:10:22 +0530 | [diff] [blame] | 203 | if (connection_method == TEE_IOCTL_LOGIN_PUBLIC || | 
|  | 204 | connection_method == TEE_IOCTL_LOGIN_REE_KERNEL) { | 
| Vesa Jääskeläinen | e33bcba | 2020-04-30 15:37:09 +0300 | [diff] [blame] | 205 | /* Nil UUID to be passed to TEE environment */ | 
|  | 206 | uuid_copy(uuid, &uuid_null); | 
|  | 207 | return 0; | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 | /* | 
|  | 211 | * In Linux environment client UUID is based on UUIDv5. | 
|  | 212 | * | 
|  | 213 | * Determine client UUID with following semantics for 'name': | 
|  | 214 | * | 
|  | 215 | * For TEEC_LOGIN_USER: | 
|  | 216 | * uid=<uid> | 
|  | 217 | * | 
|  | 218 | * For TEEC_LOGIN_GROUP: | 
|  | 219 | * gid=<gid> | 
|  | 220 | * | 
|  | 221 | */ | 
|  | 222 |  | 
|  | 223 | name = kzalloc(TEE_UUID_NS_NAME_SIZE, GFP_KERNEL); | 
|  | 224 | if (!name) | 
|  | 225 | return -ENOMEM; | 
|  | 226 |  | 
|  | 227 | switch (connection_method) { | 
|  | 228 | case TEE_IOCTL_LOGIN_USER: | 
|  | 229 | name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "uid=%x", | 
|  | 230 | current_euid().val); | 
|  | 231 | if (name_len >= TEE_UUID_NS_NAME_SIZE) { | 
|  | 232 | rc = -E2BIG; | 
|  | 233 | goto out_free_name; | 
|  | 234 | } | 
|  | 235 | break; | 
|  | 236 |  | 
|  | 237 | case TEE_IOCTL_LOGIN_GROUP: | 
|  | 238 | memcpy(&ns_grp, connection_data, sizeof(gid_t)); | 
|  | 239 | grp = make_kgid(current_user_ns(), ns_grp); | 
|  | 240 | if (!gid_valid(grp) || !in_egroup_p(grp)) { | 
|  | 241 | rc = -EPERM; | 
|  | 242 | goto out_free_name; | 
|  | 243 | } | 
|  | 244 |  | 
|  | 245 | name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "gid=%x", | 
|  | 246 | grp.val); | 
|  | 247 | if (name_len >= TEE_UUID_NS_NAME_SIZE) { | 
|  | 248 | rc = -E2BIG; | 
|  | 249 | goto out_free_name; | 
|  | 250 | } | 
|  | 251 | break; | 
|  | 252 |  | 
|  | 253 | default: | 
|  | 254 | rc = -EINVAL; | 
|  | 255 | goto out_free_name; | 
|  | 256 | } | 
|  | 257 |  | 
|  | 258 | rc = uuid_v5(uuid, &tee_client_uuid_ns, name, name_len); | 
|  | 259 | out_free_name: | 
|  | 260 | kfree(name); | 
|  | 261 |  | 
|  | 262 | return rc; | 
|  | 263 | } | 
|  | 264 | EXPORT_SYMBOL_GPL(tee_session_calc_client_uuid); | 
|  | 265 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 266 | static int tee_ioctl_version(struct tee_context *ctx, | 
|  | 267 | struct tee_ioctl_version_data __user *uvers) | 
|  | 268 | { | 
|  | 269 | struct tee_ioctl_version_data vers; | 
|  | 270 |  | 
|  | 271 | ctx->teedev->desc->ops->get_version(ctx->teedev, &vers); | 
| Jens Wiklander | 059cf56 | 2017-02-16 09:07:02 +0100 | [diff] [blame] | 272 |  | 
|  | 273 | if (ctx->teedev->desc->flags & TEE_DESC_PRIVILEGED) | 
|  | 274 | vers.gen_caps |= TEE_GEN_CAP_PRIVILEGED; | 
|  | 275 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 276 | if (copy_to_user(uvers, &vers, sizeof(vers))) | 
|  | 277 | return -EFAULT; | 
| Jens Wiklander | 059cf56 | 2017-02-16 09:07:02 +0100 | [diff] [blame] | 278 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 279 | return 0; | 
|  | 280 | } | 
|  | 281 |  | 
|  | 282 | static int tee_ioctl_shm_alloc(struct tee_context *ctx, | 
|  | 283 | struct tee_ioctl_shm_alloc_data __user *udata) | 
|  | 284 | { | 
|  | 285 | long ret; | 
|  | 286 | struct tee_ioctl_shm_alloc_data data; | 
|  | 287 | struct tee_shm *shm; | 
|  | 288 |  | 
|  | 289 | if (copy_from_user(&data, udata, sizeof(data))) | 
|  | 290 | return -EFAULT; | 
|  | 291 |  | 
|  | 292 | /* Currently no input flags are supported */ | 
|  | 293 | if (data.flags) | 
|  | 294 | return -EINVAL; | 
|  | 295 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 296 | shm = tee_shm_alloc(ctx, data.size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); | 
|  | 297 | if (IS_ERR(shm)) | 
|  | 298 | return PTR_ERR(shm); | 
|  | 299 |  | 
|  | 300 | data.id = shm->id; | 
|  | 301 | data.flags = shm->flags; | 
|  | 302 | data.size = shm->size; | 
|  | 303 |  | 
|  | 304 | if (copy_to_user(udata, &data, sizeof(data))) | 
|  | 305 | ret = -EFAULT; | 
|  | 306 | else | 
|  | 307 | ret = tee_shm_get_fd(shm); | 
|  | 308 |  | 
|  | 309 | /* | 
|  | 310 | * When user space closes the file descriptor the shared memory | 
|  | 311 | * should be freed or if tee_shm_get_fd() failed then it will | 
|  | 312 | * be freed immediately. | 
|  | 313 | */ | 
|  | 314 | tee_shm_put(shm); | 
|  | 315 | return ret; | 
|  | 316 | } | 
|  | 317 |  | 
| Jens Wiklander | 033ddf1 | 2017-11-29 14:48:26 +0200 | [diff] [blame] | 318 | static int | 
|  | 319 | tee_ioctl_shm_register(struct tee_context *ctx, | 
|  | 320 | struct tee_ioctl_shm_register_data __user *udata) | 
|  | 321 | { | 
|  | 322 | long ret; | 
|  | 323 | struct tee_ioctl_shm_register_data data; | 
|  | 324 | struct tee_shm *shm; | 
|  | 325 |  | 
|  | 326 | if (copy_from_user(&data, udata, sizeof(data))) | 
|  | 327 | return -EFAULT; | 
|  | 328 |  | 
|  | 329 | /* Currently no input flags are supported */ | 
|  | 330 | if (data.flags) | 
|  | 331 | return -EINVAL; | 
|  | 332 |  | 
|  | 333 | shm = tee_shm_register(ctx, data.addr, data.length, | 
|  | 334 | TEE_SHM_DMA_BUF | TEE_SHM_USER_MAPPED); | 
|  | 335 | if (IS_ERR(shm)) | 
|  | 336 | return PTR_ERR(shm); | 
|  | 337 |  | 
|  | 338 | data.id = shm->id; | 
|  | 339 | data.flags = shm->flags; | 
|  | 340 | data.length = shm->size; | 
|  | 341 |  | 
|  | 342 | if (copy_to_user(udata, &data, sizeof(data))) | 
|  | 343 | ret = -EFAULT; | 
|  | 344 | else | 
|  | 345 | ret = tee_shm_get_fd(shm); | 
|  | 346 | /* | 
|  | 347 | * When user space closes the file descriptor the shared memory | 
|  | 348 | * should be freed or if tee_shm_get_fd() failed then it will | 
|  | 349 | * be freed immediately. | 
|  | 350 | */ | 
|  | 351 | tee_shm_put(shm); | 
|  | 352 | return ret; | 
|  | 353 | } | 
|  | 354 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 355 | static int params_from_user(struct tee_context *ctx, struct tee_param *params, | 
|  | 356 | size_t num_params, | 
|  | 357 | struct tee_ioctl_param __user *uparams) | 
|  | 358 | { | 
|  | 359 | size_t n; | 
|  | 360 |  | 
|  | 361 | for (n = 0; n < num_params; n++) { | 
|  | 362 | struct tee_shm *shm; | 
|  | 363 | struct tee_ioctl_param ip; | 
|  | 364 |  | 
|  | 365 | if (copy_from_user(&ip, uparams + n, sizeof(ip))) | 
|  | 366 | return -EFAULT; | 
|  | 367 |  | 
|  | 368 | /* All unused attribute bits has to be zero */ | 
| Jens Wiklander | f2aa972 | 2016-12-23 13:13:34 +0100 | [diff] [blame] | 369 | if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK) | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 370 | return -EINVAL; | 
|  | 371 |  | 
|  | 372 | params[n].attr = ip.attr; | 
| Jens Wiklander | f2aa972 | 2016-12-23 13:13:34 +0100 | [diff] [blame] | 373 | switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 374 | case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: | 
|  | 375 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: | 
|  | 376 | break; | 
|  | 377 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: | 
|  | 378 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: | 
|  | 379 | params[n].u.value.a = ip.a; | 
|  | 380 | params[n].u.value.b = ip.b; | 
|  | 381 | params[n].u.value.c = ip.c; | 
|  | 382 | break; | 
|  | 383 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: | 
|  | 384 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: | 
|  | 385 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: | 
|  | 386 | /* | 
| Cedric Neveux | ba171d3 | 2019-03-04 08:54:23 +0100 | [diff] [blame] | 387 | * If a NULL pointer is passed to a TA in the TEE, | 
|  | 388 | * the ip.c IOCTL parameters is set to TEE_MEMREF_NULL | 
|  | 389 | * indicating a NULL memory reference. | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 390 | */ | 
| Cedric Neveux | ba171d3 | 2019-03-04 08:54:23 +0100 | [diff] [blame] | 391 | if (ip.c != TEE_MEMREF_NULL) { | 
|  | 392 | /* | 
|  | 393 | * If we fail to get a pointer to a shared | 
|  | 394 | * memory object (and increase the ref count) | 
|  | 395 | * from an identifier we return an error. All | 
|  | 396 | * pointers that has been added in params have | 
|  | 397 | * an increased ref count. It's the callers | 
|  | 398 | * responibility to do tee_shm_put() on all | 
|  | 399 | * resolved pointers. | 
|  | 400 | */ | 
|  | 401 | shm = tee_shm_get_from_id(ctx, ip.c); | 
|  | 402 | if (IS_ERR(shm)) | 
|  | 403 | return PTR_ERR(shm); | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 404 |  | 
| Cedric Neveux | ba171d3 | 2019-03-04 08:54:23 +0100 | [diff] [blame] | 405 | /* | 
|  | 406 | * Ensure offset + size does not overflow | 
|  | 407 | * offset and does not overflow the size of | 
|  | 408 | * the referred shared memory object. | 
|  | 409 | */ | 
|  | 410 | if ((ip.a + ip.b) < ip.a || | 
|  | 411 | (ip.a + ip.b) > shm->size) { | 
|  | 412 | tee_shm_put(shm); | 
|  | 413 | return -EINVAL; | 
|  | 414 | } | 
|  | 415 | } else if (ctx->cap_memref_null) { | 
|  | 416 | /* Pass NULL pointer to OP-TEE */ | 
|  | 417 | shm = NULL; | 
|  | 418 | } else { | 
| Etienne Carriere | ab9d3db | 2018-04-29 14:22:29 +0200 | [diff] [blame] | 419 | return -EINVAL; | 
|  | 420 | } | 
|  | 421 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 422 | params[n].u.memref.shm_offs = ip.a; | 
|  | 423 | params[n].u.memref.size = ip.b; | 
|  | 424 | params[n].u.memref.shm = shm; | 
|  | 425 | break; | 
|  | 426 | default: | 
|  | 427 | /* Unknown attribute */ | 
|  | 428 | return -EINVAL; | 
|  | 429 | } | 
|  | 430 | } | 
|  | 431 | return 0; | 
|  | 432 | } | 
|  | 433 |  | 
|  | 434 | static int params_to_user(struct tee_ioctl_param __user *uparams, | 
|  | 435 | size_t num_params, struct tee_param *params) | 
|  | 436 | { | 
|  | 437 | size_t n; | 
|  | 438 |  | 
|  | 439 | for (n = 0; n < num_params; n++) { | 
|  | 440 | struct tee_ioctl_param __user *up = uparams + n; | 
|  | 441 | struct tee_param *p = params + n; | 
|  | 442 |  | 
|  | 443 | switch (p->attr) { | 
|  | 444 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: | 
|  | 445 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: | 
|  | 446 | if (put_user(p->u.value.a, &up->a) || | 
|  | 447 | put_user(p->u.value.b, &up->b) || | 
|  | 448 | put_user(p->u.value.c, &up->c)) | 
|  | 449 | return -EFAULT; | 
|  | 450 | break; | 
|  | 451 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: | 
|  | 452 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: | 
|  | 453 | if (put_user((u64)p->u.memref.size, &up->b)) | 
|  | 454 | return -EFAULT; | 
| Gustavo A. R. Silva | 963cdcc | 2020-11-20 12:33:19 -0600 | [diff] [blame] | 455 | break; | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 456 | default: | 
|  | 457 | break; | 
|  | 458 | } | 
|  | 459 | } | 
|  | 460 | return 0; | 
|  | 461 | } | 
|  | 462 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 463 | static int tee_ioctl_open_session(struct tee_context *ctx, | 
|  | 464 | struct tee_ioctl_buf_data __user *ubuf) | 
|  | 465 | { | 
|  | 466 | int rc; | 
|  | 467 | size_t n; | 
|  | 468 | struct tee_ioctl_buf_data buf; | 
|  | 469 | struct tee_ioctl_open_session_arg __user *uarg; | 
|  | 470 | struct tee_ioctl_open_session_arg arg; | 
|  | 471 | struct tee_ioctl_param __user *uparams = NULL; | 
|  | 472 | struct tee_param *params = NULL; | 
|  | 473 | bool have_session = false; | 
|  | 474 |  | 
|  | 475 | if (!ctx->teedev->desc->ops->open_session) | 
|  | 476 | return -EINVAL; | 
|  | 477 |  | 
|  | 478 | if (copy_from_user(&buf, ubuf, sizeof(buf))) | 
|  | 479 | return -EFAULT; | 
|  | 480 |  | 
|  | 481 | if (buf.buf_len > TEE_MAX_ARG_SIZE || | 
|  | 482 | buf.buf_len < sizeof(struct tee_ioctl_open_session_arg)) | 
|  | 483 | return -EINVAL; | 
|  | 484 |  | 
|  | 485 | uarg = u64_to_user_ptr(buf.buf_ptr); | 
|  | 486 | if (copy_from_user(&arg, uarg, sizeof(arg))) | 
|  | 487 | return -EFAULT; | 
|  | 488 |  | 
|  | 489 | if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) | 
|  | 490 | return -EINVAL; | 
|  | 491 |  | 
|  | 492 | if (arg.num_params) { | 
|  | 493 | params = kcalloc(arg.num_params, sizeof(struct tee_param), | 
|  | 494 | GFP_KERNEL); | 
|  | 495 | if (!params) | 
|  | 496 | return -ENOMEM; | 
|  | 497 | uparams = uarg->params; | 
|  | 498 | rc = params_from_user(ctx, params, arg.num_params, uparams); | 
|  | 499 | if (rc) | 
|  | 500 | goto out; | 
|  | 501 | } | 
|  | 502 |  | 
| Sumit Garg | 104edb9 | 2020-03-27 10:59:48 +0530 | [diff] [blame] | 503 | if (arg.clnt_login >= TEE_IOCTL_LOGIN_REE_KERNEL_MIN && | 
|  | 504 | arg.clnt_login <= TEE_IOCTL_LOGIN_REE_KERNEL_MAX) { | 
|  | 505 | pr_debug("login method not allowed for user-space client\n"); | 
|  | 506 | rc = -EPERM; | 
|  | 507 | goto out; | 
|  | 508 | } | 
|  | 509 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 510 | rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params); | 
|  | 511 | if (rc) | 
|  | 512 | goto out; | 
|  | 513 | have_session = true; | 
|  | 514 |  | 
|  | 515 | if (put_user(arg.session, &uarg->session) || | 
|  | 516 | put_user(arg.ret, &uarg->ret) || | 
|  | 517 | put_user(arg.ret_origin, &uarg->ret_origin)) { | 
|  | 518 | rc = -EFAULT; | 
|  | 519 | goto out; | 
|  | 520 | } | 
|  | 521 | rc = params_to_user(uparams, arg.num_params, params); | 
|  | 522 | out: | 
|  | 523 | /* | 
|  | 524 | * If we've succeeded to open the session but failed to communicate | 
|  | 525 | * it back to user space, close the session again to avoid leakage. | 
|  | 526 | */ | 
|  | 527 | if (rc && have_session && ctx->teedev->desc->ops->close_session) | 
|  | 528 | ctx->teedev->desc->ops->close_session(ctx, arg.session); | 
|  | 529 |  | 
|  | 530 | if (params) { | 
|  | 531 | /* Decrease ref count for all valid shared memory pointers */ | 
|  | 532 | for (n = 0; n < arg.num_params; n++) | 
| Jens Wiklander | 84debcc | 2016-12-23 13:13:27 +0100 | [diff] [blame] | 533 | if (tee_param_is_memref(params + n) && | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 534 | params[n].u.memref.shm) | 
|  | 535 | tee_shm_put(params[n].u.memref.shm); | 
|  | 536 | kfree(params); | 
|  | 537 | } | 
|  | 538 |  | 
|  | 539 | return rc; | 
|  | 540 | } | 
|  | 541 |  | 
|  | 542 | static int tee_ioctl_invoke(struct tee_context *ctx, | 
|  | 543 | struct tee_ioctl_buf_data __user *ubuf) | 
|  | 544 | { | 
|  | 545 | int rc; | 
|  | 546 | size_t n; | 
|  | 547 | struct tee_ioctl_buf_data buf; | 
|  | 548 | struct tee_ioctl_invoke_arg __user *uarg; | 
|  | 549 | struct tee_ioctl_invoke_arg arg; | 
|  | 550 | struct tee_ioctl_param __user *uparams = NULL; | 
|  | 551 | struct tee_param *params = NULL; | 
|  | 552 |  | 
|  | 553 | if (!ctx->teedev->desc->ops->invoke_func) | 
|  | 554 | return -EINVAL; | 
|  | 555 |  | 
|  | 556 | if (copy_from_user(&buf, ubuf, sizeof(buf))) | 
|  | 557 | return -EFAULT; | 
|  | 558 |  | 
|  | 559 | if (buf.buf_len > TEE_MAX_ARG_SIZE || | 
|  | 560 | buf.buf_len < sizeof(struct tee_ioctl_invoke_arg)) | 
|  | 561 | return -EINVAL; | 
|  | 562 |  | 
|  | 563 | uarg = u64_to_user_ptr(buf.buf_ptr); | 
|  | 564 | if (copy_from_user(&arg, uarg, sizeof(arg))) | 
|  | 565 | return -EFAULT; | 
|  | 566 |  | 
|  | 567 | if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) | 
|  | 568 | return -EINVAL; | 
|  | 569 |  | 
|  | 570 | if (arg.num_params) { | 
|  | 571 | params = kcalloc(arg.num_params, sizeof(struct tee_param), | 
|  | 572 | GFP_KERNEL); | 
|  | 573 | if (!params) | 
|  | 574 | return -ENOMEM; | 
|  | 575 | uparams = uarg->params; | 
|  | 576 | rc = params_from_user(ctx, params, arg.num_params, uparams); | 
|  | 577 | if (rc) | 
|  | 578 | goto out; | 
|  | 579 | } | 
|  | 580 |  | 
|  | 581 | rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params); | 
|  | 582 | if (rc) | 
|  | 583 | goto out; | 
|  | 584 |  | 
|  | 585 | if (put_user(arg.ret, &uarg->ret) || | 
|  | 586 | put_user(arg.ret_origin, &uarg->ret_origin)) { | 
|  | 587 | rc = -EFAULT; | 
|  | 588 | goto out; | 
|  | 589 | } | 
|  | 590 | rc = params_to_user(uparams, arg.num_params, params); | 
|  | 591 | out: | 
|  | 592 | if (params) { | 
|  | 593 | /* Decrease ref count for all valid shared memory pointers */ | 
|  | 594 | for (n = 0; n < arg.num_params; n++) | 
| Jens Wiklander | 84debcc | 2016-12-23 13:13:27 +0100 | [diff] [blame] | 595 | if (tee_param_is_memref(params + n) && | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 596 | params[n].u.memref.shm) | 
|  | 597 | tee_shm_put(params[n].u.memref.shm); | 
|  | 598 | kfree(params); | 
|  | 599 | } | 
|  | 600 | return rc; | 
|  | 601 | } | 
|  | 602 |  | 
|  | 603 | static int tee_ioctl_cancel(struct tee_context *ctx, | 
|  | 604 | struct tee_ioctl_cancel_arg __user *uarg) | 
|  | 605 | { | 
|  | 606 | struct tee_ioctl_cancel_arg arg; | 
|  | 607 |  | 
|  | 608 | if (!ctx->teedev->desc->ops->cancel_req) | 
|  | 609 | return -EINVAL; | 
|  | 610 |  | 
|  | 611 | if (copy_from_user(&arg, uarg, sizeof(arg))) | 
|  | 612 | return -EFAULT; | 
|  | 613 |  | 
|  | 614 | return ctx->teedev->desc->ops->cancel_req(ctx, arg.cancel_id, | 
|  | 615 | arg.session); | 
|  | 616 | } | 
|  | 617 |  | 
|  | 618 | static int | 
|  | 619 | tee_ioctl_close_session(struct tee_context *ctx, | 
|  | 620 | struct tee_ioctl_close_session_arg __user *uarg) | 
|  | 621 | { | 
|  | 622 | struct tee_ioctl_close_session_arg arg; | 
|  | 623 |  | 
|  | 624 | if (!ctx->teedev->desc->ops->close_session) | 
|  | 625 | return -EINVAL; | 
|  | 626 |  | 
|  | 627 | if (copy_from_user(&arg, uarg, sizeof(arg))) | 
|  | 628 | return -EFAULT; | 
|  | 629 |  | 
|  | 630 | return ctx->teedev->desc->ops->close_session(ctx, arg.session); | 
|  | 631 | } | 
|  | 632 |  | 
|  | 633 | static int params_to_supp(struct tee_context *ctx, | 
|  | 634 | struct tee_ioctl_param __user *uparams, | 
|  | 635 | size_t num_params, struct tee_param *params) | 
|  | 636 | { | 
|  | 637 | size_t n; | 
|  | 638 |  | 
|  | 639 | for (n = 0; n < num_params; n++) { | 
|  | 640 | struct tee_ioctl_param ip; | 
|  | 641 | struct tee_param *p = params + n; | 
|  | 642 |  | 
| Jens Wiklander | f2aa972 | 2016-12-23 13:13:34 +0100 | [diff] [blame] | 643 | ip.attr = p->attr; | 
|  | 644 | switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 645 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: | 
|  | 646 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: | 
|  | 647 | ip.a = p->u.value.a; | 
|  | 648 | ip.b = p->u.value.b; | 
|  | 649 | ip.c = p->u.value.c; | 
|  | 650 | break; | 
|  | 651 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: | 
|  | 652 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: | 
|  | 653 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: | 
|  | 654 | ip.b = p->u.memref.size; | 
|  | 655 | if (!p->u.memref.shm) { | 
|  | 656 | ip.a = 0; | 
|  | 657 | ip.c = (u64)-1; /* invalid shm id */ | 
|  | 658 | break; | 
|  | 659 | } | 
|  | 660 | ip.a = p->u.memref.shm_offs; | 
|  | 661 | ip.c = p->u.memref.shm->id; | 
|  | 662 | break; | 
|  | 663 | default: | 
|  | 664 | ip.a = 0; | 
|  | 665 | ip.b = 0; | 
|  | 666 | ip.c = 0; | 
|  | 667 | break; | 
|  | 668 | } | 
|  | 669 |  | 
|  | 670 | if (copy_to_user(uparams + n, &ip, sizeof(ip))) | 
|  | 671 | return -EFAULT; | 
|  | 672 | } | 
|  | 673 |  | 
|  | 674 | return 0; | 
|  | 675 | } | 
|  | 676 |  | 
|  | 677 | static int tee_ioctl_supp_recv(struct tee_context *ctx, | 
|  | 678 | struct tee_ioctl_buf_data __user *ubuf) | 
|  | 679 | { | 
|  | 680 | int rc; | 
|  | 681 | struct tee_ioctl_buf_data buf; | 
|  | 682 | struct tee_iocl_supp_recv_arg __user *uarg; | 
|  | 683 | struct tee_param *params; | 
|  | 684 | u32 num_params; | 
|  | 685 | u32 func; | 
|  | 686 |  | 
|  | 687 | if (!ctx->teedev->desc->ops->supp_recv) | 
|  | 688 | return -EINVAL; | 
|  | 689 |  | 
|  | 690 | if (copy_from_user(&buf, ubuf, sizeof(buf))) | 
|  | 691 | return -EFAULT; | 
|  | 692 |  | 
|  | 693 | if (buf.buf_len > TEE_MAX_ARG_SIZE || | 
|  | 694 | buf.buf_len < sizeof(struct tee_iocl_supp_recv_arg)) | 
|  | 695 | return -EINVAL; | 
|  | 696 |  | 
|  | 697 | uarg = u64_to_user_ptr(buf.buf_ptr); | 
|  | 698 | if (get_user(num_params, &uarg->num_params)) | 
|  | 699 | return -EFAULT; | 
|  | 700 |  | 
|  | 701 | if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) != buf.buf_len) | 
|  | 702 | return -EINVAL; | 
|  | 703 |  | 
|  | 704 | params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); | 
|  | 705 | if (!params) | 
|  | 706 | return -ENOMEM; | 
|  | 707 |  | 
| Jens Wiklander | f2aa972 | 2016-12-23 13:13:34 +0100 | [diff] [blame] | 708 | rc = params_from_user(ctx, params, num_params, uarg->params); | 
|  | 709 | if (rc) | 
|  | 710 | goto out; | 
|  | 711 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 712 | rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params); | 
|  | 713 | if (rc) | 
|  | 714 | goto out; | 
|  | 715 |  | 
|  | 716 | if (put_user(func, &uarg->func) || | 
|  | 717 | put_user(num_params, &uarg->num_params)) { | 
|  | 718 | rc = -EFAULT; | 
|  | 719 | goto out; | 
|  | 720 | } | 
|  | 721 |  | 
|  | 722 | rc = params_to_supp(ctx, uarg->params, num_params, params); | 
|  | 723 | out: | 
|  | 724 | kfree(params); | 
|  | 725 | return rc; | 
|  | 726 | } | 
|  | 727 |  | 
|  | 728 | static int params_from_supp(struct tee_param *params, size_t num_params, | 
|  | 729 | struct tee_ioctl_param __user *uparams) | 
|  | 730 | { | 
|  | 731 | size_t n; | 
|  | 732 |  | 
|  | 733 | for (n = 0; n < num_params; n++) { | 
|  | 734 | struct tee_param *p = params + n; | 
|  | 735 | struct tee_ioctl_param ip; | 
|  | 736 |  | 
|  | 737 | if (copy_from_user(&ip, uparams + n, sizeof(ip))) | 
|  | 738 | return -EFAULT; | 
|  | 739 |  | 
|  | 740 | /* All unused attribute bits has to be zero */ | 
| Jens Wiklander | f2aa972 | 2016-12-23 13:13:34 +0100 | [diff] [blame] | 741 | if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK) | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 742 | return -EINVAL; | 
|  | 743 |  | 
|  | 744 | p->attr = ip.attr; | 
| Jens Wiklander | f2aa972 | 2016-12-23 13:13:34 +0100 | [diff] [blame] | 745 | switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 746 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: | 
|  | 747 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: | 
|  | 748 | /* Only out and in/out values can be updated */ | 
|  | 749 | p->u.value.a = ip.a; | 
|  | 750 | p->u.value.b = ip.b; | 
|  | 751 | p->u.value.c = ip.c; | 
|  | 752 | break; | 
|  | 753 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: | 
|  | 754 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: | 
|  | 755 | /* | 
|  | 756 | * Only the size of the memref can be updated. | 
|  | 757 | * Since we don't have access to the original | 
|  | 758 | * parameters here, only store the supplied size. | 
|  | 759 | * The driver will copy the updated size into the | 
|  | 760 | * original parameters. | 
|  | 761 | */ | 
|  | 762 | p->u.memref.shm = NULL; | 
|  | 763 | p->u.memref.shm_offs = 0; | 
|  | 764 | p->u.memref.size = ip.b; | 
|  | 765 | break; | 
|  | 766 | default: | 
|  | 767 | memset(&p->u, 0, sizeof(p->u)); | 
|  | 768 | break; | 
|  | 769 | } | 
|  | 770 | } | 
|  | 771 | return 0; | 
|  | 772 | } | 
|  | 773 |  | 
|  | 774 | static int tee_ioctl_supp_send(struct tee_context *ctx, | 
|  | 775 | struct tee_ioctl_buf_data __user *ubuf) | 
|  | 776 | { | 
|  | 777 | long rc; | 
|  | 778 | struct tee_ioctl_buf_data buf; | 
|  | 779 | struct tee_iocl_supp_send_arg __user *uarg; | 
|  | 780 | struct tee_param *params; | 
|  | 781 | u32 num_params; | 
|  | 782 | u32 ret; | 
|  | 783 |  | 
|  | 784 | /* Not valid for this driver */ | 
|  | 785 | if (!ctx->teedev->desc->ops->supp_send) | 
|  | 786 | return -EINVAL; | 
|  | 787 |  | 
|  | 788 | if (copy_from_user(&buf, ubuf, sizeof(buf))) | 
|  | 789 | return -EFAULT; | 
|  | 790 |  | 
|  | 791 | if (buf.buf_len > TEE_MAX_ARG_SIZE || | 
|  | 792 | buf.buf_len < sizeof(struct tee_iocl_supp_send_arg)) | 
|  | 793 | return -EINVAL; | 
|  | 794 |  | 
|  | 795 | uarg = u64_to_user_ptr(buf.buf_ptr); | 
|  | 796 | if (get_user(ret, &uarg->ret) || | 
|  | 797 | get_user(num_params, &uarg->num_params)) | 
|  | 798 | return -EFAULT; | 
|  | 799 |  | 
|  | 800 | if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) > buf.buf_len) | 
|  | 801 | return -EINVAL; | 
|  | 802 |  | 
|  | 803 | params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); | 
|  | 804 | if (!params) | 
|  | 805 | return -ENOMEM; | 
|  | 806 |  | 
|  | 807 | rc = params_from_supp(params, num_params, uarg->params); | 
|  | 808 | if (rc) | 
|  | 809 | goto out; | 
|  | 810 |  | 
|  | 811 | rc = ctx->teedev->desc->ops->supp_send(ctx, ret, num_params, params); | 
|  | 812 | out: | 
|  | 813 | kfree(params); | 
|  | 814 | return rc; | 
|  | 815 | } | 
|  | 816 |  | 
|  | 817 | static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 
|  | 818 | { | 
|  | 819 | struct tee_context *ctx = filp->private_data; | 
|  | 820 | void __user *uarg = (void __user *)arg; | 
|  | 821 |  | 
|  | 822 | switch (cmd) { | 
|  | 823 | case TEE_IOC_VERSION: | 
|  | 824 | return tee_ioctl_version(ctx, uarg); | 
|  | 825 | case TEE_IOC_SHM_ALLOC: | 
|  | 826 | return tee_ioctl_shm_alloc(ctx, uarg); | 
| Jens Wiklander | 033ddf1 | 2017-11-29 14:48:26 +0200 | [diff] [blame] | 827 | case TEE_IOC_SHM_REGISTER: | 
|  | 828 | return tee_ioctl_shm_register(ctx, uarg); | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 829 | case TEE_IOC_OPEN_SESSION: | 
|  | 830 | return tee_ioctl_open_session(ctx, uarg); | 
|  | 831 | case TEE_IOC_INVOKE: | 
|  | 832 | return tee_ioctl_invoke(ctx, uarg); | 
|  | 833 | case TEE_IOC_CANCEL: | 
|  | 834 | return tee_ioctl_cancel(ctx, uarg); | 
|  | 835 | case TEE_IOC_CLOSE_SESSION: | 
|  | 836 | return tee_ioctl_close_session(ctx, uarg); | 
|  | 837 | case TEE_IOC_SUPPL_RECV: | 
|  | 838 | return tee_ioctl_supp_recv(ctx, uarg); | 
|  | 839 | case TEE_IOC_SUPPL_SEND: | 
|  | 840 | return tee_ioctl_supp_send(ctx, uarg); | 
|  | 841 | default: | 
|  | 842 | return -EINVAL; | 
|  | 843 | } | 
|  | 844 | } | 
|  | 845 |  | 
|  | 846 | static const struct file_operations tee_fops = { | 
|  | 847 | .owner = THIS_MODULE, | 
|  | 848 | .open = tee_open, | 
|  | 849 | .release = tee_release, | 
|  | 850 | .unlocked_ioctl = tee_ioctl, | 
| Arnd Bergmann | 1832f2d | 2018-09-11 21:59:08 +0200 | [diff] [blame] | 851 | .compat_ioctl = compat_ptr_ioctl, | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 852 | }; | 
|  | 853 |  | 
|  | 854 | static void tee_release_device(struct device *dev) | 
|  | 855 | { | 
|  | 856 | struct tee_device *teedev = container_of(dev, struct tee_device, dev); | 
|  | 857 |  | 
|  | 858 | spin_lock(&driver_lock); | 
|  | 859 | clear_bit(teedev->id, dev_mask); | 
|  | 860 | spin_unlock(&driver_lock); | 
|  | 861 | mutex_destroy(&teedev->mutex); | 
|  | 862 | idr_destroy(&teedev->idr); | 
|  | 863 | kfree(teedev); | 
|  | 864 | } | 
|  | 865 |  | 
|  | 866 | /** | 
|  | 867 | * tee_device_alloc() - Allocate a new struct tee_device instance | 
|  | 868 | * @teedesc:	Descriptor for this driver | 
|  | 869 | * @dev:	Parent device for this device | 
|  | 870 | * @pool:	Shared memory pool, NULL if not used | 
|  | 871 | * @driver_data: Private driver data for this device | 
|  | 872 | * | 
|  | 873 | * Allocates a new struct tee_device instance. The device is | 
|  | 874 | * removed by tee_device_unregister(). | 
|  | 875 | * | 
|  | 876 | * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure | 
|  | 877 | */ | 
|  | 878 | struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, | 
|  | 879 | struct device *dev, | 
|  | 880 | struct tee_shm_pool *pool, | 
|  | 881 | void *driver_data) | 
|  | 882 | { | 
|  | 883 | struct tee_device *teedev; | 
|  | 884 | void *ret; | 
| Peng Fan | 7dd003a | 2018-01-15 17:27:35 +0800 | [diff] [blame] | 885 | int rc, max_id; | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 886 | int offs = 0; | 
|  | 887 |  | 
|  | 888 | if (!teedesc || !teedesc->name || !teedesc->ops || | 
|  | 889 | !teedesc->ops->get_version || !teedesc->ops->open || | 
|  | 890 | !teedesc->ops->release || !pool) | 
|  | 891 | return ERR_PTR(-EINVAL); | 
|  | 892 |  | 
|  | 893 | teedev = kzalloc(sizeof(*teedev), GFP_KERNEL); | 
|  | 894 | if (!teedev) { | 
|  | 895 | ret = ERR_PTR(-ENOMEM); | 
|  | 896 | goto err; | 
|  | 897 | } | 
|  | 898 |  | 
| Peng Fan | 7dd003a | 2018-01-15 17:27:35 +0800 | [diff] [blame] | 899 | max_id = TEE_NUM_DEVICES / 2; | 
|  | 900 |  | 
|  | 901 | if (teedesc->flags & TEE_DESC_PRIVILEGED) { | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 902 | offs = TEE_NUM_DEVICES / 2; | 
| Peng Fan | 7dd003a | 2018-01-15 17:27:35 +0800 | [diff] [blame] | 903 | max_id = TEE_NUM_DEVICES; | 
|  | 904 | } | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 905 |  | 
|  | 906 | spin_lock(&driver_lock); | 
| Peng Fan | 7dd003a | 2018-01-15 17:27:35 +0800 | [diff] [blame] | 907 | teedev->id = find_next_zero_bit(dev_mask, max_id, offs); | 
|  | 908 | if (teedev->id < max_id) | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 909 | set_bit(teedev->id, dev_mask); | 
|  | 910 | spin_unlock(&driver_lock); | 
|  | 911 |  | 
| Peng Fan | 7dd003a | 2018-01-15 17:27:35 +0800 | [diff] [blame] | 912 | if (teedev->id >= max_id) { | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 913 | ret = ERR_PTR(-ENOMEM); | 
|  | 914 | goto err; | 
|  | 915 | } | 
|  | 916 |  | 
|  | 917 | snprintf(teedev->name, sizeof(teedev->name), "tee%s%d", | 
|  | 918 | teedesc->flags & TEE_DESC_PRIVILEGED ? "priv" : "", | 
|  | 919 | teedev->id - offs); | 
|  | 920 |  | 
|  | 921 | teedev->dev.class = tee_class; | 
|  | 922 | teedev->dev.release = tee_release_device; | 
|  | 923 | teedev->dev.parent = dev; | 
|  | 924 |  | 
|  | 925 | teedev->dev.devt = MKDEV(MAJOR(tee_devt), teedev->id); | 
|  | 926 |  | 
|  | 927 | rc = dev_set_name(&teedev->dev, "%s", teedev->name); | 
|  | 928 | if (rc) { | 
|  | 929 | ret = ERR_PTR(rc); | 
|  | 930 | goto err_devt; | 
|  | 931 | } | 
|  | 932 |  | 
|  | 933 | cdev_init(&teedev->cdev, &tee_fops); | 
|  | 934 | teedev->cdev.owner = teedesc->owner; | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 935 |  | 
|  | 936 | dev_set_drvdata(&teedev->dev, driver_data); | 
|  | 937 | device_initialize(&teedev->dev); | 
|  | 938 |  | 
|  | 939 | /* 1 as tee_device_unregister() does one final tee_device_put() */ | 
|  | 940 | teedev->num_users = 1; | 
|  | 941 | init_completion(&teedev->c_no_users); | 
|  | 942 | mutex_init(&teedev->mutex); | 
|  | 943 | idr_init(&teedev->idr); | 
|  | 944 |  | 
|  | 945 | teedev->desc = teedesc; | 
|  | 946 | teedev->pool = pool; | 
|  | 947 |  | 
|  | 948 | return teedev; | 
|  | 949 | err_devt: | 
|  | 950 | unregister_chrdev_region(teedev->dev.devt, 1); | 
|  | 951 | err: | 
|  | 952 | pr_err("could not register %s driver\n", | 
|  | 953 | teedesc->flags & TEE_DESC_PRIVILEGED ? "privileged" : "client"); | 
|  | 954 | if (teedev && teedev->id < TEE_NUM_DEVICES) { | 
|  | 955 | spin_lock(&driver_lock); | 
|  | 956 | clear_bit(teedev->id, dev_mask); | 
|  | 957 | spin_unlock(&driver_lock); | 
|  | 958 | } | 
|  | 959 | kfree(teedev); | 
|  | 960 | return ret; | 
|  | 961 | } | 
|  | 962 | EXPORT_SYMBOL_GPL(tee_device_alloc); | 
|  | 963 |  | 
|  | 964 | static ssize_t implementation_id_show(struct device *dev, | 
|  | 965 | struct device_attribute *attr, char *buf) | 
|  | 966 | { | 
|  | 967 | struct tee_device *teedev = container_of(dev, struct tee_device, dev); | 
|  | 968 | struct tee_ioctl_version_data vers; | 
|  | 969 |  | 
|  | 970 | teedev->desc->ops->get_version(teedev, &vers); | 
|  | 971 | return scnprintf(buf, PAGE_SIZE, "%d\n", vers.impl_id); | 
|  | 972 | } | 
|  | 973 | static DEVICE_ATTR_RO(implementation_id); | 
|  | 974 |  | 
|  | 975 | static struct attribute *tee_dev_attrs[] = { | 
|  | 976 | &dev_attr_implementation_id.attr, | 
|  | 977 | NULL | 
|  | 978 | }; | 
|  | 979 |  | 
| Sudeep Holla | 8c05f50 | 2020-09-01 11:33:35 +0100 | [diff] [blame] | 980 | ATTRIBUTE_GROUPS(tee_dev); | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 981 |  | 
|  | 982 | /** | 
|  | 983 | * tee_device_register() - Registers a TEE device | 
|  | 984 | * @teedev:	Device to register | 
|  | 985 | * | 
|  | 986 | * tee_device_unregister() need to be called to remove the @teedev if | 
|  | 987 | * this function fails. | 
|  | 988 | * | 
|  | 989 | * @returns < 0 on failure | 
|  | 990 | */ | 
|  | 991 | int tee_device_register(struct tee_device *teedev) | 
|  | 992 | { | 
|  | 993 | int rc; | 
|  | 994 |  | 
|  | 995 | if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { | 
|  | 996 | dev_err(&teedev->dev, "attempt to register twice\n"); | 
|  | 997 | return -EINVAL; | 
|  | 998 | } | 
|  | 999 |  | 
| Sudeep Holla | 8c05f50 | 2020-09-01 11:33:35 +0100 | [diff] [blame] | 1000 | teedev->dev.groups = tee_dev_groups; | 
|  | 1001 |  | 
| Sudeep Holla | ab3d8e1 | 2020-09-01 11:33:34 +0100 | [diff] [blame] | 1002 | rc = cdev_device_add(&teedev->cdev, &teedev->dev); | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 1003 | if (rc) { | 
|  | 1004 | dev_err(&teedev->dev, | 
| Sudeep Holla | ab3d8e1 | 2020-09-01 11:33:34 +0100 | [diff] [blame] | 1005 | "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 1006 | teedev->name, MAJOR(teedev->dev.devt), | 
|  | 1007 | MINOR(teedev->dev.devt), rc); | 
|  | 1008 | return rc; | 
|  | 1009 | } | 
|  | 1010 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 1011 | teedev->flags |= TEE_DEVICE_FLAG_REGISTERED; | 
|  | 1012 | return 0; | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 1013 | } | 
|  | 1014 | EXPORT_SYMBOL_GPL(tee_device_register); | 
|  | 1015 |  | 
|  | 1016 | void tee_device_put(struct tee_device *teedev) | 
|  | 1017 | { | 
|  | 1018 | mutex_lock(&teedev->mutex); | 
|  | 1019 | /* Shouldn't put in this state */ | 
|  | 1020 | if (!WARN_ON(!teedev->desc)) { | 
|  | 1021 | teedev->num_users--; | 
|  | 1022 | if (!teedev->num_users) { | 
|  | 1023 | teedev->desc = NULL; | 
|  | 1024 | complete(&teedev->c_no_users); | 
|  | 1025 | } | 
|  | 1026 | } | 
|  | 1027 | mutex_unlock(&teedev->mutex); | 
|  | 1028 | } | 
|  | 1029 |  | 
|  | 1030 | bool tee_device_get(struct tee_device *teedev) | 
|  | 1031 | { | 
|  | 1032 | mutex_lock(&teedev->mutex); | 
|  | 1033 | if (!teedev->desc) { | 
|  | 1034 | mutex_unlock(&teedev->mutex); | 
|  | 1035 | return false; | 
|  | 1036 | } | 
|  | 1037 | teedev->num_users++; | 
|  | 1038 | mutex_unlock(&teedev->mutex); | 
|  | 1039 | return true; | 
|  | 1040 | } | 
|  | 1041 |  | 
|  | 1042 | /** | 
|  | 1043 | * tee_device_unregister() - Removes a TEE device | 
|  | 1044 | * @teedev:	Device to unregister | 
|  | 1045 | * | 
|  | 1046 | * This function should be called to remove the @teedev even if | 
|  | 1047 | * tee_device_register() hasn't been called yet. Does nothing if | 
|  | 1048 | * @teedev is NULL. | 
|  | 1049 | */ | 
|  | 1050 | void tee_device_unregister(struct tee_device *teedev) | 
|  | 1051 | { | 
|  | 1052 | if (!teedev) | 
|  | 1053 | return; | 
|  | 1054 |  | 
| Sudeep Holla | 8c05f50 | 2020-09-01 11:33:35 +0100 | [diff] [blame] | 1055 | if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) | 
| Sudeep Holla | ab3d8e1 | 2020-09-01 11:33:34 +0100 | [diff] [blame] | 1056 | cdev_device_del(&teedev->cdev, &teedev->dev); | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 1057 |  | 
|  | 1058 | tee_device_put(teedev); | 
|  | 1059 | wait_for_completion(&teedev->c_no_users); | 
|  | 1060 |  | 
|  | 1061 | /* | 
|  | 1062 | * No need to take a mutex any longer now since teedev->desc was | 
|  | 1063 | * set to NULL before teedev->c_no_users was completed. | 
|  | 1064 | */ | 
|  | 1065 |  | 
|  | 1066 | teedev->pool = NULL; | 
|  | 1067 |  | 
|  | 1068 | put_device(&teedev->dev); | 
|  | 1069 | } | 
|  | 1070 | EXPORT_SYMBOL_GPL(tee_device_unregister); | 
|  | 1071 |  | 
|  | 1072 | /** | 
|  | 1073 | * tee_get_drvdata() - Return driver_data pointer | 
|  | 1074 | * @teedev:	Device containing the driver_data pointer | 
|  | 1075 | * @returns the driver_data pointer supplied to tee_register(). | 
|  | 1076 | */ | 
|  | 1077 | void *tee_get_drvdata(struct tee_device *teedev) | 
|  | 1078 | { | 
|  | 1079 | return dev_get_drvdata(&teedev->dev); | 
|  | 1080 | } | 
|  | 1081 | EXPORT_SYMBOL_GPL(tee_get_drvdata); | 
|  | 1082 |  | 
| Jens Wiklander | 25559c2 | 2018-07-09 08:15:49 +0200 | [diff] [blame] | 1083 | struct match_dev_data { | 
|  | 1084 | struct tee_ioctl_version_data *vers; | 
|  | 1085 | const void *data; | 
|  | 1086 | int (*match)(struct tee_ioctl_version_data *, const void *); | 
|  | 1087 | }; | 
|  | 1088 |  | 
|  | 1089 | static int match_dev(struct device *dev, const void *data) | 
|  | 1090 | { | 
|  | 1091 | const struct match_dev_data *match_data = data; | 
|  | 1092 | struct tee_device *teedev = container_of(dev, struct tee_device, dev); | 
|  | 1093 |  | 
|  | 1094 | teedev->desc->ops->get_version(teedev, match_data->vers); | 
|  | 1095 | return match_data->match(match_data->vers, match_data->data); | 
|  | 1096 | } | 
|  | 1097 |  | 
|  | 1098 | struct tee_context * | 
|  | 1099 | tee_client_open_context(struct tee_context *start, | 
|  | 1100 | int (*match)(struct tee_ioctl_version_data *, | 
|  | 1101 | const void *), | 
|  | 1102 | const void *data, struct tee_ioctl_version_data *vers) | 
|  | 1103 | { | 
|  | 1104 | struct device *dev = NULL; | 
|  | 1105 | struct device *put_dev = NULL; | 
|  | 1106 | struct tee_context *ctx = NULL; | 
|  | 1107 | struct tee_ioctl_version_data v; | 
|  | 1108 | struct match_dev_data match_data = { vers ? vers : &v, data, match }; | 
|  | 1109 |  | 
|  | 1110 | if (start) | 
|  | 1111 | dev = &start->teedev->dev; | 
|  | 1112 |  | 
|  | 1113 | do { | 
|  | 1114 | dev = class_find_device(tee_class, dev, &match_data, match_dev); | 
|  | 1115 | if (!dev) { | 
|  | 1116 | ctx = ERR_PTR(-ENOENT); | 
|  | 1117 | break; | 
|  | 1118 | } | 
|  | 1119 |  | 
|  | 1120 | put_device(put_dev); | 
|  | 1121 | put_dev = dev; | 
|  | 1122 |  | 
|  | 1123 | ctx = teedev_open(container_of(dev, struct tee_device, dev)); | 
|  | 1124 | } while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM); | 
|  | 1125 |  | 
|  | 1126 | put_device(put_dev); | 
| Sumit Garg | 42bf415 | 2019-01-29 11:19:36 +0530 | [diff] [blame] | 1127 | /* | 
|  | 1128 | * Default behaviour for in kernel client is to not wait for | 
|  | 1129 | * tee-supplicant if not present for any requests in this context. | 
|  | 1130 | * Also this flag could be configured again before call to | 
|  | 1131 | * tee_client_open_session() if any in kernel client requires | 
|  | 1132 | * different behaviour. | 
|  | 1133 | */ | 
| Sumit Garg | bb342f0 | 2019-02-20 11:32:27 +0530 | [diff] [blame] | 1134 | if (!IS_ERR(ctx)) | 
|  | 1135 | ctx->supp_nowait = true; | 
|  | 1136 |  | 
| Jens Wiklander | 25559c2 | 2018-07-09 08:15:49 +0200 | [diff] [blame] | 1137 | return ctx; | 
|  | 1138 | } | 
|  | 1139 | EXPORT_SYMBOL_GPL(tee_client_open_context); | 
|  | 1140 |  | 
|  | 1141 | void tee_client_close_context(struct tee_context *ctx) | 
|  | 1142 | { | 
|  | 1143 | teedev_close_context(ctx); | 
|  | 1144 | } | 
|  | 1145 | EXPORT_SYMBOL_GPL(tee_client_close_context); | 
|  | 1146 |  | 
|  | 1147 | void tee_client_get_version(struct tee_context *ctx, | 
|  | 1148 | struct tee_ioctl_version_data *vers) | 
|  | 1149 | { | 
|  | 1150 | ctx->teedev->desc->ops->get_version(ctx->teedev, vers); | 
|  | 1151 | } | 
|  | 1152 | EXPORT_SYMBOL_GPL(tee_client_get_version); | 
|  | 1153 |  | 
|  | 1154 | int tee_client_open_session(struct tee_context *ctx, | 
|  | 1155 | struct tee_ioctl_open_session_arg *arg, | 
|  | 1156 | struct tee_param *param) | 
|  | 1157 | { | 
|  | 1158 | if (!ctx->teedev->desc->ops->open_session) | 
|  | 1159 | return -EINVAL; | 
|  | 1160 | return ctx->teedev->desc->ops->open_session(ctx, arg, param); | 
|  | 1161 | } | 
|  | 1162 | EXPORT_SYMBOL_GPL(tee_client_open_session); | 
|  | 1163 |  | 
|  | 1164 | int tee_client_close_session(struct tee_context *ctx, u32 session) | 
|  | 1165 | { | 
|  | 1166 | if (!ctx->teedev->desc->ops->close_session) | 
|  | 1167 | return -EINVAL; | 
|  | 1168 | return ctx->teedev->desc->ops->close_session(ctx, session); | 
|  | 1169 | } | 
|  | 1170 | EXPORT_SYMBOL_GPL(tee_client_close_session); | 
|  | 1171 |  | 
|  | 1172 | int tee_client_invoke_func(struct tee_context *ctx, | 
|  | 1173 | struct tee_ioctl_invoke_arg *arg, | 
|  | 1174 | struct tee_param *param) | 
|  | 1175 | { | 
|  | 1176 | if (!ctx->teedev->desc->ops->invoke_func) | 
|  | 1177 | return -EINVAL; | 
|  | 1178 | return ctx->teedev->desc->ops->invoke_func(ctx, arg, param); | 
|  | 1179 | } | 
|  | 1180 | EXPORT_SYMBOL_GPL(tee_client_invoke_func); | 
|  | 1181 |  | 
| Igor Opaniuk | 4f062dc | 2019-01-24 19:32:31 +0200 | [diff] [blame] | 1182 | int tee_client_cancel_req(struct tee_context *ctx, | 
|  | 1183 | struct tee_ioctl_cancel_arg *arg) | 
|  | 1184 | { | 
|  | 1185 | if (!ctx->teedev->desc->ops->cancel_req) | 
|  | 1186 | return -EINVAL; | 
|  | 1187 | return ctx->teedev->desc->ops->cancel_req(ctx, arg->cancel_id, | 
|  | 1188 | arg->session); | 
|  | 1189 | } | 
|  | 1190 |  | 
| Sumit Garg | 0fc1db9 | 2019-01-29 11:19:35 +0530 | [diff] [blame] | 1191 | static int tee_client_device_match(struct device *dev, | 
|  | 1192 | struct device_driver *drv) | 
|  | 1193 | { | 
|  | 1194 | const struct tee_client_device_id *id_table; | 
|  | 1195 | struct tee_client_device *tee_device; | 
|  | 1196 |  | 
|  | 1197 | id_table = to_tee_client_driver(drv)->id_table; | 
|  | 1198 | tee_device = to_tee_client_device(dev); | 
|  | 1199 |  | 
|  | 1200 | while (!uuid_is_null(&id_table->uuid)) { | 
|  | 1201 | if (uuid_equal(&tee_device->id.uuid, &id_table->uuid)) | 
|  | 1202 | return 1; | 
|  | 1203 | id_table++; | 
|  | 1204 | } | 
|  | 1205 |  | 
|  | 1206 | return 0; | 
|  | 1207 | } | 
|  | 1208 |  | 
|  | 1209 | static int tee_client_device_uevent(struct device *dev, | 
|  | 1210 | struct kobj_uevent_env *env) | 
|  | 1211 | { | 
|  | 1212 | uuid_t *dev_id = &to_tee_client_device(dev)->id.uuid; | 
|  | 1213 |  | 
|  | 1214 | return add_uevent_var(env, "MODALIAS=tee:%pUb", dev_id); | 
|  | 1215 | } | 
|  | 1216 |  | 
|  | 1217 | struct bus_type tee_bus_type = { | 
|  | 1218 | .name		= "tee", | 
|  | 1219 | .match		= tee_client_device_match, | 
|  | 1220 | .uevent		= tee_client_device_uevent, | 
|  | 1221 | }; | 
|  | 1222 | EXPORT_SYMBOL_GPL(tee_bus_type); | 
|  | 1223 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 1224 | static int __init tee_init(void) | 
|  | 1225 | { | 
|  | 1226 | int rc; | 
|  | 1227 |  | 
|  | 1228 | tee_class = class_create(THIS_MODULE, "tee"); | 
|  | 1229 | if (IS_ERR(tee_class)) { | 
|  | 1230 | pr_err("couldn't create class\n"); | 
|  | 1231 | return PTR_ERR(tee_class); | 
|  | 1232 | } | 
|  | 1233 |  | 
|  | 1234 | rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee"); | 
|  | 1235 | if (rc) { | 
|  | 1236 | pr_err("failed to allocate char dev region\n"); | 
| Sumit Garg | 0fc1db9 | 2019-01-29 11:19:35 +0530 | [diff] [blame] | 1237 | goto out_unreg_class; | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 1238 | } | 
|  | 1239 |  | 
| Sumit Garg | 0fc1db9 | 2019-01-29 11:19:35 +0530 | [diff] [blame] | 1240 | rc = bus_register(&tee_bus_type); | 
|  | 1241 | if (rc) { | 
|  | 1242 | pr_err("failed to register tee bus\n"); | 
|  | 1243 | goto out_unreg_chrdev; | 
|  | 1244 | } | 
|  | 1245 |  | 
|  | 1246 | return 0; | 
|  | 1247 |  | 
|  | 1248 | out_unreg_chrdev: | 
|  | 1249 | unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES); | 
|  | 1250 | out_unreg_class: | 
|  | 1251 | class_destroy(tee_class); | 
|  | 1252 | tee_class = NULL; | 
|  | 1253 |  | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 1254 | return rc; | 
|  | 1255 | } | 
|  | 1256 |  | 
|  | 1257 | static void __exit tee_exit(void) | 
|  | 1258 | { | 
| Sumit Garg | 0fc1db9 | 2019-01-29 11:19:35 +0530 | [diff] [blame] | 1259 | bus_unregister(&tee_bus_type); | 
|  | 1260 | unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES); | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 1261 | class_destroy(tee_class); | 
|  | 1262 | tee_class = NULL; | 
| Jens Wiklander | 967c9cc | 2015-03-11 14:39:39 +0100 | [diff] [blame] | 1263 | } | 
|  | 1264 |  | 
|  | 1265 | subsys_initcall(tee_init); | 
|  | 1266 | module_exit(tee_exit); | 
|  | 1267 |  | 
|  | 1268 | MODULE_AUTHOR("Linaro"); | 
|  | 1269 | MODULE_DESCRIPTION("TEE Driver"); | 
|  | 1270 | MODULE_VERSION("1.0"); | 
|  | 1271 | MODULE_LICENSE("GPL v2"); |