Since the tee subsystem does not keep a strong reference to its idle shared memory buffers, it races with other threads that try to destroy a shared memory through a close of its dma-buf fd or by unmapping the memory. In tee_shm_get_from_id() when a lookup in teedev->idr has been successful, it is possible that the tee_shm is in the dma-buf teardown path, but that path is blocked by the teedev mutex. Since we don't have an API to tell if the tee_shm is in the dma-buf teardown path or not we must find another way of detecting this condition. Fix this by doing the reference counting directly on the tee_shm using a new refcount_t refcount field. dma-buf is replaced by using anon_inode_getfd() instead, this separates the life-cycle of the underlying file from the tee_shm. tee_shm_put() is updated to hold the mutex when decreasing the refcount to 0 and then remove the tee_shm from teedev->idr before releasing the mutex. This means that the tee_shm can never be found unless it has a refcount larger than 0.
Showing the changes to include/linux (1 of 2 files). Show all
Unified · Split
| @@ -195,7 +195,7 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method, · 194 unmodified lines | |||
| 195 | * @offset: offset of buffer in user space | 195 | * @offset: offset of buffer in user space |
| 196 | * @pages: locked pages from userspace | 196 | * @pages: locked pages from userspace |
| 197 | * @num_pages: number of locked pages | 197 | * @num_pages: number of locked pages |
| 198 | * @dmabuf: dmabuf used to for exporting to user space | 198 | * @refcount: reference counter |
| 199 | * @flags: defined by TEE_SHM_* in tee_drv.h | 199 | * @flags: defined by TEE_SHM_* in tee_drv.h |
| 200 | * @id: unique id of a shared memory object on this device, shared | 200 | * @id: unique id of a shared memory object on this device, shared |
| 201 | * with user space | 201 | * with user space |
| @@ -214,7 +214,7 @@ struct tee_shm { · 12 unmodified lines | |||
| 214 | unsigned int offset; | 214 | unsigned int offset; |
| 215 | struct page **pages; | 215 | struct page **pages; |
| 216 | size_t num_pages; | 216 | size_t num_pages; |
| 217 | struct dma_buf *dmabuf; | 217 | refcount_t refcount; |
| 218 | u32 flags; | 218 | u32 flags; |
| 219 | int id; | 219 | int id; |
| 220 | u64 sec_world_id; | 220 | u64 sec_world_id; |