From 4172d6971a212b3597f1e112334d22785ea7f864 Mon Sep 17 00:00:00 2001 From: "Danilo C. L. de Paula" Date: Thu, 26 Sep 2019 00:35:11 +0100 Subject: [PATCH] * Thu Sep 26 2019 Danilo Cesar Lemes de Paula - 4.1.0-12.el8 - kvm-block-Use-QEMU_IS_ALIGNED.patch [bz#1745922] - kvm-block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch [bz#1745922] - kvm-block-qcow2-refactor-encryption-code.patch [bz#1745922] - kvm-qemu-iotests-Add-test-for-bz-1745922.patch [bz#1745922] - Resolves: bz#1745922 (Luks-inside-qcow2 snapshot cannot boot after 'qemu-img rebase') --- kvm-block-Use-QEMU_IS_ALIGNED.patch | 192 ++++++++++++++ ...corruption-introduced-by-commit-8ac0.patch | 78 ++++++ ...block-qcow2-refactor-encryption-code.patch | 234 ++++++++++++++++++ ...qemu-iotests-Add-test-for-bz-1745922.patch | 191 ++++++++++++++ qemu-kvm.spec | 18 +- 5 files changed, 712 insertions(+), 1 deletion(-) create mode 100644 kvm-block-Use-QEMU_IS_ALIGNED.patch create mode 100644 kvm-block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch create mode 100644 kvm-block-qcow2-refactor-encryption-code.patch create mode 100644 kvm-qemu-iotests-Add-test-for-bz-1745922.patch diff --git a/kvm-block-Use-QEMU_IS_ALIGNED.patch b/kvm-block-Use-QEMU_IS_ALIGNED.patch new file mode 100644 index 0000000..7d4e065 --- /dev/null +++ b/kvm-block-Use-QEMU_IS_ALIGNED.patch @@ -0,0 +1,192 @@ +From 1eb1c45037b1e1084ab601ac8461fabca162b479 Mon Sep 17 00:00:00 2001 +From: Maxim Levitsky +Date: Tue, 24 Sep 2019 21:11:49 +0100 +Subject: [PATCH 1/4] block: Use QEMU_IS_ALIGNED + +RH-Author: Maxim Levitsky +Message-id: <20190924211152.13461-2-mlevitsk@redhat.com> +Patchwork-id: 90874 +O-Subject: [RHEL-AV-8.1.0 qemu-kvm PATCH v2 1/4] block: Use QEMU_IS_ALIGNED +Bugzilla: 1745922 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Danilo de Paula + +From: Nir Soffer + +Replace instances of: + + (n & (BDRV_SECTOR_SIZE - 1)) == 0 + +And: + + (n & ~BDRV_SECTOR_MASK) == 0 + +With: + + QEMU_IS_ALIGNED(n, BDRV_SECTOR_SIZE) + +Which reveals the intent of the code better, and makes it easier to +locate the code checking alignment. + +Signed-off-by: Nir Soffer +Message-id: 20190827185913.27427-2-nsoffer@redhat.com +Reviewed-by: John Snow +Signed-off-by: Max Reitz +(cherry picked from commit 1bbbf32d5fffe334531c315d7bd865fdfb67b6c5) +Signed-off-by: Maxim Levitsky +Signed-off-by: Danilo C. L. de Paula +--- + block/bochs.c | 4 ++-- + block/cloop.c | 4 ++-- + block/dmg.c | 4 ++-- + block/io.c | 8 ++++---- + block/qcow2-cluster.c | 4 ++-- + block/qcow2.c | 4 ++-- + block/vvfat.c | 8 ++++---- + qemu-img.c | 2 +- + 8 files changed, 19 insertions(+), 19 deletions(-) + +diff --git a/block/bochs.c b/block/bochs.c +index 962f185..32bb83b 100644 +--- a/block/bochs.c ++++ b/block/bochs.c +@@ -248,8 +248,8 @@ bochs_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + QEMUIOVector local_qiov; + int ret; + +- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); +- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0); ++ assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); + + qemu_iovec_init(&local_qiov, qiov->niov); + qemu_co_mutex_lock(&s->lock); +diff --git a/block/cloop.c b/block/cloop.c +index 384c973..4de9487 100644 +--- a/block/cloop.c ++++ b/block/cloop.c +@@ -253,8 +253,8 @@ cloop_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + int nb_sectors = bytes >> BDRV_SECTOR_BITS; + int ret, i; + +- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); +- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0); ++ assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); + + qemu_co_mutex_lock(&s->lock); + +diff --git a/block/dmg.c b/block/dmg.c +index 45f6b28..4a045f2 100644 +--- a/block/dmg.c ++++ b/block/dmg.c +@@ -697,8 +697,8 @@ dmg_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + int nb_sectors = bytes >> BDRV_SECTOR_BITS; + int ret, i; + +- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); +- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0); ++ assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); + + qemu_co_mutex_lock(&s->lock); + +diff --git a/block/io.c b/block/io.c +index 06305c6..54093fc 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -1079,8 +1079,8 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs, + sector_num = offset >> BDRV_SECTOR_BITS; + nb_sectors = bytes >> BDRV_SECTOR_BITS; + +- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); +- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0); ++ assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); + assert(bytes <= BDRV_REQUEST_MAX_BYTES); + assert(drv->bdrv_co_readv); + +@@ -1132,8 +1132,8 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, + sector_num = offset >> BDRV_SECTOR_BITS; + nb_sectors = bytes >> BDRV_SECTOR_BITS; + +- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); +- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0); ++ assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); + assert(bytes <= BDRV_REQUEST_MAX_BYTES); + + assert(drv->bdrv_co_writev); +diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c +index cc5609e..f2de746 100644 +--- a/block/qcow2-cluster.c ++++ b/block/qcow2-cluster.c +@@ -470,8 +470,8 @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, + { + if (bytes && bs->encrypted) { + BDRVQcow2State *s = bs->opaque; +- assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0); +- assert((bytes & ~BDRV_SECTOR_MASK) == 0); ++ assert(QEMU_IS_ALIGNED(offset_in_cluster, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); + assert(s->crypto); + if (qcow2_co_encrypt(bs, cluster_offset, + src_cluster_offset + offset_in_cluster, +diff --git a/block/qcow2.c b/block/qcow2.c +index 039bdc2..dc4302f 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -2071,8 +2071,8 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, + } + if (bs->encrypted) { + assert(s->crypto); +- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); +- assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0); ++ assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(cur_bytes, BDRV_SECTOR_SIZE)); + if (qcow2_co_decrypt(bs, cluster_offset, offset, + cluster_data, cur_bytes) < 0) { + ret = -EIO; +diff --git a/block/vvfat.c b/block/vvfat.c +index f6c2880..019b8f1 100644 +--- a/block/vvfat.c ++++ b/block/vvfat.c +@@ -1547,8 +1547,8 @@ vvfat_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + int nb_sectors = bytes >> BDRV_SECTOR_BITS; + void *buf; + +- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); +- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0); ++ assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); + + buf = g_try_malloc(bytes); + if (bytes && buf == NULL) { +@@ -3082,8 +3082,8 @@ vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + int nb_sectors = bytes >> BDRV_SECTOR_BITS; + void *buf; + +- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); +- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0); ++ assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); + + buf = g_try_malloc(bytes); + if (bytes && buf == NULL) { +diff --git a/qemu-img.c b/qemu-img.c +index 7998377..940ae94 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -2138,7 +2138,7 @@ static int img_convert(int argc, char **argv) + int64_t sval; + + sval = cvtnum(optarg); +- if (sval < 0 || sval & (BDRV_SECTOR_SIZE - 1) || ++ if (sval < 0 || !QEMU_IS_ALIGNED(sval, BDRV_SECTOR_SIZE) || + sval / BDRV_SECTOR_SIZE > MAX_BUF_SECTORS) { + error_report("Invalid buffer size for sparse output specified. " + "Valid sizes are multiples of %llu up to %llu. Select " +-- +1.8.3.1 + diff --git a/kvm-block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch b/kvm-block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch new file mode 100644 index 0000000..9cdcb3f --- /dev/null +++ b/kvm-block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch @@ -0,0 +1,78 @@ +From 554884a1fe9a271ad78771c37e4be5a8f84258fc Mon Sep 17 00:00:00 2001 +From: Maxim Levitsky +Date: Tue, 24 Sep 2019 21:11:50 +0100 +Subject: [PATCH 2/4] block/qcow2: Fix corruption introduced by commit + 8ac0f15f335 + +RH-Author: Maxim Levitsky +Message-id: <20190924211152.13461-3-mlevitsk@redhat.com> +Patchwork-id: 90878 +O-Subject: [RHEL-AV-8.1.0 qemu-kvm PATCH v2 2/4] block/qcow2: Fix corruption introduced by commit 8ac0f15f335 +Bugzilla: 1745922 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Danilo de Paula + +This fixes subtle corruption introduced by luks threaded encryption +in commit 8ac0f15f335 + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1745922 + +The corruption happens when we do a write that + * writes to two or more unallocated clusters at once + * doesn't fully cover the first sector + * doesn't fully cover the last sector + * uses luks encryption + +In this case, when allocating the new clusters we COW both areas +prior to the write and after the write, and we encrypt them. + +The above mentioned commit accidentally made it so we encrypt the +second COW area using the physical cluster offset of the first area. + +The problem is that offset_in_cluster in do_perform_cow_encrypt +can be larger that the cluster size, thus cluster_offset +will no longer point to the start of the cluster at which encrypted +area starts. + +Next patch in this series will refactor the code to avoid all these +assumptions. + +In the bugreport that was triggered by rebasing a luks image to new, +zero filled base, which lot of such writes, and causes some files +with zero areas to contain garbage there instead. +But as described above it can happen elsewhere as well + +Signed-off-by: Maxim Levitsky +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190915203655.21638-2-mlevitsk@redhat.com +Reviewed-by: Max Reitz +Signed-off-by: Max Reitz +(cherry picked from commit 38e7d54bdc518b5a05a922467304bcace2396945) +Signed-off-by: Maxim Levitsky +Signed-off-by: Danilo C. L. de Paula +--- + block/qcow2-cluster.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c +index f2de746..11e5a92 100644 +--- a/block/qcow2-cluster.c ++++ b/block/qcow2-cluster.c +@@ -473,9 +473,10 @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, + assert(QEMU_IS_ALIGNED(offset_in_cluster, BDRV_SECTOR_SIZE)); + assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); + assert(s->crypto); +- if (qcow2_co_encrypt(bs, cluster_offset, +- src_cluster_offset + offset_in_cluster, +- buffer, bytes) < 0) { ++ if (qcow2_co_encrypt(bs, ++ start_of_cluster(s, cluster_offset + offset_in_cluster), ++ src_cluster_offset + offset_in_cluster, ++ buffer, bytes) < 0) { + return false; + } + } +-- +1.8.3.1 + diff --git a/kvm-block-qcow2-refactor-encryption-code.patch b/kvm-block-qcow2-refactor-encryption-code.patch new file mode 100644 index 0000000..f32907a --- /dev/null +++ b/kvm-block-qcow2-refactor-encryption-code.patch @@ -0,0 +1,234 @@ +From 780fbdf04884188eca3d5891faa2b2417a88ef14 Mon Sep 17 00:00:00 2001 +From: Maxim Levitsky +Date: Tue, 24 Sep 2019 21:11:51 +0100 +Subject: [PATCH 3/4] block/qcow2: refactor encryption code + +RH-Author: Maxim Levitsky +Message-id: <20190924211152.13461-4-mlevitsk@redhat.com> +Patchwork-id: 90876 +O-Subject: [RHEL-AV-8.1.0 qemu-kvm PATCH v2 3/4] block/qcow2: refactor encryption code +Bugzilla: 1745922 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Danilo de Paula + +* Change the qcow2_co_{encrypt|decrypt} to just receive full host and + guest offsets and use this function directly instead of calling + do_perform_cow_encrypt (which is removed by that patch). + +* Adjust qcow2_co_encdec to take full host and guest offsets as well. + +* Document the qcow2_co_{encrypt|decrypt} arguments + to prevent the bug fixed in former commit from hopefully + happening again. + +Signed-off-by: Maxim Levitsky +Message-id: 20190915203655.21638-3-mlevitsk@redhat.com +Reviewed-by: Vladimir Sementsov-Ogievskiy +[mreitz: Let perform_cow() return the error value returned by + qcow2_co_encrypt(), as proposed by Vladimir] +Signed-off-by: Max Reitz +(cherry picked from commit 603fbd076c76438b15ec842f0e2d1ba4867dfd00) +Signed-off-by: Maxim Levitsky + +Signed-off-by: Danilo C. L. de Paula +--- + block/qcow2-cluster.c | 41 +++++++++++---------------------- + block/qcow2-threads.c | 63 +++++++++++++++++++++++++++++++++++++++------------ + block/qcow2.c | 5 ++-- + block/qcow2.h | 8 +++---- + 4 files changed, 69 insertions(+), 48 deletions(-) + +diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c +index 11e5a92..b30fd12 100644 +--- a/block/qcow2-cluster.c ++++ b/block/qcow2-cluster.c +@@ -461,28 +461,6 @@ static int coroutine_fn do_perform_cow_read(BlockDriverState *bs, + return 0; + } + +-static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, +- uint64_t src_cluster_offset, +- uint64_t cluster_offset, +- unsigned offset_in_cluster, +- uint8_t *buffer, +- unsigned bytes) +-{ +- if (bytes && bs->encrypted) { +- BDRVQcow2State *s = bs->opaque; +- assert(QEMU_IS_ALIGNED(offset_in_cluster, BDRV_SECTOR_SIZE)); +- assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); +- assert(s->crypto); +- if (qcow2_co_encrypt(bs, +- start_of_cluster(s, cluster_offset + offset_in_cluster), +- src_cluster_offset + offset_in_cluster, +- buffer, bytes) < 0) { +- return false; +- } +- } +- return true; +-} +- + static int coroutine_fn do_perform_cow_write(BlockDriverState *bs, + uint64_t cluster_offset, + unsigned offset_in_cluster, +@@ -887,12 +865,19 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m) + + /* Encrypt the data if necessary before writing it */ + if (bs->encrypted) { +- if (!do_perform_cow_encrypt(bs, m->offset, m->alloc_offset, +- start->offset, start_buffer, +- start->nb_bytes) || +- !do_perform_cow_encrypt(bs, m->offset, m->alloc_offset, +- end->offset, end_buffer, end->nb_bytes)) { +- ret = -EIO; ++ ret = qcow2_co_encrypt(bs, ++ m->alloc_offset + start->offset, ++ m->offset + start->offset, ++ start_buffer, start->nb_bytes); ++ if (ret < 0) { ++ goto fail; ++ } ++ ++ ret = qcow2_co_encrypt(bs, ++ m->alloc_offset + end->offset, ++ m->offset + end->offset, ++ end_buffer, end->nb_bytes); ++ if (ret < 0) { + goto fail; + } + } +diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c +index 3b1e63f..8f5a0d1 100644 +--- a/block/qcow2-threads.c ++++ b/block/qcow2-threads.c +@@ -234,35 +234,70 @@ static int qcow2_encdec_pool_func(void *opaque) + } + + static int coroutine_fn +-qcow2_co_encdec(BlockDriverState *bs, uint64_t file_cluster_offset, +- uint64_t offset, void *buf, size_t len, Qcow2EncDecFunc func) ++qcow2_co_encdec(BlockDriverState *bs, uint64_t host_offset, ++ uint64_t guest_offset, void *buf, size_t len, ++ Qcow2EncDecFunc func) + { + BDRVQcow2State *s = bs->opaque; + Qcow2EncDecData arg = { + .block = s->crypto, +- .offset = s->crypt_physical_offset ? +- file_cluster_offset + offset_into_cluster(s, offset) : +- offset, ++ .offset = s->crypt_physical_offset ? host_offset : guest_offset, + .buf = buf, + .len = len, + .func = func, + }; + +- return qcow2_co_process(bs, qcow2_encdec_pool_func, &arg); ++ assert(QEMU_IS_ALIGNED(guest_offset, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(host_offset, BDRV_SECTOR_SIZE)); ++ assert(QEMU_IS_ALIGNED(len, BDRV_SECTOR_SIZE)); ++ assert(s->crypto); ++ ++ return len == 0 ? 0 : qcow2_co_process(bs, qcow2_encdec_pool_func, &arg); + } + ++/* ++ * qcow2_co_encrypt() ++ * ++ * Encrypts one or more contiguous aligned sectors ++ * ++ * @host_offset - underlying storage offset of the first sector of the ++ * data to be encrypted ++ * ++ * @guest_offset - guest (virtual) offset of the first sector of the ++ * data to be encrypted ++ * ++ * @buf - buffer with the data to encrypt, that after encryption ++ * will be written to the underlying storage device at ++ * @host_offset ++ * ++ * @len - length of the buffer (must be a BDRV_SECTOR_SIZE multiple) ++ * ++ * Depending on the encryption method, @host_offset and/or @guest_offset ++ * may be used for generating the initialization vector for ++ * encryption. ++ * ++ * Note that while the whole range must be aligned on sectors, it ++ * does not have to be aligned on clusters and can also cross cluster ++ * boundaries ++ */ + int coroutine_fn +-qcow2_co_encrypt(BlockDriverState *bs, uint64_t file_cluster_offset, +- uint64_t offset, void *buf, size_t len) ++qcow2_co_encrypt(BlockDriverState *bs, uint64_t host_offset, ++ uint64_t guest_offset, void *buf, size_t len) + { +- return qcow2_co_encdec(bs, file_cluster_offset, offset, buf, len, +- qcrypto_block_encrypt); ++ return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len, ++ qcrypto_block_encrypt); + } + ++/* ++ * qcow2_co_decrypt() ++ * ++ * Decrypts one or more contiguous aligned sectors ++ * Similar to qcow2_co_encrypt ++ */ + int coroutine_fn +-qcow2_co_decrypt(BlockDriverState *bs, uint64_t file_cluster_offset, +- uint64_t offset, void *buf, size_t len) ++qcow2_co_decrypt(BlockDriverState *bs, uint64_t host_offset, ++ uint64_t guest_offset, void *buf, size_t len) + { +- return qcow2_co_encdec(bs, file_cluster_offset, offset, buf, len, +- qcrypto_block_decrypt); ++ return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len, ++ qcrypto_block_decrypt); + } +diff --git a/block/qcow2.c b/block/qcow2.c +index dc4302f..d4c4f24 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -2073,7 +2073,8 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, + assert(s->crypto); + assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); + assert(QEMU_IS_ALIGNED(cur_bytes, BDRV_SECTOR_SIZE)); +- if (qcow2_co_decrypt(bs, cluster_offset, offset, ++ if (qcow2_co_decrypt(bs, cluster_offset + offset_in_cluster, ++ offset, + cluster_data, cur_bytes) < 0) { + ret = -EIO; + goto fail; +@@ -2288,7 +2289,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, + QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); + qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size); + +- if (qcow2_co_encrypt(bs, cluster_offset, offset, ++ if (qcow2_co_encrypt(bs, cluster_offset + offset_in_cluster, offset, + cluster_data, cur_bytes) < 0) { + ret = -EIO; + goto out_unlocked; +diff --git a/block/qcow2.h b/block/qcow2.h +index fc1b0d3..b54e734 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -757,10 +757,10 @@ ssize_t coroutine_fn + qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size, + const void *src, size_t src_size); + int coroutine_fn +-qcow2_co_encrypt(BlockDriverState *bs, uint64_t file_cluster_offset, +- uint64_t offset, void *buf, size_t len); ++qcow2_co_encrypt(BlockDriverState *bs, uint64_t host_offset, ++ uint64_t guest_offset, void *buf, size_t len); + int coroutine_fn +-qcow2_co_decrypt(BlockDriverState *bs, uint64_t file_cluster_offset, +- uint64_t offset, void *buf, size_t len); ++qcow2_co_decrypt(BlockDriverState *bs, uint64_t host_offset, ++ uint64_t guest_offset, void *buf, size_t len); + + #endif +-- +1.8.3.1 + diff --git a/kvm-qemu-iotests-Add-test-for-bz-1745922.patch b/kvm-qemu-iotests-Add-test-for-bz-1745922.patch new file mode 100644 index 0000000..00751f5 --- /dev/null +++ b/kvm-qemu-iotests-Add-test-for-bz-1745922.patch @@ -0,0 +1,191 @@ +From a888b935e29a08f0ace84906fee84b41a5f8b95d Mon Sep 17 00:00:00 2001 +From: Maxim Levitsky +Date: Tue, 24 Sep 2019 21:11:52 +0100 +Subject: [PATCH 4/4] qemu-iotests: Add test for bz #1745922 + +RH-Author: Maxim Levitsky +Message-id: <20190924211152.13461-5-mlevitsk@redhat.com> +Patchwork-id: 90877 +O-Subject: [RHEL-AV-8.1.0 qemu-kvm PATCH v2 4/4] qemu-iotests: Add test for bz #1745922 +Bugzilla: 1745922 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Danilo de Paula + +Signed-off-by: Maxim Levitsky +Tested-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190915203655.21638-4-mlevitsk@redhat.com +Reviewed-by: Max Reitz +Signed-off-by: Max Reitz +(cherry picked from commit 1825cc0783ccf0ec5d9f0b225a99b340bdd4c68f) +Signed-off-by: Maxim Levitsky + + Conflicts: + tests/qemu-iotests/group + usual conflicts with missing tests + +Signed-off-by: Danilo C. L. de Paula +--- + tests/qemu-iotests/263 | 91 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/263.out | 40 ++++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 132 insertions(+) + create mode 100755 tests/qemu-iotests/263 + create mode 100644 tests/qemu-iotests/263.out + +diff --git a/tests/qemu-iotests/263 b/tests/qemu-iotests/263 +new file mode 100755 +index 0000000..d2c030f +--- /dev/null ++++ b/tests/qemu-iotests/263 +@@ -0,0 +1,91 @@ ++#!/usr/bin/env bash ++# ++# Test encrypted write that crosses cluster boundary of two unallocated clusters ++# Based on 188 ++# ++# Copyright (C) 2019 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# creator ++owner=mlevitsk@redhat.com ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_test_img ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++_supported_fmt qcow2 ++_supported_proto generic ++_supported_os Linux ++ ++ ++size=1M ++ ++SECRET="secret,id=sec0,data=astrochicken" ++QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT ++ ++ ++_run_test() ++{ ++ echo "== reading the whole image ==" ++ $QEMU_IO --object $SECRET -c "read -P 0 0 $size" --image-opts "$1" | _filter_qemu_io | _filter_testdir ++ ++ echo ++ echo "== write two 512 byte sectors on a cluster boundary ==" ++ $QEMU_IO --object $SECRET -c "write -P 0xAA 0xFE00 0x400" --image-opts "$1" | _filter_qemu_io | _filter_testdir ++ ++ echo ++ echo "== verify that the rest of the image is not changed ==" ++ $QEMU_IO --object $SECRET -c "read -P 0x00 0x00000 0xFE00" --image-opts "$1" | _filter_qemu_io | _filter_testdir ++ $QEMU_IO --object $SECRET -c "read -P 0xAA 0x0FE00 0x400" --image-opts "$1" | _filter_qemu_io | _filter_testdir ++ $QEMU_IO --object $SECRET -c "read -P 0x00 0x10200 0xEFE00" --image-opts "$1" | _filter_qemu_io | _filter_testdir ++ ++} ++ ++ ++echo ++echo "testing LUKS qcow2 encryption" ++echo ++ ++_make_test_img --object $SECRET -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10,cluster_size=64K" $size ++_run_test "driver=$IMGFMT,encrypt.key-secret=sec0,file.filename=$TEST_IMG" ++_cleanup_test_img ++ ++echo ++echo "testing legacy AES qcow2 encryption" ++echo ++ ++ ++_make_test_img --object $SECRET -o "encrypt.format=aes,encrypt.key-secret=sec0,cluster_size=64K" $size ++_run_test "driver=$IMGFMT,encrypt.key-secret=sec0,file.filename=$TEST_IMG" ++_cleanup_test_img ++ ++ ++ ++# success, all done ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/263.out b/tests/qemu-iotests/263.out +new file mode 100644 +index 0000000..0c982c5 +--- /dev/null ++++ b/tests/qemu-iotests/263.out +@@ -0,0 +1,40 @@ ++QA output created by 263 ++ ++testing LUKS qcow2 encryption ++ ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 ++== reading the whole image == ++read 1048576/1048576 bytes at offset 0 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++== write two 512 byte sectors on a cluster boundary == ++wrote 1024/1024 bytes at offset 65024 ++1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++== verify that the rest of the image is not changed == ++read 65024/65024 bytes at offset 0 ++63.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 1024/1024 bytes at offset 65024 ++1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 982528/982528 bytes at offset 66048 ++959.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++testing legacy AES qcow2 encryption ++ ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=aes encrypt.key-secret=sec0 ++== reading the whole image == ++read 1048576/1048576 bytes at offset 0 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++== write two 512 byte sectors on a cluster boundary == ++wrote 1024/1024 bytes at offset 65024 ++1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++== verify that the rest of the image is not changed == ++read 65024/65024 bytes at offset 0 ++63.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 1024/1024 bytes at offset 65024 ++1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 982528/982528 bytes at offset 66048 ++959.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 813db25..4a7e08f 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -271,3 +271,4 @@ + 254 rw backing quick + 255 rw quick + 256 rw quick ++263 rw quick +\ No newline at end of file +-- +1.8.3.1 + diff --git a/qemu-kvm.spec b/qemu-kvm.spec index 697bb0c..50ee372 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -67,7 +67,7 @@ Obsoletes: %1-rhev Summary: QEMU is a machine emulator and virtualizer Name: qemu-kvm Version: 4.1.0 -Release: 11%{?dist} +Release: 12%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 15 License: GPLv2 and GPLv2+ and CC-BY @@ -208,6 +208,14 @@ Patch61: kvm-hostmem-file-fix-pmem-file-size-check.patch Patch62: kvm-memory-fetch-pmem-size-in-get_file_size.patch # For bz#1753992 - core dump when testing persistent reservation in guest Patch63: kvm-pr-manager-Fix-invalid-g_free-crash-bug.patch +# For bz#1745922 - Luks-inside-qcow2 snapshot cannot boot after 'qemu-img rebase' +Patch64: kvm-block-Use-QEMU_IS_ALIGNED.patch +# For bz#1745922 - Luks-inside-qcow2 snapshot cannot boot after 'qemu-img rebase' +Patch65: kvm-block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch +# For bz#1745922 - Luks-inside-qcow2 snapshot cannot boot after 'qemu-img rebase' +Patch66: kvm-block-qcow2-refactor-encryption-code.patch +# For bz#1745922 - Luks-inside-qcow2 snapshot cannot boot after 'qemu-img rebase' +Patch67: kvm-qemu-iotests-Add-test-for-bz-1745922.patch BuildRequires: wget BuildRequires: rpm-build @@ -1149,6 +1157,14 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %changelog +* Thu Sep 26 2019 Danilo Cesar Lemes de Paula - 4.1.0-12.el8 +- kvm-block-Use-QEMU_IS_ALIGNED.patch [bz#1745922] +- kvm-block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch [bz#1745922] +- kvm-block-qcow2-refactor-encryption-code.patch [bz#1745922] +- kvm-qemu-iotests-Add-test-for-bz-1745922.patch [bz#1745922] +- Resolves: bz#1745922 + (Luks-inside-qcow2 snapshot cannot boot after 'qemu-img rebase') + * Mon Sep 23 2019 Danilo Cesar Lemes de Paula - 4.1.0-11.el8 - kvm-blockjob-update-nodes-head-while-removing-all-bdrv.patch [bz#1746631] - kvm-hostmem-file-fix-pmem-file-size-check.patch [bz#1724008 bz#1736788]