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

tee: add register user memory

Added new ioctl to allow users register own buffers as a shared memory.

Signed-off-by: Volodymyr Babchuk <vlad.babchuk@gmail.com>
[jw: moved tee_shm_is_registered() declaration]
[jw: added space after __tee_shm_alloc() implementation]
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>

+294 -30
+39 -2
drivers/tee/tee_core.c
··· 114 114 if (data.flags) 115 115 return -EINVAL; 116 116 117 - data.id = -1; 118 - 119 117 shm = tee_shm_alloc(ctx, data.size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); 120 118 if (IS_ERR(shm)) 121 119 return PTR_ERR(shm); ··· 127 129 else 128 130 ret = tee_shm_get_fd(shm); 129 131 132 + /* 133 + * When user space closes the file descriptor the shared memory 134 + * should be freed or if tee_shm_get_fd() failed then it will 135 + * be freed immediately. 136 + */ 137 + tee_shm_put(shm); 138 + return ret; 139 + } 140 + 141 + static int 142 + tee_ioctl_shm_register(struct tee_context *ctx, 143 + struct tee_ioctl_shm_register_data __user *udata) 144 + { 145 + long ret; 146 + struct tee_ioctl_shm_register_data data; 147 + struct tee_shm *shm; 148 + 149 + if (copy_from_user(&data, udata, sizeof(data))) 150 + return -EFAULT; 151 + 152 + /* Currently no input flags are supported */ 153 + if (data.flags) 154 + return -EINVAL; 155 + 156 + shm = tee_shm_register(ctx, data.addr, data.length, 157 + TEE_SHM_DMA_BUF | TEE_SHM_USER_MAPPED); 158 + if (IS_ERR(shm)) 159 + return PTR_ERR(shm); 160 + 161 + data.id = shm->id; 162 + data.flags = shm->flags; 163 + data.length = shm->size; 164 + 165 + if (copy_to_user(udata, &data, sizeof(data))) 166 + ret = -EFAULT; 167 + else 168 + ret = tee_shm_get_fd(shm); 130 169 /* 131 170 * When user space closes the file descriptor the shared memory 132 171 * should be freed or if tee_shm_get_fd() failed then it will ··· 621 586 return tee_ioctl_version(ctx, uarg); 622 587 case TEE_IOC_SHM_ALLOC: 623 588 return tee_ioctl_shm_alloc(ctx, uarg); 589 + case TEE_IOC_SHM_REGISTER: 590 + return tee_ioctl_shm_register(ctx, uarg); 624 591 case TEE_IOC_OPEN_SESSION: 625 592 return tee_ioctl_open_session(ctx, uarg); 626 593 case TEE_IOC_INVOKE:
+180 -26
drivers/tee/tee_shm.c
··· 23 23 static void tee_shm_release(struct tee_shm *shm) 24 24 { 25 25 struct tee_device *teedev = shm->teedev; 26 - struct tee_shm_pool_mgr *poolm; 27 26 28 27 mutex_lock(&teedev->mutex); 29 28 idr_remove(&teedev->idr, shm->id); ··· 30 31 list_del(&shm->link); 31 32 mutex_unlock(&teedev->mutex); 32 33 33 - if (shm->flags & TEE_SHM_DMA_BUF) 34 - poolm = teedev->pool->dma_buf_mgr; 35 - else 36 - poolm = teedev->pool->private_mgr; 34 + if (shm->flags & TEE_SHM_POOL) { 35 + struct tee_shm_pool_mgr *poolm; 37 36 38 - poolm->ops->free(poolm, shm); 37 + if (shm->flags & TEE_SHM_DMA_BUF) 38 + poolm = teedev->pool->dma_buf_mgr; 39 + else 40 + poolm = teedev->pool->private_mgr; 41 + 42 + poolm->ops->free(poolm, shm); 43 + } else if (shm->flags & TEE_SHM_REGISTER) { 44 + size_t n; 45 + int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm); 46 + 47 + if (rc) 48 + dev_err(teedev->dev.parent, 49 + "unregister shm %p failed: %d", shm, rc); 50 + 51 + for (n = 0; n < shm->num_pages; n++) 52 + put_page(shm->pages[n]); 53 + 54 + kfree(shm->pages); 55 + } 56 + 39 57 kfree(shm); 40 58 41 59 tee_device_put(teedev); ··· 92 76 struct tee_shm *shm = dmabuf->priv; 93 77 size_t size = vma->vm_end - vma->vm_start; 94 78 79 + /* Refuse sharing shared memory provided by application */ 80 + if (shm->flags & TEE_SHM_REGISTER) 81 + return -EINVAL; 82 + 95 83 return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT, 96 84 size, vma->vm_page_prot); 97 85 } ··· 109 89 .mmap = tee_shm_op_mmap, 110 90 }; 111 91 112 - /** 113 - * tee_shm_alloc() - Allocate shared memory 114 - * @ctx: Context that allocates the shared memory 115 - * @size: Requested size of shared memory 116 - * @flags: Flags setting properties for the requested shared memory. 117 - * 118 - * Memory allocated as global shared memory is automatically freed when the 119 - * TEE file pointer is closed. The @flags field uses the bits defined by 120 - * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be 121 - * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and 122 - * associated with a dma-buf handle, else driver private memory. 123 - */ 124 - struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags) 92 + struct tee_shm *__tee_shm_alloc(struct tee_context *ctx, 93 + struct tee_device *teedev, 94 + size_t size, u32 flags) 125 95 { 126 - struct tee_device *teedev = ctx->teedev; 127 96 struct tee_shm_pool_mgr *poolm = NULL; 128 97 struct tee_shm *shm; 129 98 void *ret; 130 99 int rc; 100 + 101 + if (ctx && ctx->teedev != teedev) { 102 + dev_err(teedev->dev.parent, "ctx and teedev mismatch\n"); 103 + return ERR_PTR(-EINVAL); 104 + } 131 105 132 106 if (!(flags & TEE_SHM_MAPPED)) { 133 107 dev_err(teedev->dev.parent, ··· 149 135 goto err_dev_put; 150 136 } 151 137 152 - shm->flags = flags; 138 + shm->flags = flags | TEE_SHM_POOL; 153 139 shm->teedev = teedev; 154 140 shm->ctx = ctx; 155 141 if (flags & TEE_SHM_DMA_BUF) ··· 185 171 goto err_rem; 186 172 } 187 173 } 188 - mutex_lock(&teedev->mutex); 189 - list_add_tail(&shm->link, &ctx->list_shm); 190 - mutex_unlock(&teedev->mutex); 174 + 175 + if (ctx) { 176 + mutex_lock(&teedev->mutex); 177 + list_add_tail(&shm->link, &ctx->list_shm); 178 + mutex_unlock(&teedev->mutex); 179 + } 191 180 192 181 return shm; 193 182 err_rem: ··· 205 188 tee_device_put(teedev); 206 189 return ret; 207 190 } 191 + 192 + /** 193 + * tee_shm_alloc() - Allocate shared memory 194 + * @ctx: Context that allocates the shared memory 195 + * @size: Requested size of shared memory 196 + * @flags: Flags setting properties for the requested shared memory. 197 + * 198 + * Memory allocated as global shared memory is automatically freed when the 199 + * TEE file pointer is closed. The @flags field uses the bits defined by 200 + * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be 201 + * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and 202 + * associated with a dma-buf handle, else driver private memory. 203 + */ 204 + struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags) 205 + { 206 + return __tee_shm_alloc(ctx, ctx->teedev, size, flags); 207 + } 208 208 EXPORT_SYMBOL_GPL(tee_shm_alloc); 209 + 210 + struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size) 211 + { 212 + return __tee_shm_alloc(NULL, teedev, size, TEE_SHM_MAPPED); 213 + } 214 + EXPORT_SYMBOL_GPL(tee_shm_priv_alloc); 215 + 216 + struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr, 217 + size_t length, u32 flags) 218 + { 219 + struct tee_device *teedev = ctx->teedev; 220 + const u32 req_flags = TEE_SHM_DMA_BUF | TEE_SHM_USER_MAPPED; 221 + struct tee_shm *shm; 222 + void *ret; 223 + int rc; 224 + int num_pages; 225 + unsigned long start; 226 + 227 + if (flags != req_flags) 228 + return ERR_PTR(-ENOTSUPP); 229 + 230 + if (!tee_device_get(teedev)) 231 + return ERR_PTR(-EINVAL); 232 + 233 + if (!teedev->desc->ops->shm_register || 234 + !teedev->desc->ops->shm_unregister) { 235 + tee_device_put(teedev); 236 + return ERR_PTR(-ENOTSUPP); 237 + } 238 + 239 + shm = kzalloc(sizeof(*shm), GFP_KERNEL); 240 + if (!shm) { 241 + ret = ERR_PTR(-ENOMEM); 242 + goto err; 243 + } 244 + 245 + shm->flags = flags | TEE_SHM_REGISTER; 246 + shm->teedev = teedev; 247 + shm->ctx = ctx; 248 + shm->id = -1; 249 + start = rounddown(addr, PAGE_SIZE); 250 + shm->offset = addr - start; 251 + shm->size = length; 252 + num_pages = (roundup(addr + length, PAGE_SIZE) - start) / PAGE_SIZE; 253 + shm->pages = kcalloc(num_pages, sizeof(*shm->pages), GFP_KERNEL); 254 + if (!shm->pages) { 255 + ret = ERR_PTR(-ENOMEM); 256 + goto err; 257 + } 258 + 259 + rc = get_user_pages_fast(start, num_pages, 1, shm->pages); 260 + if (rc > 0) 261 + shm->num_pages = rc; 262 + if (rc != num_pages) { 263 + if (rc > 0) 264 + rc = -ENOMEM; 265 + ret = ERR_PTR(rc); 266 + goto err; 267 + } 268 + 269 + mutex_lock(&teedev->mutex); 270 + shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL); 271 + mutex_unlock(&teedev->mutex); 272 + 273 + if (shm->id < 0) { 274 + ret = ERR_PTR(shm->id); 275 + goto err; 276 + } 277 + 278 + rc = teedev->desc->ops->shm_register(ctx, shm, shm->pages, 279 + shm->num_pages); 280 + if (rc) { 281 + ret = ERR_PTR(rc); 282 + goto err; 283 + } 284 + 285 + if (flags & TEE_SHM_DMA_BUF) { 286 + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 287 + 288 + exp_info.ops = &tee_shm_dma_buf_ops; 289 + exp_info.size = shm->size; 290 + exp_info.flags = O_RDWR; 291 + exp_info.priv = shm; 292 + 293 + shm->dmabuf = dma_buf_export(&exp_info); 294 + if (IS_ERR(shm->dmabuf)) { 295 + ret = ERR_CAST(shm->dmabuf); 296 + teedev->desc->ops->shm_unregister(ctx, shm); 297 + goto err; 298 + } 299 + } 300 + 301 + mutex_lock(&teedev->mutex); 302 + list_add_tail(&shm->link, &ctx->list_shm); 303 + mutex_unlock(&teedev->mutex); 304 + 305 + return shm; 306 + err: 307 + if (shm) { 308 + size_t n; 309 + 310 + if (shm->id >= 0) { 311 + mutex_lock(&teedev->mutex); 312 + idr_remove(&teedev->idr, shm->id); 313 + mutex_unlock(&teedev->mutex); 314 + } 315 + for (n = 0; n < shm->num_pages; n++) 316 + put_page(shm->pages[n]); 317 + kfree(shm->pages); 318 + } 319 + kfree(shm); 320 + tee_device_put(teedev); 321 + return ret; 322 + } 323 + EXPORT_SYMBOL_GPL(tee_shm_register); 209 324 210 325 /** 211 326 * tee_shm_get_fd() - Increase reference count and return file descriptor ··· 346 197 */ 347 198 int tee_shm_get_fd(struct tee_shm *shm) 348 199 { 349 - u32 req_flags = TEE_SHM_MAPPED | TEE_SHM_DMA_BUF; 350 200 int fd; 351 201 352 - if ((shm->flags & req_flags) != req_flags) 202 + if (!(shm->flags & TEE_SHM_DMA_BUF)) 353 203 return -EINVAL; 354 204 355 205 fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC); ··· 386 238 */ 387 239 int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa) 388 240 { 241 + if (!(shm->flags & TEE_SHM_MAPPED)) 242 + return -EINVAL; 389 243 /* Check that we're in the range of the shm */ 390 244 if ((char *)va < (char *)shm->kaddr) 391 245 return -EINVAL; ··· 408 258 */ 409 259 int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va) 410 260 { 261 + if (!(shm->flags & TEE_SHM_MAPPED)) 262 + return -EINVAL; 411 263 /* Check that we're in the range of the shm */ 412 264 if (pa < shm->paddr) 413 265 return -EINVAL; ··· 436 284 */ 437 285 void *tee_shm_get_va(struct tee_shm *shm, size_t offs) 438 286 { 287 + if (!(shm->flags & TEE_SHM_MAPPED)) 288 + return ERR_PTR(-EINVAL); 439 289 if (offs >= shm->size) 440 290 return ERR_PTR(-EINVAL); 441 291 return (char *)shm->kaddr + offs;
+45 -2
include/linux/tee_drv.h
··· 25 25 * specific TEE driver. 26 26 */ 27 27 28 - #define TEE_SHM_MAPPED 0x1 /* Memory mapped by the kernel */ 29 - #define TEE_SHM_DMA_BUF 0x2 /* Memory with dma-buf handle */ 28 + #define TEE_SHM_MAPPED BIT(0) /* Memory mapped by the kernel */ 29 + #define TEE_SHM_DMA_BUF BIT(1) /* Memory with dma-buf handle */ 30 + #define TEE_SHM_EXT_DMA_BUF BIT(2) /* Memory with dma-buf handle */ 31 + #define TEE_SHM_REGISTER BIT(3) /* Memory registered in secure world */ 32 + #define TEE_SHM_USER_MAPPED BIT(4) /* Memory mapped in user space */ 33 + #define TEE_SHM_POOL BIT(5) /* Memory allocated from pool */ 30 34 31 35 struct device; 32 36 struct tee_device; ··· 80 76 * @cancel_req: request cancel of an ongoing invoke or open 81 77 * @supp_revc: called for supplicant to get a command 82 78 * @supp_send: called for supplicant to send a response 79 + * @shm_register: register shared memory buffer in TEE 80 + * @shm_unregister: unregister shared memory buffer in TEE 83 81 */ 84 82 struct tee_driver_ops { 85 83 void (*get_version)(struct tee_device *teedev, ··· 100 94 struct tee_param *param); 101 95 int (*supp_send)(struct tee_context *ctx, u32 ret, u32 num_params, 102 96 struct tee_param *param); 97 + int (*shm_register)(struct tee_context *ctx, struct tee_shm *shm, 98 + struct page **pages, size_t num_pages); 99 + int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm); 103 100 }; 104 101 105 102 /** ··· 309 300 * @returns a pointer to 'struct tee_shm' 310 301 */ 311 302 struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags); 303 + 304 + /** 305 + * tee_shm_priv_alloc() - Allocate shared memory privately 306 + * @dev: Device that allocates the shared memory 307 + * @size: Requested size of shared memory 308 + * 309 + * Allocates shared memory buffer that is not associated with any client 310 + * context. Such buffers are owned by TEE driver and used for internal calls. 311 + * 312 + * @returns a pointer to 'struct tee_shm' 313 + */ 314 + struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size); 315 + 316 + /** 317 + * tee_shm_register() - Register shared memory buffer 318 + * @ctx: Context that registers the shared memory 319 + * @addr: Address is userspace of the shared buffer 320 + * @length: Length of the shared buffer 321 + * @flags: Flags setting properties for the requested shared memory. 322 + * 323 + * @returns a pointer to 'struct tee_shm' 324 + */ 325 + struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr, 326 + size_t length, u32 flags); 327 + 328 + /** 329 + * tee_shm_is_registered() - Check if shared memory object in registered in TEE 330 + * @shm: Shared memory handle 331 + * @returns true if object is registered in TEE 332 + */ 333 + static inline bool tee_shm_is_registered(struct tee_shm *shm) 334 + { 335 + return shm && (shm->flags & TEE_SHM_REGISTER); 336 + } 312 337 313 338 /** 314 339 * tee_shm_free() - Free shared memory
+30
include/uapi/linux/tee.h
··· 50 50 51 51 #define TEE_GEN_CAP_GP (1 << 0)/* GlobalPlatform compliant TEE */ 52 52 #define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplicant) */ 53 + #define TEE_GEN_CAP_REG_MEM (1 << 2)/* Supports registering shared memory */ 53 54 54 55 /* 55 56 * TEE Implementation ID ··· 333 332 #define TEE_IOC_SUPPL_SEND _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 7, \ 334 333 struct tee_ioctl_buf_data) 335 334 335 + /** 336 + * struct tee_ioctl_shm_register_data - Shared memory register argument 337 + * @addr: [in] Start address of shared memory to register 338 + * @length: [in/out] Length of shared memory to register 339 + * @flags: [in/out] Flags to/from registration. 340 + * @id: [out] Identifier of the shared memory 341 + * 342 + * The flags field should currently be zero as input. Updated by the call 343 + * with actual flags as defined by TEE_IOCTL_SHM_* above. 344 + * This structure is used as argument for TEE_IOC_SHM_REGISTER below. 345 + */ 346 + struct tee_ioctl_shm_register_data { 347 + __u64 addr; 348 + __u64 length; 349 + __u32 flags; 350 + __s32 id; 351 + }; 352 + 353 + /** 354 + * TEE_IOC_SHM_REGISTER - Register shared memory argument 355 + * 356 + * Registers shared memory between the user space process and secure OS. 357 + * 358 + * Returns a file descriptor on success or < 0 on failure 359 + * 360 + * The shared memory is unregisterred when the descriptor is closed. 361 + */ 362 + #define TEE_IOC_SHM_REGISTER _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 9, \ 363 + struct tee_ioctl_shm_register_data) 336 364 /* 337 365 * Five syscalls are used when communicating with the TEE driver. 338 366 * open(): opens the device associated with the driver