From 36d5d901ac42f22136ea70180a000225456127ed Mon Sep 17 00:00:00 2001 From: kettenis Date: Thu, 8 May 2014 20:08:50 +0000 Subject: [PATCH] Fix some potential integer overflows caused by converting a page number into an offset/size/address by shifting by PAGE_SHIFT. Make uvm_objwrire/unwire use voff_t instead of off_t. The former is the right type here even if it is equivalent to the latter. Inspired by a somewhat similar changes in Bitrig. ok deraadt@, guenther@ --- sys/uvm/uvm_aobj.c | 15 ++++++++------- sys/uvm/uvm_fault.c | 8 ++++---- sys/uvm/uvm_object.c | 12 ++++++------ sys/uvm/uvm_object.h | 6 +++--- sys/uvm/uvm_pager.c | 7 ++++--- sys/uvm/uvm_swap.c | 4 ++-- sys/uvm/uvm_vnode.c | 6 +++--- 7 files changed, 30 insertions(+), 28 deletions(-) diff --git a/sys/uvm/uvm_aobj.c b/sys/uvm/uvm_aobj.c index 173d469f584..153ca4d4716 100644 --- a/sys/uvm/uvm_aobj.c +++ b/sys/uvm/uvm_aobj.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_aobj.c,v 1.63 2014/04/30 19:25:14 kettenis Exp $ */ +/* $OpenBSD: uvm_aobj.c,v 1.64 2014/05/08 20:08:50 kettenis Exp $ */ /* $NetBSD: uvm_aobj.c,v 1.39 2001/02/18 21:19:08 chs Exp $ */ /* @@ -422,7 +422,8 @@ uao_shrink_flush(struct uvm_object *uobj, int startpg, int endpg) { KASSERT(startpg < endpg); KASSERT(uobj->uo_refs == 1); - uao_flush(uobj, startpg << PAGE_SHIFT, endpg << PAGE_SHIFT, PGO_FREE); + uao_flush(uobj, (voff_t)startpg << PAGE_SHIFT, + (voff_t)endpg << PAGE_SHIFT, PGO_FREE); uao_dropswap_range(uobj, startpg, endpg); } @@ -909,14 +910,14 @@ uao_flush(struct uvm_object *uobj, voff_t start, voff_t stop, int flags) if (flags & PGO_ALLPAGES) { start = 0; - stop = aobj->u_pages << PAGE_SHIFT; + stop = (voff_t)aobj->u_pages << PAGE_SHIFT; } else { start = trunc_page(start); stop = round_page(stop); - if (stop > (aobj->u_pages << PAGE_SHIFT)) { + if (stop > ((voff_t)aobj->u_pages << PAGE_SHIFT)) { printf("uao_flush: strange, got an out of range " "flush (fixed)\n"); - stop = aobj->u_pages << PAGE_SHIFT; + stop = (voff_t)aobj->u_pages << PAGE_SHIFT; } } @@ -1414,7 +1415,7 @@ uao_pagein_page(struct uvm_aobj *aobj, int pageidx) pg = NULL; npages = 1; - rv = uao_get(&aobj->u_obj, pageidx << PAGE_SHIFT, + rv = uao_get(&aobj->u_obj, (voff_t)pageidx << PAGE_SHIFT, &pg, &npages, 0, VM_PROT_READ|VM_PROT_WRITE, 0, 0); switch (rv) { @@ -1511,7 +1512,7 @@ uao_dropswap_range(struct uvm_object *uobj, voff_t start, voff_t end) int slot = elt->slots[j]; KASSERT(uvm_pagelookup(&aobj->u_obj, - (UAO_SWHASH_ELT_PAGEIDX_BASE(elt) + (voff_t)(UAO_SWHASH_ELT_PAGEIDX_BASE(elt) + j) << PAGE_SHIFT) == NULL); if (slot > 0) { diff --git a/sys/uvm/uvm_fault.c b/sys/uvm/uvm_fault.c index 98e2ad24277..d739d4fc772 100644 --- a/sys/uvm/uvm_fault.c +++ b/sys/uvm/uvm_fault.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_fault.c,v 1.72 2014/04/13 23:14:15 tedu Exp $ */ +/* $OpenBSD: uvm_fault.c,v 1.73 2014/05/08 20:08:50 kettenis Exp $ */ /* $NetBSD: uvm_fault.c,v 1.51 2000/08/06 00:22:53 thorpej Exp $ */ /* @@ -622,7 +622,7 @@ ReFault: /* wide fault (!narrow) */ nback = min(uvmadvice[ufi.entry->advice].nback, (ufi.orig_rvaddr - ufi.entry->start) >> PAGE_SHIFT); - startva = ufi.orig_rvaddr - (nback << PAGE_SHIFT); + startva = ufi.orig_rvaddr - ((vsize_t)nback << PAGE_SHIFT); nforw = min(uvmadvice[ufi.entry->advice].nforw, ((ufi.entry->end - ufi.orig_rvaddr) >> PAGE_SHIFT) - 1); @@ -664,13 +664,13 @@ ReFault: if (uobj) { uoff = (startva - ufi.entry->start) + ufi.entry->offset; (void) uobj->pgops->pgo_flush(uobj, uoff, uoff + - (nback << PAGE_SHIFT), PGO_DEACTIVATE); + ((vsize_t)nback << PAGE_SHIFT), PGO_DEACTIVATE); } /* now forget about the backpages */ if (amap) anons += nback; - startva += (nback << PAGE_SHIFT); + startva += ((vsize_t)nback << PAGE_SHIFT); npages -= nback; centeridx = 0; } diff --git a/sys/uvm/uvm_object.c b/sys/uvm/uvm_object.c index e6844f08c52..06ca765ca40 100644 --- a/sys/uvm/uvm_object.c +++ b/sys/uvm/uvm_object.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_object.c,v 1.7 2013/05/30 15:17:59 tedu Exp $ */ +/* $OpenBSD: uvm_object.c,v 1.8 2014/05/08 20:08:50 kettenis Exp $ */ /* * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -64,12 +64,12 @@ uvm_objinit(struct uvm_object *uobj, struct uvm_pagerops *pgops, int refs) */ int -uvm_objwire(struct uvm_object *uobj, off_t start, off_t end, +uvm_objwire(struct uvm_object *uobj, voff_t start, voff_t end, struct pglist *pageq) { - int i, npages, error; + int i, npages, left, error; struct vm_page *pgs[FETCH_PAGECOUNT]; - off_t offset = start, left; + voff_t offset = start; left = (end - start) >> PAGE_SHIFT; @@ -127,7 +127,7 @@ uvm_objwire(struct uvm_object *uobj, off_t start, off_t end, uvm_page_unbusy(pgs, npages); left -= npages; - offset += npages << PAGE_SHIFT; + offset += (voff_t)npages << PAGE_SHIFT; } return 0; @@ -146,7 +146,7 @@ error: */ void -uvm_objunwire(struct uvm_object *uobj, off_t start, off_t end) +uvm_objunwire(struct uvm_object *uobj, voff_t start, voff_t end) { struct vm_page *pg; off_t offset; diff --git a/sys/uvm/uvm_object.h b/sys/uvm/uvm_object.h index 83085701bdb..4b37af15e65 100644 --- a/sys/uvm/uvm_object.h +++ b/sys/uvm/uvm_object.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_object.h,v 1.19 2013/05/30 15:17:59 tedu Exp $ */ +/* $OpenBSD: uvm_object.h,v 1.20 2014/05/08 20:08:50 kettenis Exp $ */ /* $NetBSD: uvm_object.h,v 1.11 2001/03/09 01:02:12 chs Exp $ */ /* @@ -97,8 +97,8 @@ RB_PROTOTYPE(uvm_objtree, vm_page, objt, uvm_pagecmp) ((struct vnode *)uobj)->v_flag & VTEXT) void uvm_objinit(struct uvm_object *, struct uvm_pagerops *, int); -int uvm_objwire(struct uvm_object *, off_t, off_t, struct pglist *); -void uvm_objunwire(struct uvm_object *, off_t, off_t); +int uvm_objwire(struct uvm_object *, voff_t, voff_t, struct pglist *); +void uvm_objunwire(struct uvm_object *, voff_t, voff_t); #endif /* _KERNEL */ diff --git a/sys/uvm/uvm_pager.c b/sys/uvm/uvm_pager.c index 4e4918fd0e7..23b7f15d2bd 100644 --- a/sys/uvm/uvm_pager.c +++ b/sys/uvm/uvm_pager.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_pager.c,v 1.65 2014/04/13 23:14:15 tedu Exp $ */ +/* $OpenBSD: uvm_pager.c,v 1.66 2014/05/08 20:08:50 kettenis Exp $ */ /* $NetBSD: uvm_pager.c,v 1.36 2000/11/27 18:26:41 chs Exp $ */ /* @@ -278,7 +278,7 @@ void uvm_pagermapout(vaddr_t kva, int npages) { - pmap_remove(pmap_kernel(), kva, kva + (npages << PAGE_SHIFT)); + pmap_remove(pmap_kernel(), kva, kva + ((vsize_t)npages << PAGE_SHIFT)); pmap_update(pmap_kernel()); uvm_pseg_release(kva); @@ -724,7 +724,8 @@ uvm_aio_aiodone(struct buf *bp) uobj = NULL; for (i = 0; i < npages; i++) - pgs[i] = uvm_atopg((vaddr_t)bp->b_data + (i << PAGE_SHIFT)); + pgs[i] = uvm_atopg((vaddr_t)bp->b_data + + ((vsize_t)i << PAGE_SHIFT)); uvm_pagermapout((vaddr_t)bp->b_data, npages); #ifdef UVM_SWAP_ENCRYPT /* diff --git a/sys/uvm/uvm_swap.c b/sys/uvm/uvm_swap.c index 6f9b404e781..9929b576f3a 100644 --- a/sys/uvm/uvm_swap.c +++ b/sys/uvm/uvm_swap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_swap.c,v 1.126 2014/04/29 09:55:28 kettenis Exp $ */ +/* $OpenBSD: uvm_swap.c,v 1.127 2014/05/08 20:08:50 kettenis Exp $ */ /* $NetBSD: uvm_swap.c,v 1.40 2000/11/17 11:39:39 mrg Exp $ */ /* @@ -1780,7 +1780,7 @@ uvm_swap_io(struct vm_page **pps, int startslot, int npages, int flags) bp->b_vp = NULL; buf_replacevnode(bp, swapdev_vp); splx(s); - bp->b_bufsize = bp->b_bcount = npages << PAGE_SHIFT; + bp->b_bufsize = bp->b_bcount = (long)npages << PAGE_SHIFT; /* * for pageouts we must set "dirtyoff" [NFS client code needs it]. diff --git a/sys/uvm/uvm_vnode.c b/sys/uvm/uvm_vnode.c index a67c01e5295..4105d87c997 100644 --- a/sys/uvm/uvm_vnode.c +++ b/sys/uvm/uvm_vnode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_vnode.c,v 1.81 2014/04/13 23:14:15 tedu Exp $ */ +/* $OpenBSD: uvm_vnode.c,v 1.82 2014/05/08 20:08:50 kettenis Exp $ */ /* $NetBSD: uvm_vnode.c,v 1.36 2000/11/24 20:34:01 chs Exp $ */ /* @@ -1159,7 +1159,7 @@ uvn_io(struct uvm_vnode *uvn, vm_page_t *pps, int npages, int flags, int rw) */ /* fill out uio/iov */ iov.iov_base = (caddr_t) kva; - wanted = npages << PAGE_SHIFT; + wanted = (size_t)npages << PAGE_SHIFT; if (file_offset + wanted > uvn->u_size) wanted = uvn->u_size - file_offset; /* XXX: needed? */ iov.iov_len = wanted; @@ -1211,7 +1211,7 @@ uvn_io(struct uvm_vnode *uvn, vm_page_t *pps, int npages, int flags, int rw) result = EIO; /* XXX: error? */ } else if (got < PAGE_SIZE * npages && rw == UIO_READ) { memset((void *) (kva + got), 0, - (npages << PAGE_SHIFT) - got); + ((size_t)npages << PAGE_SHIFT) - got); } } -- 2.20.1