]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_io: fix mread with length 1 mod page size
authorEric Biggers <ebiggers@google.com>
Tue, 11 Jun 2024 18:29:28 +0000 (11:29 -0700)
committerCarlos Maiolino <cem@kernel.org>
Mon, 17 Jun 2024 11:50:56 +0000 (13:50 +0200)
Fix a weird bug in mread where if you passed it a length that was 1
modulo the page size, for example

        xfs_io -r file -c "mmap -r 0 8192" -c "mread -v 0 4097"

... it never reset its pointer into the buffer into which it copies the
data from the memory map.  This caused an out-of-bounds write, which
depending on the length passed could be very large and reliably
segfault.  Also nothing was printed, despite the use of -v option.

(I don't know if this case gets reached by any existing xfstest, but
presumably not.  I noticed it while working on a patch to an xfstest.)

Signed-off-by: Eric Biggers <ebiggers@google.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
io/mmap.c

index 85087f5702ad96ccdc54d39ce6e66c541bde2fec..4c03e3d57df5c62eb5776d7f14d290738390233b 100644 (file)
--- a/io/mmap.c
+++ b/io/mmap.c
@@ -471,34 +471,26 @@ mread_f(
                dumplen = pagesize;
 
        if (rflag) {
-               for (tmp = length - 1, c = 0; tmp >= 0; tmp--, c = 1) {
-                       *bp = *(((char *)mapping->addr) + dumpoffset + tmp);
-                       cnt++;
-                       if (c && cnt == dumplen) {
+               for (tmp = length - 1; tmp >= 0; tmp--) {
+                       bp[cnt++] = ((char *)mapping->addr)[dumpoffset + tmp];
+                       if (cnt == dumplen) {
                                if (dump) {
                                        dump_buffer(printoffset, dumplen);
                                        printoffset += dumplen;
                                }
-                               bp = (char *)io_buffer;
                                dumplen = pagesize;
                                cnt = 0;
-                       } else {
-                               bp++;
                        }
                }
        } else {
-               for (tmp = 0, c = 0; tmp < length; tmp++, c = 1) {
-                       *bp = *(((char *)mapping->addr) + dumpoffset + tmp);
-                       cnt++;
-                       if (c && cnt == dumplen) {
+               for (tmp = 0; tmp < length; tmp++) {
+                       bp[cnt++] = ((char *)mapping->addr)[dumpoffset + tmp];
+                       if (cnt == dumplen) {
                                if (dump)
                                        dump_buffer(printoffset + tmp -
                                                (dumplen - 1), dumplen);
-                               bp = (char *)io_buffer;
                                dumplen = pagesize;
                                cnt = 0;
-                       } else {
-                               bp++;
                        }
                }
        }