diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 171985dcb19..e31e6289987 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -2790,27 +2790,33 @@ vn_copy_file_range(struct vnode *invp, off_t *inoffp, struct vnode *outvp, { int error; size_t len; - uint64_t uvalin, uvalout; + uint64_t uval; len = *lenp; *lenp = 0; /* For error returns. */ error = 0; /* Do some sanity checks on the arguments. */ - uvalin = *inoffp; - uvalin += len; - uvalout = *outoffp; - uvalout += len; if (invp->v_type == VDIR || outvp->v_type == VDIR) error = EISDIR; - else if (*inoffp < 0 || uvalin > INT64_MAX || uvalin < - (uint64_t)*inoffp || *outoffp < 0 || uvalout > INT64_MAX || - uvalout < (uint64_t)*outoffp || invp->v_type != VREG || - outvp->v_type != VREG) + else if (*inoffp < 0 || *outoffp < 0 || + invp->v_type != VREG || outvp->v_type != VREG) error = EINVAL; if (error != 0) goto out; + /* Ensure offset + len does not wrap around. */ + uval = *inoffp; + uval += len; + if (uval > INT64_MAX) + len = INT64_MAX - *inoffp; + uval = *outoffp; + uval += len; + if (uval > INT64_MAX) + len = INT64_MAX - *outoffp; + if (len == 0) + goto out; + /* * If the two vnode are for the same file system, call * VOP_COPY_FILE_RANGE(), otherwise call vn_generic_copy_file_range()