vfs: Avoid integer overflow when faulting

In vn_io_fault1(), the read / write length can easily exceed INT_MAX.
Passing it directly to uiomove(), which expects an int, results in a
negative uio_resid, which to the caller looks like we read more than
was requested.

PR:		298159
MFC after:	1 week
Reviewed by:	olce, kib
Differential Revision:	https://reviews.freebsd.org/D59412
This commit is contained in:
Dag-Erling Smørgrav committed 2026-11-01 21:09:50 +01:00
1 parent 0a12444b29
commit b487aca485
1 file changed
+9 -3
+9 -3
View File
@@ -1531,7 +1531,7 @@ vn_io_fault1(struct vnode *vp, struct uio *uio, struct vn_io_fault_args *args,
vm_page_t *prev_td_ma;
vm_prot_t prot;
vm_offset_t addr, end;
size_t len, resid;
size_t len;
ssize_t adv;
int error, cnt, saveheld, prev_td_ma_cnt;
@@ -1553,7 +1553,6 @@ vn_io_fault1(struct vnode *vp, struct uio *uio, struct vn_io_fault_args *args,
* point using UIO_NOCOPY below.
*/
uio_clone = cloneuio(uio);
resid = uio->uio_resid;
short_uio.uio_segflg = UIO_USERSPACE;
short_uio.uio_rw = uio->uio_rw;
@@ -1563,9 +1562,15 @@ vn_io_fault1(struct vnode *vp, struct uio *uio, struct vn_io_fault_args *args,
if (error != EFAULT)
goto out;
/*
* Advance clone to the redo point.
*/
atomic_add_long(&vn_io_faults_cnt, 1);
uio_clone->uio_segflg = UIO_NOCOPY;
uiomove(NULL, resid - uio->uio_resid, uio_clone);
while (uio_clone->uio_resid > uio->uio_resid) {
len = MIN(uio_clone->uio_resid - uio->uio_resid, INT_MAX);
uiomove(NULL, len, uio_clone);
}
uio_clone->uio_segflg = uio->uio_segflg;
saveheld = curthread_pflags_set(TDP_UIOHELD);
@@ -1629,6 +1634,7 @@ vn_io_fault1(struct vnode *vp, struct uio *uio, struct vn_io_fault_args *args,
curthread_pflags_restore(saveheld);
out:
freeuio(uio_clone);
MPASS(uio->uio_resid >= 0);
return (error);
}