ttm: make sure userspace can't destroy kernel create memory managers
authorDave Airlie <airlied@redhat.com>
Mon, 18 Feb 2008 00:39:21 +0000 (10:39 +1000)
committerDave Airlie <airlied@linux.ie>
Wed, 5 Mar 2008 19:37:54 +0000 (05:37 +1000)
this adds something to say the kernel initialised the memory region not
the userspace. and blocks userspace from deallocating kernel areas

linux-core/drm_bo.c
linux-core/drm_objects.h
shared-core/nouveau_mem.c

index b67946e..3e8ffa0 100644 (file)
@@ -2180,7 +2180,7 @@ restart:
        return 0;
 }
 
-int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type)
+int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_clean)
 {
        struct drm_buffer_manager *bm = &dev->bm;
        struct drm_mem_type_manager *man = &bm->man[mem_type];
@@ -2196,6 +2196,13 @@ int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type)
                          "memory manager type %u\n", mem_type);
                return ret;
        }
+
+       if ((man->kern_init_type) && (kern_clean == 0)) {
+               DRM_ERROR("Trying to take down kernel initialized "
+                         "memory manager type %u\n", mem_type);
+               return -EPERM;
+       }
+
        man->use_type = 0;
        man->has_type = 0;
 
@@ -2247,9 +2254,9 @@ static int drm_bo_lock_mm(struct drm_device *dev, unsigned mem_type)
        return ret;
 }
 
-int drm_bo_init_mm(struct drm_device *dev,
-                  unsigned type,
-                  unsigned long p_offset, unsigned long p_size)
+int drm_bo_init_mm(struct drm_device *dev, unsigned type,
+                  unsigned long p_offset, unsigned long p_size,
+                  int kern_init)
 {
        struct drm_buffer_manager *bm = &dev->bm;
        int ret = -EINVAL;
@@ -2283,6 +2290,7 @@ int drm_bo_init_mm(struct drm_device *dev,
        }
        man->has_type = 1;
        man->use_type = 1;
+       man->kern_init_type = kern_init;
        man->size = p_size;
 
        INIT_LIST_HEAD(&man->lru);
@@ -2316,7 +2324,7 @@ int drm_bo_driver_finish(struct drm_device *dev)
                man = &bm->man[i];
                if (man->has_type) {
                        man->use_type = 0;
-                       if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i)) {
+                       if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i, 1)) {
                                ret = -EBUSY;
                                DRM_ERROR("DRM memory manager type %d "
                                          "is not clean.\n", i);
@@ -2386,7 +2394,7 @@ int drm_bo_driver_init(struct drm_device *dev)
         * Initialize the system memory buffer type.
         * Other types need to be driver / IOCTL initialized.
         */
-       ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0);
+       ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0, 1);
        if (ret)
                goto out_unlock;
 
@@ -2446,7 +2454,7 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
                goto out;
        }
        ret = drm_bo_init_mm(dev, arg->mem_type,
-                            arg->p_offset, arg->p_size);
+                            arg->p_offset, arg->p_size, 0);
 
 out:
        mutex_unlock(&dev->struct_mutex);
@@ -2485,9 +2493,11 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f
                goto out;
        }
        ret = 0;
-       if (drm_bo_clean_mm(dev, arg->mem_type)) {
-               DRM_ERROR("Memory manager type %d not clean. "
-                         "Delaying takedown\n", arg->mem_type);
+       if ((ret = drm_bo_clean_mm(dev, arg->mem_type, 0))) {
+               if (ret == -EINVAL)
+                       DRM_ERROR("Memory manager type %d not clean. "
+                                 "Delaying takedown\n", arg->mem_type);
+               ret = 0;
        }
 out:
        mutex_unlock(&dev->struct_mutex);
index ae0725c..69e3f67 100644 (file)
@@ -516,6 +516,7 @@ struct drm_buffer_object {
 struct drm_mem_type_manager {
        int has_type;
        int use_type;
+       int kern_init_type;
        struct drm_mm manager;
        struct list_head lru;
        struct list_head pinned;
@@ -684,9 +685,10 @@ extern int drm_bo_mem_space(struct drm_buffer_object *bo,
 extern int drm_bo_move_buffer(struct drm_buffer_object *bo,
                              uint64_t new_mem_flags,
                              int no_wait, int move_unfenced);
-extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type);
+extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_clean);
 extern int drm_bo_init_mm(struct drm_device *dev, unsigned type,
-                         unsigned long p_offset, unsigned long p_size);
+                         unsigned long p_offset, unsigned long p_size,
+                         int kern_init);
 extern int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle,
                                  uint64_t flags, uint64_t mask, uint32_t hint,
                                  uint32_t fence_class, int use_old_fence_class,
index 3d376ae..80b2990 100644 (file)
@@ -376,7 +376,7 @@ nouveau_mem_init_ttm(struct drm_device *dev)
        bar1_size = drm_get_resource_len(dev, 1) >> PAGE_SHIFT;
        if (bar1_size < vram_size) {
                if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0,
-                                         bar1_size, vram_size - bar1_size))) {
+                                         bar1_size, vram_size - bar1_size, 1))) {
                        DRM_ERROR("Failed PRIV0 mm init: %d\n", ret);
                        return ret;
                }
@@ -387,7 +387,7 @@ nouveau_mem_init_ttm(struct drm_device *dev)
 #ifdef HACK_OLD_MM
        vram_size /= 4;
 #endif
-       if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, vram_size))) {
+       if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, vram_size, 1))) {
                DRM_ERROR("Failed VRAM mm init: %d\n", ret);
                return ret;
        }
@@ -407,7 +407,7 @@ nouveau_mem_init_ttm(struct drm_device *dev)
 
        if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0,
                                  dev_priv->gart_info.aper_size >>
-                                 PAGE_SHIFT))) {
+                                 PAGE_SHIFT, 1))) {
                DRM_ERROR("Failed TT mm init: %d\n", ret);
                return ret;
        }