Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tee: new ioctl to a register tee_shm from a dmabuf file descriptor

Add a userspace API to create a tee_shm object that refers to a dmabuf
reference.

Userspace registers the dmabuf file descriptor as in a tee_shm object.
The registration is completed with a tee_shm returned file descriptor.

Userspace is free to close the dmabuf file descriptor after it has been
registered since all the resources are now held via the new tee_shm
object.

Closing the tee_shm file descriptor will eventually release all
resources used by the tee_shm object when all references are released.

The new IOCTL, TEE_IOC_SHM_REGISTER_FD, supports dmabuf references to
physically contiguous memory buffers. Dmabuf references acquired from
the TEE DMA-heap can be used as protected memory for Secure Video Path
and such use cases. It depends on the TEE and the TEE driver if dmabuf
references acquired by other means can be used.

A new tee_shm flag is added to identify tee_shm objects built from a
registered dmabuf, TEE_SHM_DMA_BUF.

Signed-off-by: Etienne Carriere <etienne.carriere@foss.st.com>
Signed-off-by: Olivier Masse <olivier.masse@nxp.com>
Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>

authored by

Etienne Carriere and committed by
Jens Wiklander
146bf4e7 fdf631ac

+182 -4
+61 -1
drivers/tee/tee_core.c
··· 354 354 return ret; 355 355 } 356 356 357 + static int 358 + tee_ioctl_shm_register_fd(struct tee_context *ctx, 359 + struct tee_ioctl_shm_register_fd_data __user *udata) 360 + { 361 + struct tee_ioctl_shm_register_fd_data data; 362 + struct tee_shm *shm; 363 + long ret; 364 + 365 + if (copy_from_user(&data, udata, sizeof(data))) 366 + return -EFAULT; 367 + 368 + /* Currently no input flags are supported */ 369 + if (data.flags) 370 + return -EINVAL; 371 + 372 + shm = tee_shm_register_fd(ctx, data.fd); 373 + if (IS_ERR(shm)) 374 + return -EINVAL; 375 + 376 + data.id = shm->id; 377 + data.flags = shm->flags; 378 + data.size = shm->size; 379 + 380 + if (copy_to_user(udata, &data, sizeof(data))) 381 + ret = -EFAULT; 382 + else 383 + ret = tee_shm_get_fd(shm); 384 + 385 + /* 386 + * When user space closes the file descriptor the shared memory 387 + * should be freed or if tee_shm_get_fd() failed then it will 388 + * be freed immediately. 389 + */ 390 + tee_shm_put(shm); 391 + return ret; 392 + } 393 + 357 394 static int param_from_user_memref(struct tee_context *ctx, 358 395 struct tee_param_memref *memref, 359 396 struct tee_ioctl_param *ip) 360 397 { 361 398 struct tee_shm *shm; 399 + size_t offs = 0; 362 400 363 401 /* 364 402 * If a NULL pointer is passed to a TA in the TEE, ··· 427 389 tee_shm_put(shm); 428 390 return -EINVAL; 429 391 } 392 + 393 + if (shm->flags & TEE_SHM_DMA_BUF) { 394 + struct tee_shm_dmabuf_ref *ref; 395 + 396 + ref = container_of(shm, struct tee_shm_dmabuf_ref, shm); 397 + if (ref->parent_shm) { 398 + /* 399 + * The shm already has one reference to 400 + * ref->parent_shm so we are clear of 0. 401 + * We're getting another reference since 402 + * this shm will be used in the parameter 403 + * list instead of the shm we got with 404 + * tee_shm_get_from_id() above. 405 + */ 406 + refcount_inc(&ref->parent_shm->refcount); 407 + tee_shm_put(shm); 408 + shm = ref->parent_shm; 409 + offs = ref->offset; 410 + } 411 + } 430 412 } else if (ctx->cap_memref_null) { 431 413 /* Pass NULL pointer to OP-TEE */ 432 414 shm = NULL; ··· 454 396 return -EINVAL; 455 397 } 456 398 457 - memref->shm_offs = ip->a; 399 + memref->shm_offs = ip->a + offs; 458 400 memref->size = ip->b; 459 401 memref->shm = shm; 460 402 ··· 900 842 return tee_ioctl_shm_alloc(ctx, uarg); 901 843 case TEE_IOC_SHM_REGISTER: 902 844 return tee_ioctl_shm_register(ctx, uarg); 845 + case TEE_IOC_SHM_REGISTER_FD: 846 + return tee_ioctl_shm_register_fd(ctx, uarg); 903 847 case TEE_IOC_OPEN_SESSION: 904 848 return tee_ioctl_open_session(ctx, uarg); 905 849 case TEE_IOC_INVOKE:
+8
drivers/tee/tee_private.h
··· 13 13 #include <linux/mutex.h> 14 14 #include <linux/types.h> 15 15 16 + /* extra references appended to shm object for registered shared memory */ 17 + struct tee_shm_dmabuf_ref { 18 + struct tee_shm shm; 19 + size_t offset; 20 + struct dma_buf *dmabuf; 21 + struct tee_shm *parent_shm; 22 + }; 23 + 16 24 int tee_shm_get_fd(struct tee_shm *shm); 17 25 18 26 bool tee_device_get(struct tee_device *teedev);
+71 -3
drivers/tee/tee_shm.c
··· 4 4 */ 5 5 #include <linux/anon_inodes.h> 6 6 #include <linux/device.h> 7 + #include <linux/dma-buf.h> 7 8 #include <linux/idr.h> 8 9 #include <linux/io.h> 9 10 #include <linux/mm.h> ··· 46 45 47 46 static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm) 48 47 { 49 - if (shm->flags & TEE_SHM_POOL) { 48 + void *p = shm; 49 + 50 + if (shm->flags & TEE_SHM_DMA_BUF) { 51 + struct tee_shm_dmabuf_ref *ref; 52 + 53 + ref = container_of(shm, struct tee_shm_dmabuf_ref, shm); 54 + p = ref; 55 + dma_buf_put(ref->dmabuf); 56 + } else if (shm->flags & TEE_SHM_POOL) { 50 57 teedev->pool->ops->free(teedev->pool, shm); 51 58 } else if (shm->flags & TEE_SHM_DYNAMIC) { 52 59 int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm); ··· 68 59 69 60 teedev_ctx_put(shm->ctx); 70 61 71 - kfree(shm); 62 + kfree(p); 72 63 73 64 tee_device_put(teedev); 74 65 } ··· 178 169 * tee_client_invoke_func(). The memory allocated is later freed with a 179 170 * call to tee_shm_free(). 180 171 * 181 - * @returns a pointer to 'struct tee_shm' 172 + * @returns a pointer to 'struct tee_shm' on success, and ERR_PTR on failure 182 173 */ 183 174 struct tee_shm *tee_shm_alloc_kernel_buf(struct tee_context *ctx, size_t size) 184 175 { ··· 187 178 return shm_alloc_helper(ctx, size, PAGE_SIZE, flags, -1); 188 179 } 189 180 EXPORT_SYMBOL_GPL(tee_shm_alloc_kernel_buf); 181 + 182 + struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd) 183 + { 184 + struct tee_shm_dmabuf_ref *ref; 185 + int rc; 186 + 187 + if (!tee_device_get(ctx->teedev)) 188 + return ERR_PTR(-EINVAL); 189 + 190 + teedev_ctx_get(ctx); 191 + 192 + ref = kzalloc(sizeof(*ref), GFP_KERNEL); 193 + if (!ref) { 194 + rc = -ENOMEM; 195 + goto err_put_tee; 196 + } 197 + 198 + refcount_set(&ref->shm.refcount, 1); 199 + ref->shm.ctx = ctx; 200 + ref->shm.id = -1; 201 + ref->shm.flags = TEE_SHM_DMA_BUF; 202 + 203 + ref->dmabuf = dma_buf_get(fd); 204 + if (IS_ERR(ref->dmabuf)) { 205 + rc = PTR_ERR(ref->dmabuf); 206 + goto err_kfree_ref; 207 + } 208 + 209 + rc = tee_heap_update_from_dma_buf(ctx->teedev, ref->dmabuf, 210 + &ref->offset, &ref->shm, 211 + &ref->parent_shm); 212 + if (rc) 213 + goto err_put_dmabuf; 214 + 215 + mutex_lock(&ref->shm.ctx->teedev->mutex); 216 + ref->shm.id = idr_alloc(&ref->shm.ctx->teedev->idr, &ref->shm, 217 + 1, 0, GFP_KERNEL); 218 + mutex_unlock(&ref->shm.ctx->teedev->mutex); 219 + if (ref->shm.id < 0) { 220 + rc = ref->shm.id; 221 + goto err_put_dmabuf; 222 + } 223 + 224 + return &ref->shm; 225 + 226 + err_put_dmabuf: 227 + dma_buf_put(ref->dmabuf); 228 + err_kfree_ref: 229 + kfree(ref); 230 + err_put_tee: 231 + teedev_ctx_put(ctx); 232 + tee_device_put(ctx->teedev); 233 + 234 + return ERR_PTR(rc); 235 + } 236 + EXPORT_SYMBOL_GPL(tee_shm_register_fd); 190 237 191 238 /** 192 239 * tee_shm_alloc_priv_buf() - Allocate shared memory for a privately shared ··· 506 441 507 442 /* Refuse sharing shared memory provided by application */ 508 443 if (shm->flags & TEE_SHM_USER_MAPPED) 444 + return -EINVAL; 445 + /* Refuse sharing registered DMA_bufs with the application */ 446 + if (shm->flags & TEE_SHM_DMA_BUF) 509 447 return -EINVAL; 510 448 511 449 /* check for overflowing the buffer's size */
+1
include/linux/tee_core.h
··· 28 28 #define TEE_SHM_USER_MAPPED BIT(1) /* Memory mapped in user space */ 29 29 #define TEE_SHM_POOL BIT(2) /* Memory allocated from pool */ 30 30 #define TEE_SHM_PRIV BIT(3) /* Memory private to TEE driver */ 31 + #define TEE_SHM_DMA_BUF BIT(4) /* Memory with dma-buf handle */ 31 32 32 33 #define TEE_DEVICE_FLAG_REGISTERED 0x1 33 34 #define TEE_MAX_DEV_NAME_LEN 32
+10
include/linux/tee_drv.h
··· 117 117 void *addr, size_t length); 118 118 119 119 /** 120 + * tee_shm_register_fd() - Register shared memory from file descriptor 121 + * 122 + * @ctx: Context that allocates the shared memory 123 + * @fd: Shared memory file descriptor reference 124 + * 125 + * @returns a pointer to 'struct tee_shm' on success, and ERR_PTR on failure 126 + */ 127 + struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd); 128 + 129 + /** 120 130 * tee_shm_free() - Free shared memory 121 131 * @shm: Handle to shared memory to free 122 132 */
+31
include/uapi/linux/tee.h
··· 379 379 }; 380 380 381 381 /** 382 + * struct tee_ioctl_shm_register_fd_data - Shared memory registering argument 383 + * @fd: [in] File descriptor identifying dmabuf reference 384 + * @size: [out] Size of referenced memory 385 + * @flags: [in] Flags to/from allocation. 386 + * @id: [out] Identifier of the shared memory 387 + * 388 + * The flags field should currently be zero as input. Updated by the call 389 + * with actual flags as defined by TEE_IOCTL_SHM_* above. 390 + * This structure is used as argument for TEE_IOC_SHM_REGISTER_FD below. 391 + */ 392 + struct tee_ioctl_shm_register_fd_data { 393 + __s64 fd; 394 + __u64 size; 395 + __u32 flags; 396 + __s32 id; 397 + }; 398 + 399 + /** 400 + * TEE_IOC_SHM_REGISTER_FD - register a shared memory from a file descriptor 401 + * 402 + * Returns a file descriptor on success or < 0 on failure 403 + * 404 + * The returned file descriptor refers to the shared memory object in the 405 + * kernel. The supplied file deccriptor can be closed if it's not needed 406 + * for other purposes. The shared memory is freed when the descriptor is 407 + * closed. 408 + */ 409 + #define TEE_IOC_SHM_REGISTER_FD _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 8, \ 410 + struct tee_ioctl_shm_register_fd_data) 411 + 412 + /** 382 413 * TEE_IOC_SHM_REGISTER - Register shared memory argument 383 414 * 384 415 * Registers shared memory between the user space process and secure OS.