aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-03-12 14:52:55 -0500
committerEric Anholt <eric@anholt.net>2010-03-17 16:17:24 -0400
commit1f2b10131f83f7caa67bf1273cec126b4283015d (patch)
treed1e447b0d39a04c065f7878603b9e66444a0b69f
parent59f2d0fc4bdfbbfabfa3715ba17d0609e5964c7e (diff)
drm/i915: Avoid NULL deref in get_pages() unwind after error.
Fixes: http://bugzilla.kernel.org/show_bug.cgi?id=15527 NULL pointer dereference in i915_gem_object_save_bit_17_swizzle BUG: unable to handle kernel NULL pointer dereference at (null) IP: [<f82b5d2b>] i915_gem_object_save_bit_17_swizzle+0x5b/0xc0 [i915] Call Trace: [<f82aea55>] ? i915_gem_object_put_pages+0x125/0x150 [i915] [<f82aeb71>] ? i915_gem_object_get_pages+0xf1/0x110 [i915] [<f82b0de8>] ? i915_gem_object_bind_to_gtt+0xb8/0x2a0 [i915] [<c02db74d>] ? drm_mm_get_block_generic+0x4d/0x180 [<f82b11cd>] ? i915_gem_mmap_gtt_ioctl+0x16d/0x240 [i915] [<f82ae786>] ? i915_gem_madvise_ioctl+0x86/0x120 [i915] Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reported-by: maciej.rutecki@gmail.com Cc: stable@kernel.org Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 134973f77069..933e865a8929 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1466,9 +1466,6 @@ i915_gem_object_put_pages(struct drm_gem_object *obj)
1466 obj_priv->dirty = 0; 1466 obj_priv->dirty = 0;
1467 1467
1468 for (i = 0; i < page_count; i++) { 1468 for (i = 0; i < page_count; i++) {
1469 if (obj_priv->pages[i] == NULL)
1470 break;
1471
1472 if (obj_priv->dirty) 1469 if (obj_priv->dirty)
1473 set_page_dirty(obj_priv->pages[i]); 1470 set_page_dirty(obj_priv->pages[i]);
1474 1471
@@ -2251,7 +2248,6 @@ i915_gem_object_get_pages(struct drm_gem_object *obj,
2251 struct address_space *mapping; 2248 struct address_space *mapping;
2252 struct inode *inode; 2249 struct inode *inode;
2253 struct page *page; 2250 struct page *page;
2254 int ret;
2255 2251
2256 if (obj_priv->pages_refcount++ != 0) 2252 if (obj_priv->pages_refcount++ != 0)
2257 return 0; 2253 return 0;
@@ -2274,11 +2270,9 @@ i915_gem_object_get_pages(struct drm_gem_object *obj,
2274 mapping_gfp_mask (mapping) | 2270 mapping_gfp_mask (mapping) |
2275 __GFP_COLD | 2271 __GFP_COLD |
2276 gfpmask); 2272 gfpmask);
2277 if (IS_ERR(page)) { 2273 if (IS_ERR(page))
2278 ret = PTR_ERR(page); 2274 goto err_pages;
2279 i915_gem_object_put_pages(obj); 2275
2280 return ret;
2281 }
2282 obj_priv->pages[i] = page; 2276 obj_priv->pages[i] = page;
2283 } 2277 }
2284 2278
@@ -2286,6 +2280,15 @@ i915_gem_object_get_pages(struct drm_gem_object *obj,
2286 i915_gem_object_do_bit_17_swizzle(obj); 2280 i915_gem_object_do_bit_17_swizzle(obj);
2287 2281
2288 return 0; 2282 return 0;
2283
2284err_pages:
2285 while (i--)
2286 page_cache_release(obj_priv->pages[i]);
2287
2288 drm_free_large(obj_priv->pages);
2289 obj_priv->pages = NULL;
2290 obj_priv->pages_refcount--;
2291 return PTR_ERR(page);
2289} 2292}
2290 2293
2291static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg) 2294static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg)