summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-12-17 09:21:56 +0000
committerkib <kib@FreeBSD.org>2013-12-17 09:21:56 +0000
commit758e3a99342f38f2affc2019fd5b16adf0898255 (patch)
tree13e2b4c9dfb92cab18802b8ce91cef46c15fb35c /sys/kern
parente5df7f0316ab4d319ec41a8c92c42cb3e50a2543 (diff)
downloadFreeBSD-src-758e3a99342f38f2affc2019fd5b16adf0898255.zip
FreeBSD-src-758e3a99342f38f2affc2019fd5b16adf0898255.tar.gz
MFC r258039:
Avoid overflow for the page counts. MFC r258365: Revert back to use int for the page counts. Rearrange the checks to correctly handle overflowing address arithmetic.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/vfs_vnops.c19
1 files changed, 9 insertions, 10 deletions
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index b65dfc5..da4a914 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -933,7 +933,7 @@ vn_io_fault(struct file *fp, struct uio *uio, struct ucred *active_cred,
void *rl_cookie;
struct mount *mp;
vm_page_t *prev_td_ma;
- int cnt, error, save, saveheld, prev_td_ma_cnt;
+ int error, cnt, save, saveheld, prev_td_ma_cnt;
vm_offset_t addr, end;
vm_prot_t prot;
size_t len, resid;
@@ -1007,21 +1007,20 @@ vn_io_fault(struct file *fp, struct uio *uio, struct ucred *active_cred,
uio_clone->uio_iovcnt--;
continue;
}
-
- addr = (vm_offset_t)uio_clone->uio_iov->iov_base;
+ if (len > io_hold_cnt * PAGE_SIZE)
+ len = io_hold_cnt * PAGE_SIZE;
+ addr = (uintptr_t)uio_clone->uio_iov->iov_base;
end = round_page(addr + len);
- cnt = howmany(end - trunc_page(addr), PAGE_SIZE);
+ if (end < addr) {
+ error = EFAULT;
+ break;
+ }
+ cnt = atop(end - trunc_page(addr));
/*
* A perfectly misaligned address and length could cause
* both the start and the end of the chunk to use partial
* page. +2 accounts for such a situation.
*/
- if (cnt > io_hold_cnt + 2) {
- len = io_hold_cnt * PAGE_SIZE;
- KASSERT(howmany(round_page(addr + len) -
- trunc_page(addr), PAGE_SIZE) <= io_hold_cnt + 2,
- ("cnt overflow"));
- }
cnt = vm_fault_quick_hold_pages(&td->td_proc->p_vmspace->vm_map,
addr, len, prot, ma, io_hold_cnt + 2);
if (cnt == -1) {
OpenPOWER on IntegriCloud