git: b487aca48535 - main - vfs: Avoid integer overflow when faulting
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 01 Nov 2026 20:25:37 UTC
The branch main has been updated by des:
URL: https://cgit.FreeBSD.org/src/commit/?id=b487aca48535e5f04e4913447fcbe33f1bf56c68
commit b487aca48535e5f04e4913447fcbe33f1bf56c68
Author: Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-11-01 20:09:50 +0000
Commit: Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-11-01 20:09:50 +0000
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
---
sys/kern/vfs_vnops.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 96b1c5696251..0bb8bfffec85 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -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);
}