Commit e67dfe75b6830279ef24bfa5237c1488e2890a8d
Committed by
Greg Kroah-Hartman
1 parent
5444d8ab9a
more bio_map_user_iov() leak fixes
commit 2b04e8f6bbb196cab4b232af0f8d48ff2c7a8058 upstream. we need to take care of failure exit as well - pages already in bio should be dropped by analogue of bio_unmap_pages(), since their refcounts had been bumped only once per reference in bio. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 9 additions and 5 deletions Side-by-side Diff
block/bio.c
... | ... | @@ -1266,6 +1266,7 @@ |
1266 | 1266 | int ret, offset; |
1267 | 1267 | struct iov_iter i; |
1268 | 1268 | struct iovec iov; |
1269 | + struct bio_vec *bvec; | |
1269 | 1270 | |
1270 | 1271 | iov_for_each(iov, i, *iter) { |
1271 | 1272 | unsigned long uaddr = (unsigned long) iov.iov_base; |
... | ... | @@ -1310,7 +1311,12 @@ |
1310 | 1311 | ret = get_user_pages_fast(uaddr, local_nr_pages, |
1311 | 1312 | (iter->type & WRITE) != WRITE, |
1312 | 1313 | &pages[cur_page]); |
1313 | - if (ret < local_nr_pages) { | |
1314 | + if (unlikely(ret < local_nr_pages)) { | |
1315 | + for (j = cur_page; j < page_limit; j++) { | |
1316 | + if (!pages[j]) | |
1317 | + break; | |
1318 | + put_page(pages[j]); | |
1319 | + } | |
1314 | 1320 | ret = -EFAULT; |
1315 | 1321 | goto out_unmap; |
1316 | 1322 | } |
... | ... | @@ -1372,10 +1378,8 @@ |
1372 | 1378 | return bio; |
1373 | 1379 | |
1374 | 1380 | out_unmap: |
1375 | - for (j = 0; j < nr_pages; j++) { | |
1376 | - if (!pages[j]) | |
1377 | - break; | |
1378 | - put_page(pages[j]); | |
1381 | + bio_for_each_segment_all(bvec, bio, j) { | |
1382 | + put_page(bvec->bv_page); | |
1379 | 1383 | } |
1380 | 1384 | out: |
1381 | 1385 | kfree(pages); |