diff options
author | Theodore Ts'o <tytso@mit.edu> | 2024-04-25 17:52:05 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2024-04-25 17:52:05 -0400 |
commit | 8cfc832cf6771c950c9220b6fe8c9df82f577c52 (patch) | |
tree | 15a8f4c81904419af93335daaaf4520c4edceef2 | |
parent | d819acefb176188bac3e28e7d56fd80325dfc5ee (diff) | |
download | e2fsprogs-8cfc832cf6771c950c9220b6fe8c9df82f577c52.tar.gz |
libextr2fs: handle short reads/writes while creating the qcow file
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>
-rw-r--r-- | lib/ext2fs/qcow2.c | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/lib/ext2fs/qcow2.c b/lib/ext2fs/qcow2.c index 208241707..8f96eeed7 100644 --- a/lib/ext2fs/qcow2.c +++ b/lib/ext2fs/qcow2.c @@ -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; } |