From 2c409f9a07a9d815b95fc8a5a4705d7988afe5df Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 18 Feb 2008 10:39:21 +1000 Subject: ttm: make sure userspace can't destroy kernel create memory managers --- linux-core/drm_bo.c | 30 ++++++++++++++++++++---------- linux-core/drm_objects.h | 6 ++++-- shared-core/i915_init.c | 8 ++++---- shared-core/nouveau_mem.c | 6 +++--- shared-core/radeon_ms_drm.c | 8 ++++---- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 1f3c2d2c..54b8baf8 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2178,7 +2178,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]; @@ -2194,6 +2194,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; @@ -2245,9 +2252,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; @@ -2281,6 +2288,7 @@ int drm_bo_init_mm(struct drm_device *dev, } man->has_type = 1; man->use_type = 1; + man->kern_init_type = kern_init; INIT_LIST_HEAD(&man->lru); INIT_LIST_HEAD(&man->pinned); @@ -2313,7 +2321,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); @@ -2384,7 +2392,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; @@ -2444,7 +2452,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); @@ -2483,9 +2491,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); diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 7b585c3e..71da4b27 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -515,6 +515,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; @@ -681,9 +682,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, diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index fe2fb389..b2d3f0d0 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -167,8 +167,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); printk("setting up %ld bytes of VRAM space\n", prealloc_size); printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size)); - drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT); - drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT); + drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT, 1); + drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT, 1); I915_WRITE(LP_RING + RING_LEN, 0); I915_WRITE(LP_RING + RING_HEAD, 0); @@ -305,11 +305,11 @@ int i915_driver_unload(struct drm_device *dev) mutex_lock(&dev->struct_mutex); drm_bo_usage_deref_locked(&dev_priv->ring_buffer); - if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) { + if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) { DRM_ERROR("Memory manager type 3 not clean. " "Delaying takedown\n"); } - if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { + if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { DRM_ERROR("Memory manager type 3 not clean. " "Delaying takedown\n"); } diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 3d376aed..80b2990d 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -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; } diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index bf76b45d..857182ae 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -160,7 +160,7 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->fence_reg = SCRATCH_REG2; drm_bo_driver_init(dev); /* initialize vram */ - ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size); + ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size, 1); if (ret != 0) { radeon_ms_driver_unload(dev); return ret; @@ -176,7 +176,7 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) /* initialize ttm */ ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0, - dev_priv->gpu_gart_size / RADEON_PAGE_SIZE); + dev_priv->gpu_gart_size / RADEON_PAGE_SIZE, 1); if (ret != 0) { radeon_ms_driver_unload(dev); return ret; @@ -277,7 +277,7 @@ int radeon_ms_driver_unload(struct drm_device *dev) DRM_INFO("[radeon_ms] unloading\n"); /* clean ttm memory manager */ mutex_lock(&dev->struct_mutex); - if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) { + if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) { DRM_ERROR("TT memory manager not clean. Delaying takedown\n"); } mutex_unlock(&dev->struct_mutex); @@ -289,7 +289,7 @@ int radeon_ms_driver_unload(struct drm_device *dev) DRM_INFO("[radeon_ms] bus down\n"); /* clean vram memory manager */ mutex_lock(&dev->struct_mutex); - if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { + if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { DRM_ERROR("VRAM memory manager not clean. Delaying takedown\n"); } mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3