Page MenuHomeFreeBSD

fix copy_file_range(2) so that it handles the case where input offset + len would wrap around

Authored by rmacklem on Mon, Sep 28, 1:19 AM.



Without this patch, if a call to copy_file_range(2) specifies an input file
outset + 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.

Test Plan

Tested with a little file copy program and a patched variant
of "cp", where the len argument for copy_file_range() is

Diff Detail

rS FreeBSD src repository
Automatic diff as part of commit; lint not applicable.
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

asomers requested changes to this revision.Mon, Sep 28, 4:17 AM
asomers added inline comments.
2808 ↗(On Diff #77581)

Why do you still return EINVAL if the output offset + len would wrap around? I would think that the common case would be copy_file_range(infd, some_potentially_nonzero_offset, outfd, some_potentially_nonzero_offset, SIZE_MAX, 0) to copy to the EOF of the input file. In that case, you should allow outoffp to wrap, too.

This revision now requires changes to proceed.Mon, Sep 28, 4:17 AM
2808 ↗(On Diff #77581)

If outoffp wraps around it goes negative.
I can't see VOP_WRITE() with a negative
file offset being a good idea.
I agree that, usually, the copy will end before
the wrap around happens (is there a real file
system that can handle a sparse file of size
INT64_MAX?), but I think a wraparound is

Change handling of a wrap around of *outoffp + len
to clip "len" instead of return EINVAL.

rmacklem added inline comments.
2808 ↗(On Diff #77601)

Although allowing it to wrap around doesn't
seem like a good idea, doing a further clip
of "len" seems ok.
This will allow SSIZE_MAX to be used for
"copy to EOF" when the output offset > input offset.

Add a check for len being clipped down to 0.
No sense in doing the VOP call for this case.

2806 ↗(On Diff #77604)

What if uval + len overflow so that the sum is less then either of addends ?

2806 ↗(On Diff #77604)

I don't think this can happen.
*inoffp is off_t (signed 64bit) and has been already checked
for non-negative, so it must be <= INT64_MAX.
len has been clipped to SSIZE_MAX, so it can't be
greater than INT64_MAX.
--> The sum of these can't exceed UINT64_MAX.
Sound right?

Treating overflow of inoffp and outoffp identically makes sense to me.

This revision is now accepted and ready to land.Tue, Sep 29, 1:06 AM