mirror of
https://github.com/S3NEO/android_kernel_samsung_msm8226.git
synced 2024-09-21 20:11:08 +00:00
bio: take care not overflow page count when mapping/copying user data
If the iovec is being set up in a way that causes uaddr + PAGE_SIZE to overflow, we could end up attempting to map a huge number of pages. Check for this invalid input type. Reported-by: Dan Rosenberg <drosenberg@vsecurity.com> Cc: stable@kernel.org Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
This commit is contained in:
parent
f3f63c1c28
commit
cb4644cac4
1 changed files with 13 additions and 1 deletions
14
fs/bio.c
14
fs/bio.c
|
@ -834,6 +834,12 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
|
||||||
end = (uaddr + iov[i].iov_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
end = (uaddr + iov[i].iov_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||||
start = uaddr >> PAGE_SHIFT;
|
start = uaddr >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overflow, abort
|
||||||
|
*/
|
||||||
|
if (end < start)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
nr_pages += end - start;
|
nr_pages += end - start;
|
||||||
len += iov[i].iov_len;
|
len += iov[i].iov_len;
|
||||||
}
|
}
|
||||||
|
@ -962,6 +968,12 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
|
||||||
unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||||
unsigned long start = uaddr >> PAGE_SHIFT;
|
unsigned long start = uaddr >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overflow, abort
|
||||||
|
*/
|
||||||
|
if (end < start)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
nr_pages += end - start;
|
nr_pages += end - start;
|
||||||
/*
|
/*
|
||||||
* buffer must be aligned to at least hardsector size for now
|
* buffer must be aligned to at least hardsector size for now
|
||||||
|
@ -989,7 +1001,7 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
|
||||||
unsigned long start = uaddr >> PAGE_SHIFT;
|
unsigned long start = uaddr >> PAGE_SHIFT;
|
||||||
const int local_nr_pages = end - start;
|
const int local_nr_pages = end - start;
|
||||||
const int page_limit = cur_page + local_nr_pages;
|
const int page_limit = cur_page + local_nr_pages;
|
||||||
|
|
||||||
ret = get_user_pages_fast(uaddr, local_nr_pages,
|
ret = get_user_pages_fast(uaddr, local_nr_pages,
|
||||||
write_to_vm, &pages[cur_page]);
|
write_to_vm, &pages[cur_page]);
|
||||||
if (ret < local_nr_pages) {
|
if (ret < local_nr_pages) {
|
||||||
|
|
Loading…
Reference in a new issue