Il giorno lun 22 dic 2025 alle ore 19:41 Paul Eggert
<[email protected]> ha scritto:
>
> [cc'ing [email protected]; this coreutils thread can be
> found in <https://lists.gnu.org/r/coreutils/2025-12/threads.html#00055>.]
>
> On 2025-12-20 00:51, Matteo Croce wrote:
> > This can be triggered with a huge file:
> >
> > $ truncate -s $((2**63 - 1)) file1
> >
> > $ ( dd bs=1M skip=$((2**43 - 2)) count=0 && cat ) < file1
> > 0+0 records in
> > 0+0 records out
> > 0 bytes copied, 2,825e-05 s, 0,0 kB/s
> > cat: -: Invalid argument
> >
> > $ dd if=file1 bs=1M skip=$((2**43 - 2))
> > dd: error reading 'file1': Invalid argument
> > 1+0 records in
> > 1+0 records out
> > 1048576 bytes (1,0 MB, 1,0 MiB) copied, 0,103536 s, 10,1 MB/s
>
> OK, but in bleeding-edge coreutils neither of these examples call
> copy_file_range. The diagnostics result from plain 'read' syscalls near
> TYPE_MAXIMUM (off_t). (dd never calls copy_file_range, and ironically
> the code in 'cat' that does call copy_file_range avoids the overflow
> itself, before invoking copy_file_range, and relies on plain 'read' to
> do the right thing near TYPE_MAXIMUM (off_t).) So these examples have
> nothing to do with copy_file_range.
>

Yes I know that copy_file_range is unrelated, my commands are just a
simple reproducers for the kernel issue.
Where in cat.c the code avoids the overflow? I see:

ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30;

which should evaluate to 0x7FFFFFFFC0000000
also strace says:

$ strace -e copy_file_range cat /etc/fstab >fstab
copy_file_range(3, NULL, 1, NULL, 9223372035781033984, 0) = 568
copy_file_range(3, NULL, 1, NULL, 9223372035781033984, 0) = 0
+++ exited with 0 +++

> You've found a Linux kernel bug that affects countless apps, and we
> can't reasonably expect app developers to patch all the apps to work
> around the bug. So the fix should be done in the kernel.
>
> I looked at the kernel patch you suggested in
> <https://lore.kernel.org/linux-fsdevel/[email protected]/T/>.
> Unfortunately, I see two problems with it, the first minor, the second
> less so.
>
> The minor problem is that the unpatched kernel code is merely
> incorrectly checking whether pos + count fits into loff_t. MAX_RW_COUNT
> should not be involved with the fix, as MAX_RW_COUNT is irrelevant to
> file offset range. Better would be to do correct overflow checks, with
> something like the attached patch (which I have not compiled or tested).
>
> Second and more important, the patch doesn't fix the real bug which is
> that read(FD, BUF, SIZE) fails with -EINVAL if adding SIZE to the
> current file position would overflow off_t. That's wrong: the syscall
> should read whatever bytes are present (up to EOF), and then report the
> number of bytes read. We cannot fix this bug merely via something like
> the attached patch.
>
> One possible fix for the second problem would be to change
> rw_verify_area's API to return the possibly-smaller number of bytes that
> can be read, and then modify its callers to do the right thing.
> ("correct" in the sense of "don't try to read past TYPE_MAXIMUM
> (off_t)".) Alternatively, we could fix rw_verify_area's callers to not
> try to read past TYPE_MAXIMUM (off_t), without changing the API.

Yes, the kernel bug has to be fixed, of course.
Your patch doesn't compile due to an unmatched curly brace, I fixed it
but it panics at boot, can you check if I preserved the correct logic?

Regards,
-- 
Matteo Croce

perl -e 'for($t=0;;$t++){print chr($t*($t>>8|$t>>13)&255)}' |aplay

Attachment: rw_verify_area-overflow.diff
Description: Binary data

Reply via email to