Make copy_file_range(2) Linux compatible for overflow of offset + len.
Without this patch, if a call to copy_file_range(2) specifies an input file offset + len that would wrap around, EINVAL is returned. I thought that was the Linux behaviour, but recent testing showed that Linux accepts this case and does the copy_file_range() to EOF. This patch changes the FreeBSD code to exhibit the same behaviour as Linux for this case. Reviewed by: asomers, kib Differential Revision: https://reviews.freebsd.org/D26569
This commit is contained in:
parent
6b70483040
commit
82f487005c
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user