Whamcloud - gitweb
libextr2fs: handle short reads/writes while creating the qcow file
authorTheodore Ts'o <tytso@mit.edu>
Thu, 25 Apr 2024 21:52:05 +0000 (17:52 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 25 Apr 2024 21:52:05 +0000 (17:52 -0400)
This issue was flagged by Coverity, although its analysis was
incorrect.  This isn't actually a memory overrun / security issue, but
rather a functional correctness issue since POSIX allows reads and
writes to be partially completed, and in those cases qcow2_copy_data()
could result in a corrutped qcow2 file.

Addresses-Coverity-Bug: 1531830
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
lib/ext2fs/qcow2.c

index 2082417..8f96eee 100644 (file)
@@ -134,7 +134,9 @@ static int qcow2_read_l2_table(struct ext2_qcow2_image *img,
 static int qcow2_copy_data(int fdin, int fdout, __u64 off_in,
                           __u64 off_out, void *buf, size_t count)
 {
-       size_t size;
+       ssize_t c1, c2, c;
+       void *ptr;
+       int retries = 10;
 
        assert(buf);
 
@@ -144,14 +146,24 @@ static int qcow2_copy_data(int fdin, int fdout, __u64 off_in,
        if (ext2fs_llseek(fdin, off_in, SEEK_SET) < 0)
                return errno;
 
-       size = read(fdin, buf, count);
-       if (size != count)
-               return errno;
-
-       size = write(fdout, buf, count);
-       if (size != count)
-               return errno;
-
+       while (count > 0) {
+               errno = 0;
+               c1 = read(fdin, buf, count);
+               if (c1 < 0 || ((c1 == 0) && errno))
+                       return errno;
+               if (c1 == 0)
+                       break;  /* EOF */
+
+               for (ptr = buf, c = c1; c > 0; ptr += c2, c -= c2) {
+                       errno = 0;
+                       c2 = write(fdout, ptr, c1);
+                       if (c2 < 0 || ((c2 == 0) && errno))
+                               return errno;
+                       if (c2 == 0 && --retries <= 0)
+                               break; /* This should never happen...  */
+               }
+               count -= c1;
+       }
        return 0;
 }