summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2007-02-01 00:38:57 +0100
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2007-02-01 00:38:57 +0100
commit333c6af47a906461678b5a8b2af415936d30babc (patch)
tree4158ba73f5fa8e5fdbf39f2b3b164681fba7b1f9
parent3024f23c6551e219b0236041a8205bf1bc60ed94 (diff)
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.
-rw-r--r--linux-core/drm_vm.c65
1 files 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);