On 2025-12-22 17:28, Matteo Croce wrote:
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
Oh, I might be mistaken here. I was looking at my experimental copy of
coreutils, which has some changes/fixes in this area.
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 +++
Those particular copy_file_range calls don't tickle the kernel bug, as
the files are at offset 0. But you're right, you can probably tickle the
kernel bug in other uses.
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?
No, but that's understandable as my patch was hopelessly munged. You can
try the attached instead. (Notice that it does not fail with EOVERFLOW;
either the requested area is valid or it's not.)diff --git a/fs/read_write.c b/fs/read_write.c
index 833bae068770..322a87117455 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -459,13 +459,14 @@ int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t
if (ppos) {
loff_t pos = *ppos;
- if (unlikely(pos < 0)) {
- if (!unsigned_offsets(file))
+ if (unsigned_offsets(file)) {
+ if (check_add_overflow ((uoff_t) pos, count,
+ &(uoff_t) {0}))
return -EINVAL;
- if (count >= -pos) /* both values are in 0..LLONG_MAX */
- return -EOVERFLOW;
- } else if (unlikely((loff_t) (pos + count) < 0)) {
- if (!unsigned_offsets(file))
+ } else {
+ if (unlikely(pos < 0))
+ return -EINVAL;
+ if (check_add_overflow (pos, count, &(loff_t) {0}))
return -EINVAL;
}
}