Unverified Commit f8f59a2c authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Christian Brauner
Browse files

copy_file_range: limit size if in compat mode



If the process runs in 32-bit compat mode, copy_file_range results can be
in the in-band error range.  In this case limit copy length to MAX_RW_COUNT
to prevent a signed overflow.

Reported-by: default avatarFlorian Weimer <fweimer@redhat.com>
Closes: https://lore.kernel.org/all/lhuh5ynl8z5.fsf@oldenburg.str.redhat.com/


Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
Link: https://lore.kernel.org/20250813151107.99856-1-mszeredi@redhat.com


Reviewed-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent 15769d94
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -1576,6 +1576,13 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
	if (len == 0)
		return 0;

	/*
	 * Make sure return value doesn't overflow in 32bit compat mode.  Also
	 * limit the size for all cases except when calling ->copy_file_range().
	 */
	if (splice || !file_out->f_op->copy_file_range || in_compat_syscall())
		len = min_t(size_t, MAX_RW_COUNT, len);

	file_start_write(file_out);

	/*
@@ -1589,9 +1596,7 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
						      len, flags);
	} else if (!splice && file_in->f_op->remap_file_range && samesb) {
		ret = file_in->f_op->remap_file_range(file_in, pos_in,
				file_out, pos_out,
				min_t(loff_t, MAX_RW_COUNT, len),
				REMAP_FILE_CAN_SHORTEN);
				file_out, pos_out, len, REMAP_FILE_CAN_SHORTEN);
		/* fallback to splice */
		if (ret <= 0)
			splice = true;
@@ -1624,8 +1629,7 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
	 * to splicing from input file, while file_start_write() is held on
	 * the output file on a different sb.
	 */
	ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out,
			       min_t(size_t, len, MAX_RW_COUNT), 0);
	ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out, len, 0);
done:
	if (ret > 0) {
		fsnotify_access(file_in);