diff options
| author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-03-12 14:52:55 -0500 |
|---|---|---|
| committer | Eric Anholt <eric@anholt.net> | 2010-03-17 16:17:24 -0400 |
| commit | 1f2b10131f83f7caa67bf1273cec126b4283015d (patch) | |
| tree | d1e447b0d39a04c065f7878603b9e66444a0b69f | |
| parent | 59f2d0fc4bdfbbfabfa3715ba17d0609e5964c7e (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.c | 21 |
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 | |||
| 2284 | err_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 | ||
| 2291 | static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg) | 2294 | static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg) |
