aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorNitin Gupta <ngupta@vflare.org>2013-01-02 11:53:41 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-13 22:40:02 -0500
commit397c60668aa5ae7130b5ad4e73870d7b8a787085 (patch)
tree3614efa94688c19233023c49d940fe0d3c061cf3 /drivers/staging
parente16a922a27ec352537a8027cadc32dc156534ca5 (diff)
staging: zram: fix invalid memory references during disk write
Fixes a bug introduced by commit c8f2f0db1 ("zram: Fix handling of incompressible pages") which caused invalid memory references during disk write. Invalid references could occur in two cases: - Incoming data expands on compression: In this case, reference was made to kunmap()'ed bio page. - Partial (non PAGE_SIZE) write with incompressible data: In this case, reference was made to a kfree()'ed buffer. Fixes bug 50081: https://bugzilla.kernel.org/show_bug.cgi?id=50081 Signed-off-by: Nitin Gupta <ngupta@vflare.org> Cc: stable <stable@vger.kernel.org> Reported-by: Mihail Kasadjikov <hamer.mk@gmail.com> Reported-by: Tomas M <tomas@slax.org> Reviewed-by: Minchan Kim <minchan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/zram/zram_drv.c39
1 files changed, 24 insertions, 15 deletions
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index fb4a7c94aed..f2a73bd739f 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -265,7 +265,7 @@ out_cleanup:
265static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, 265static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
266 int offset) 266 int offset)
267{ 267{
268 int ret; 268 int ret = 0;
269 size_t clen; 269 size_t clen;
270 unsigned long handle; 270 unsigned long handle;
271 struct page *page; 271 struct page *page;
@@ -286,10 +286,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
286 goto out; 286 goto out;
287 } 287 }
288 ret = zram_decompress_page(zram, uncmem, index); 288 ret = zram_decompress_page(zram, uncmem, index);
289 if (ret) { 289 if (ret)
290 kfree(uncmem);
291 goto out; 290 goto out;
292 }
293 } 291 }
294 292
295 /* 293 /*
@@ -302,16 +300,18 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
302 300
303 user_mem = kmap_atomic(page); 301 user_mem = kmap_atomic(page);
304 302
305 if (is_partial_io(bvec)) 303 if (is_partial_io(bvec)) {
306 memcpy(uncmem + offset, user_mem + bvec->bv_offset, 304 memcpy(uncmem + offset, user_mem + bvec->bv_offset,
307 bvec->bv_len); 305 bvec->bv_len);
308 else 306 kunmap_atomic(user_mem);
307 user_mem = NULL;
308 } else {
309 uncmem = user_mem; 309 uncmem = user_mem;
310 }
310 311
311 if (page_zero_filled(uncmem)) { 312 if (page_zero_filled(uncmem)) {
312 kunmap_atomic(user_mem); 313 if (!is_partial_io(bvec))
313 if (is_partial_io(bvec)) 314 kunmap_atomic(user_mem);
314 kfree(uncmem);
315 zram_stat_inc(&zram->stats.pages_zero); 315 zram_stat_inc(&zram->stats.pages_zero);
316 zram_set_flag(zram, index, ZRAM_ZERO); 316 zram_set_flag(zram, index, ZRAM_ZERO);
317 ret = 0; 317 ret = 0;
@@ -321,9 +321,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
321 ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen, 321 ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
322 zram->compress_workmem); 322 zram->compress_workmem);
323 323
324 kunmap_atomic(user_mem); 324 if (!is_partial_io(bvec)) {
325 if (is_partial_io(bvec)) 325 kunmap_atomic(user_mem);
326 kfree(uncmem); 326 user_mem = NULL;
327 uncmem = NULL;
328 }
327 329
328 if (unlikely(ret != LZO_E_OK)) { 330 if (unlikely(ret != LZO_E_OK)) {
329 pr_err("Compression failed! err=%d\n", ret); 331 pr_err("Compression failed! err=%d\n", ret);
@@ -332,8 +334,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
332 334
333 if (unlikely(clen > max_zpage_size)) { 335 if (unlikely(clen > max_zpage_size)) {
334 zram_stat_inc(&zram->stats.bad_compress); 336 zram_stat_inc(&zram->stats.bad_compress);
335 src = uncmem;
336 clen = PAGE_SIZE; 337 clen = PAGE_SIZE;
338 src = NULL;
339 if (is_partial_io(bvec))
340 src = uncmem;
337 } 341 }
338 342
339 handle = zs_malloc(zram->mem_pool, clen); 343 handle = zs_malloc(zram->mem_pool, clen);
@@ -345,7 +349,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
345 } 349 }
346 cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO); 350 cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO);
347 351
352 if ((clen == PAGE_SIZE) && !is_partial_io(bvec))
353 src = kmap_atomic(page);
348 memcpy(cmem, src, clen); 354 memcpy(cmem, src, clen);
355 if ((clen == PAGE_SIZE) && !is_partial_io(bvec))
356 kunmap_atomic(src);
349 357
350 zs_unmap_object(zram->mem_pool, handle); 358 zs_unmap_object(zram->mem_pool, handle);
351 359
@@ -358,9 +366,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
358 if (clen <= PAGE_SIZE / 2) 366 if (clen <= PAGE_SIZE / 2)
359 zram_stat_inc(&zram->stats.good_compress); 367 zram_stat_inc(&zram->stats.good_compress);
360 368
361 return 0;
362
363out: 369out:
370 if (is_partial_io(bvec))
371 kfree(uncmem);
372
364 if (ret) 373 if (ret)
365 zram_stat64_inc(zram, &zram->stats.failed_writes); 374 zram_stat64_inc(zram, &zram->stats.failed_writes);
366 return ret; 375 return ret;