Commit e67dfe75b6830279ef24bfa5237c1488e2890a8d

Authored by Al Viro
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

... ... @@ -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);