From 333c6af47a906461678b5a8b2af415936d30babc Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 1 Feb 2007 00:38:57 +0100 Subject: Protect drm_mmap against disappearing maps. The map lists and hash tables are protected using dev->struct_mutex, but drm_mmap strangely never locked this mutex. --- linux-core/drm_vm.c | 65 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 827a7bdb..b11e09f8 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -42,8 +42,7 @@ static void drm_vm_open(struct vm_area_struct *vma); static void drm_vm_close(struct vm_area_struct *vma); static void drm_vm_ttm_close(struct vm_area_struct *vma); -static int drm_vm_ttm_open(struct vm_area_struct *vma); -static void drm_vm_ttm_open_wrapper(struct vm_area_struct *vma); +static void drm_vm_ttm_open(struct vm_area_struct *vma); pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) @@ -511,13 +510,13 @@ static struct vm_operations_struct drm_vm_sg_ops = { #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) static struct vm_operations_struct drm_vm_ttm_ops = { .nopage = drm_vm_ttm_nopage, - .open = drm_vm_ttm_open_wrapper, + .open = drm_vm_ttm_open, .close = drm_vm_ttm_close, }; #else static struct vm_operations_struct drm_vm_ttm_ops = { .fault = drm_vm_ttm_fault, - .open = drm_vm_ttm_open_wrapper, + .open = drm_vm_ttm_open, .close = drm_vm_ttm_close, }; #endif @@ -530,7 +529,7 @@ static struct vm_operations_struct drm_vm_ttm_ops = { * Create a new drm_vma_entry structure as the \p vma private data entry and * add it to drm_device::vmalist. */ -static void drm_vm_open(struct vm_area_struct *vma) +static void drm_vm_open_locked(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->head->dev; @@ -542,36 +541,43 @@ static void drm_vm_open(struct vm_area_struct *vma) vma_entry = drm_ctl_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); if (vma_entry) { - mutex_lock(&dev->struct_mutex); vma_entry->vma = vma; vma_entry->next = dev->vmalist; vma_entry->pid = current->pid; dev->vmalist = vma_entry; - mutex_unlock(&dev->struct_mutex); } } -static int drm_vm_ttm_open(struct vm_area_struct *vma) { - - drm_local_map_t *map = (drm_local_map_t *)vma->vm_private_data; - drm_ttm_t *ttm; +static void drm_vm_open(struct vm_area_struct *vma) +{ drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->head->dev; - drm_vm_open(vma); mutex_lock(&dev->struct_mutex); + drm_vm_open_locked(vma); + mutex_unlock(&dev->struct_mutex); +} + +static void drm_vm_ttm_open_locked(struct vm_area_struct *vma) { + + drm_local_map_t *map = (drm_local_map_t *)vma->vm_private_data; + drm_ttm_t *ttm; + + drm_vm_open_locked(vma); ttm = (drm_ttm_t *) map->offset; atomic_inc(&ttm->vma_count); #ifdef DRM_ODD_MM_COMPAT drm_ttm_add_vma(ttm, vma); #endif - mutex_unlock(&dev->struct_mutex); - return 0; } -static void drm_vm_ttm_open_wrapper(struct vm_area_struct *vma) -{ - drm_vm_ttm_open(vma); +static void drm_vm_ttm_open(struct vm_area_struct *vma) { + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->head->dev; + + mutex_lock(&dev->struct_mutex); + drm_vm_ttm_open_locked(vma); + mutex_unlock(&dev->struct_mutex); } /** @@ -653,7 +659,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) drm_device_dma_t *dma; unsigned long length = vma->vm_end - vma->vm_start; - lock_kernel(); dev = priv->head->dev; dma = dev->dma; DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", @@ -664,7 +669,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) unlock_kernel(); return -EINVAL; } - unlock_kernel(); if (!capable(CAP_SYS_ADMIN) && (dma->flags & _DRM_DMA_USE_PCI_RO)) { @@ -686,7 +690,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_file = filp; /* Needed for drm_vm_open() */ - drm_vm_open(vma); + drm_vm_open_locked(vma); return 0; } @@ -719,7 +723,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs); * according to the mapping type and remaps the pages. Finally sets the file * pointer and calls vm_open(). */ -int drm_mmap(struct file *filp, struct vm_area_struct *vma) +static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; @@ -839,12 +843,8 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_file = filp; vma->vm_flags |= VM_RESERVED | VM_IO; #ifdef DRM_ODD_MM_COMPAT - mutex_lock(&dev->struct_mutex); drm_ttm_map_bound(vma); - mutex_unlock(&dev->struct_mutex); #endif - if (drm_vm_ttm_open(vma)) - return -EAGAIN; return 0; } default: @@ -853,7 +853,20 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_file = filp; /* Needed for drm_vm_open() */ - drm_vm_open(vma); + drm_vm_open_locked(vma); return 0; } + +int drm_mmap(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_mmap_locked(filp, vma); + mutex_unlock(&dev->struct_mutex); + + return ret; +} EXPORT_SYMBOL(drm_mmap); -- cgit v1.2.3