mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-22 20:21:05 +01:00
vfs_vnops.c: Fix vn_generic_copy_file_range() for truncation
When copy_file_range(2) was first being developed, *inoffp + len had to be <= infile_size or an error was returned. This semantic (as defined by Linux) changed to allow *inoffp + len to be greater than infile_size and the copy would end at *inoffp + infile_size. Unfortunately, the code that decided if the outfd should be truncated in length did not get updated for this semantics change. As such, if a copy_file_range(2) is done, where infile_size - *inoffp is less that outfile_size but len is large, the outfd file is truncated when it should not be. (The semantics for this for Linux is to not truncate outfd in this case.) This patch fixes the problem. I believe the calculation is safe for all non-negative values of outsize, *outoffp, *inoffp and insize, which should be ok, since they are all guaranteed to be non-negative. Note that this bug is not observed over NFSv4.2, since it truncates len to infile_size - *inoffp. PR: 276045 Reviewed by: asomers, kib MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D43258
This commit is contained in:
parent
38c63bdc46
commit
2319ca6a01
@ -3361,8 +3361,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
|
||||
goto out;
|
||||
if (VOP_PATHCONF(invp, _PC_MIN_HOLE_SIZE, &holein) != 0)
|
||||
holein = 0;
|
||||
if (holein > 0)
|
||||
error = vn_getsize_locked(invp, &insize, incred);
|
||||
error = vn_getsize_locked(invp, &insize, incred);
|
||||
VOP_UNLOCK(invp);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
@ -3398,7 +3397,11 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
|
||||
*/
|
||||
if (error == 0)
|
||||
error = vn_getsize_locked(outvp, &outsize, outcred);
|
||||
if (error == 0 && outsize > *outoffp && outsize <= *outoffp + len) {
|
||||
if (error == 0 && outsize > *outoffp &&
|
||||
*outoffp <= OFF_MAX - len && outsize <= *outoffp + len &&
|
||||
*inoffp < insize &&
|
||||
*outoffp <= OFF_MAX - (insize - *inoffp) &&
|
||||
outsize <= *outoffp + (insize - *inoffp)) {
|
||||
#ifdef MAC
|
||||
error = mac_vnode_check_write(curthread->td_ucred,
|
||||
outcred, outvp);
|
||||
|
Loading…
Reference in New Issue
Block a user