Message ID | 20171208133823.18790-2-kleber.souza@canonical.com |
---|---|
State | New |
Headers | show |
Series | Fix for CVE-2017-12190 | expand |
On 08.12.2017 13:38, Kleber Sacilotto de Souza wrote: > From: Al Viro <viro@zeniv.linux.org.uk> > > 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. > > Cc: stable@vger.kernel.org > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> > > CVE-CVE-2017-12190 > (backported from commit 2b04e8f6bbb196cab4b232af0f8d48ff2c7a8058) > [klebers: page_cache_release() is defined as put_page(), but keep it as > page_cache_release() for consistency with the rest of the code.] > Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> Acked-by: Stefan Bader <stefan.bader@canonical.com> > --- Same provisional ack in case both functions are the same. > block/bio.c | 14 +++++++++----- > 1 file changed, 9 insertions(+), 5 deletions(-) > > diff --git a/block/bio.c b/block/bio.c > index 68bbc835bacc..6750552d6b16 100644 > --- a/block/bio.c > +++ b/block/bio.c > @@ -1268,6 +1268,7 @@ struct bio *bio_map_user_iov(struct request_queue *q, > int ret, offset; > struct iov_iter i; > struct iovec iov; > + struct bio_vec *bvec; > > iov_for_each(iov, i, *iter) { > unsigned long uaddr = (unsigned long) iov.iov_base; > @@ -1312,7 +1313,12 @@ struct bio *bio_map_user_iov(struct request_queue *q, > ret = get_user_pages_fast(uaddr, local_nr_pages, > (iter->type & WRITE) != WRITE, > &pages[cur_page]); > - if (ret < local_nr_pages) { > + if (unlikely(ret < local_nr_pages)) { > + for (j = cur_page; j < page_limit; j++) { > + if (!pages[j]) > + break; > + put_page(pages[j]); > + } > ret = -EFAULT; > goto out_unmap; > } > @@ -1374,10 +1380,8 @@ struct bio *bio_map_user_iov(struct request_queue *q, > return bio; > > out_unmap: > - for (j = 0; j < nr_pages; j++) { > - if (!pages[j]) > - break; > - page_cache_release(pages[j]); > + bio_for_each_segment_all(bvec, bio, j) { > + page_cache_release(bvec->bv_page); > } > out: > kfree(pages); >
Acked-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
Applied to xenial master-next branch. Thanks. Cascardo. Applied-to: xenial/master-next
Applied to zesty master-next branch. Thanks. Cascardo. Applied-to: zesty/master-next
diff --git a/block/bio.c b/block/bio.c index 68bbc835bacc..6750552d6b16 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1268,6 +1268,7 @@ struct bio *bio_map_user_iov(struct request_queue *q, int ret, offset; struct iov_iter i; struct iovec iov; + struct bio_vec *bvec; iov_for_each(iov, i, *iter) { unsigned long uaddr = (unsigned long) iov.iov_base; @@ -1312,7 +1313,12 @@ struct bio *bio_map_user_iov(struct request_queue *q, ret = get_user_pages_fast(uaddr, local_nr_pages, (iter->type & WRITE) != WRITE, &pages[cur_page]); - if (ret < local_nr_pages) { + if (unlikely(ret < local_nr_pages)) { + for (j = cur_page; j < page_limit; j++) { + if (!pages[j]) + break; + put_page(pages[j]); + } ret = -EFAULT; goto out_unmap; } @@ -1374,10 +1380,8 @@ struct bio *bio_map_user_iov(struct request_queue *q, return bio; out_unmap: - for (j = 0; j < nr_pages; j++) { - if (!pages[j]) - break; - page_cache_release(pages[j]); + bio_for_each_segment_all(bvec, bio, j) { + page_cache_release(bvec->bv_page); } out: kfree(pages);