- vdpa: Fix bug where vdpa appliance migration does not resume after rollback - block: Parse filenames only when explicitly requested (CVE-2024-4467) - block: introduce bdrv_open_file_child() helper - iotests/270: Don't store data-file with json: prefix in image (CVE-2024-4467) - iotests/244: Don't store data-file with protocol in image (CVE-2024-4467) - qcow2: Don't open data_file with BDRV_O_NO_IO (CVE-2024-4467) - qcow2: Do not reopen data_file in invalidate_cache - hw/intc/arm_gic: Fix deactivation of SPI lines chery-pick from 7175a562f157d39725ab396e39c1e8e410d206b3 - vhost-user: Skip unnecessary duplicated VHOST_USER_SET_LOG_BASE requests - target/ppc: Split off common embedded TLB init cheery-pick from 581eea5d656b73c6532109f4ced4c73fd4e5fd47` - vdpa: fix vdpa device migrate rollback wrong when suspend device failed 1. - hw/virtio/virtio-pci:Support shadow device for virtio-net/blk/scsi devices Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com> (cherry picked from commit ad45062d44e901468eeb8c4ac0729587daaa1e1f)
222 lines
8.1 KiB
Diff
222 lines
8.1 KiB
Diff
From d21b395997737618116926cb2680e85d79e14d19 Mon Sep 17 00:00:00 2001
|
|
From: Hanna Reitz <hreitz@redhat.com>
|
|
Date: Wed, 27 Apr 2022 13:40:55 +0200
|
|
Subject: [PATCH] qcow2: Do not reopen data_file in invalidate_cache
|
|
|
|
qcow2_co_invalidate_cache() closes and opens the qcow2 file, by calling
|
|
qcow2_close() and qcow2_do_open(). These two functions must thus be
|
|
usable from both a global-state and an I/O context.
|
|
|
|
As they are, they are not safe to call in an I/O context, because they
|
|
use bdrv_unref_child() and bdrv_open_child() to close/open the data_file
|
|
child, respectively, both of which are global-state functions. When
|
|
used from qcow2_co_invalidate_cache(), we do not need to close/open the
|
|
data_file child, though (we do not do this for bs->file or bs->backing
|
|
either), and so we should skip it in the qcow2_co_invalidate_cache()
|
|
path.
|
|
|
|
To do so, add a parameter to qcow2_do_open() and qcow2_close() to make
|
|
them skip handling s->data_file, and have qcow2_co_invalidate_cache()
|
|
exempt it from the memset() on the BDRVQcow2State.
|
|
|
|
(Note that the QED driver similarly closes/opens the QED image by
|
|
invoking bdrv_qed_close()+bdrv_qed_do_open(), but both functions seem
|
|
safe to use in an I/O context.)
|
|
|
|
Fixes: https://gitlab.com/qemu-project/qemu/-/issues/945
|
|
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
|
|
Message-Id: <20220427114057.36651-3-hreitz@redhat.com>
|
|
Reviewed-by: Eric Blake <eblake@redhat.com>
|
|
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
|
---
|
|
block/qcow2.c | 104 ++++++++++++++++++++++++++++++--------------------
|
|
1 file changed, 62 insertions(+), 42 deletions(-)
|
|
|
|
diff --git a/block/qcow2.c b/block/qcow2.c
|
|
index be90a898e3..4a6b0a3ea9 100644
|
|
--- a/block/qcow2.c
|
|
+++ b/block/qcow2.c
|
|
@@ -1296,7 +1296,8 @@ static int validate_compression_type(BDRVQcow2State *s, Error **errp)
|
|
|
|
/* Called with s->lock held. */
|
|
static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
|
- int flags, Error **errp)
|
|
+ int flags, bool open_data_file,
|
|
+ Error **errp)
|
|
{
|
|
ERRP_GUARD();
|
|
BDRVQcow2State *s = bs->opaque;
|
|
@@ -1614,50 +1615,52 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
|
goto fail;
|
|
}
|
|
|
|
- /* Open external data file */
|
|
- s->data_file = bdrv_open_child(NULL, options, "data-file", bs,
|
|
- &child_of_bds, BDRV_CHILD_DATA,
|
|
- true, errp);
|
|
- if (*errp) {
|
|
- ret = -EINVAL;
|
|
- goto fail;
|
|
- }
|
|
+ if (open_data_file) {
|
|
+ /* Open external data file */
|
|
+ s->data_file = bdrv_open_child(NULL, options, "data-file", bs,
|
|
+ &child_of_bds, BDRV_CHILD_DATA,
|
|
+ true, errp);
|
|
+ if (*errp) {
|
|
+ ret = -EINVAL;
|
|
+ goto fail;
|
|
+ }
|
|
|
|
- if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
|
|
- if (!s->data_file && s->image_data_file) {
|
|
- s->data_file = bdrv_open_child(s->image_data_file, options,
|
|
- "data-file", bs, &child_of_bds,
|
|
- BDRV_CHILD_DATA, false, errp);
|
|
+ if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
|
|
+ if (!s->data_file && s->image_data_file) {
|
|
+ s->data_file = bdrv_open_child(s->image_data_file, options,
|
|
+ "data-file", bs, &child_of_bds,
|
|
+ BDRV_CHILD_DATA, false, errp);
|
|
+ if (!s->data_file) {
|
|
+ ret = -EINVAL;
|
|
+ goto fail;
|
|
+ }
|
|
+ }
|
|
if (!s->data_file) {
|
|
+ error_setg(errp, "'data-file' is required for this image");
|
|
ret = -EINVAL;
|
|
goto fail;
|
|
}
|
|
- }
|
|
- if (!s->data_file) {
|
|
- error_setg(errp, "'data-file' is required for this image");
|
|
- ret = -EINVAL;
|
|
- goto fail;
|
|
- }
|
|
|
|
- /* No data here */
|
|
- bs->file->role &= ~BDRV_CHILD_DATA;
|
|
+ /* No data here */
|
|
+ bs->file->role &= ~BDRV_CHILD_DATA;
|
|
|
|
- /* Must succeed because we have given up permissions if anything */
|
|
- bdrv_child_refresh_perms(bs, bs->file, &error_abort);
|
|
- } else {
|
|
- if (s->data_file) {
|
|
- error_setg(errp, "'data-file' can only be set for images with an "
|
|
- "external data file");
|
|
- ret = -EINVAL;
|
|
- goto fail;
|
|
- }
|
|
+ /* Must succeed because we have given up permissions if anything */
|
|
+ bdrv_child_refresh_perms(bs, bs->file, &error_abort);
|
|
+ } else {
|
|
+ if (s->data_file) {
|
|
+ error_setg(errp, "'data-file' can only be set for images with "
|
|
+ "an external data file");
|
|
+ ret = -EINVAL;
|
|
+ goto fail;
|
|
+ }
|
|
|
|
- s->data_file = bs->file;
|
|
+ s->data_file = bs->file;
|
|
|
|
- if (data_file_is_raw(bs)) {
|
|
- error_setg(errp, "data-file-raw requires a data file");
|
|
- ret = -EINVAL;
|
|
- goto fail;
|
|
+ if (data_file_is_raw(bs)) {
|
|
+ error_setg(errp, "data-file-raw requires a data file");
|
|
+ ret = -EINVAL;
|
|
+ goto fail;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -1839,7 +1842,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
|
|
|
fail:
|
|
g_free(s->image_data_file);
|
|
- if (has_data_file(bs)) {
|
|
+ if (open_data_file && has_data_file(bs)) {
|
|
bdrv_unref_child(bs, s->data_file);
|
|
s->data_file = NULL;
|
|
}
|
|
@@ -1876,7 +1879,8 @@ static void coroutine_fn qcow2_open_entry(void *opaque)
|
|
BDRVQcow2State *s = qoc->bs->opaque;
|
|
|
|
qemu_co_mutex_lock(&s->lock);
|
|
- qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, qoc->errp);
|
|
+ qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, true,
|
|
+ qoc->errp);
|
|
qemu_co_mutex_unlock(&s->lock);
|
|
}
|
|
|
|
@@ -2714,7 +2718,7 @@ static int qcow2_inactivate(BlockDriverState *bs)
|
|
return result;
|
|
}
|
|
|
|
-static void qcow2_close(BlockDriverState *bs)
|
|
+static void qcow2_do_close(BlockDriverState *bs, bool close_data_file)
|
|
{
|
|
BDRVQcow2State *s = bs->opaque;
|
|
qemu_vfree(s->l1_table);
|
|
@@ -2740,7 +2744,7 @@ static void qcow2_close(BlockDriverState *bs)
|
|
g_free(s->image_backing_file);
|
|
g_free(s->image_backing_format);
|
|
|
|
- if (has_data_file(bs)) {
|
|
+ if (close_data_file && has_data_file(bs)) {
|
|
bdrv_unref_child(bs, s->data_file);
|
|
s->data_file = NULL;
|
|
}
|
|
@@ -2749,11 +2753,17 @@ static void qcow2_close(BlockDriverState *bs)
|
|
qcow2_free_snapshots(bs);
|
|
}
|
|
|
|
+static void qcow2_close(BlockDriverState *bs)
|
|
+{
|
|
+ qcow2_do_close(bs, true);
|
|
+}
|
|
+
|
|
static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs,
|
|
Error **errp)
|
|
{
|
|
ERRP_GUARD();
|
|
BDRVQcow2State *s = bs->opaque;
|
|
+ BdrvChild *data_file;
|
|
int flags = s->flags;
|
|
QCryptoBlock *crypto = NULL;
|
|
QDict *options;
|
|
@@ -2767,14 +2777,24 @@ static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs,
|
|
crypto = s->crypto;
|
|
s->crypto = NULL;
|
|
|
|
- qcow2_close(bs);
|
|
+ /*
|
|
+ * Do not reopen s->data_file (i.e., have qcow2_do_close() not close it,
|
|
+ * and then prevent qcow2_do_open() from opening it), because this function
|
|
+ * runs in the I/O path and as such we must not invoke global-state
|
|
+ * functions like bdrv_unref_child() and bdrv_open_child().
|
|
+ */
|
|
|
|
+ qcow2_do_close(bs, false);
|
|
+
|
|
+ data_file = s->data_file;
|
|
memset(s, 0, sizeof(BDRVQcow2State));
|
|
+ s->data_file = data_file;
|
|
+
|
|
options = qdict_clone_shallow(bs->options);
|
|
|
|
flags &= ~BDRV_O_INACTIVE;
|
|
qemu_co_mutex_lock(&s->lock);
|
|
- ret = qcow2_do_open(bs, options, flags, errp);
|
|
+ ret = qcow2_do_open(bs, options, flags, false, errp);
|
|
qemu_co_mutex_unlock(&s->lock);
|
|
qobject_unref(options);
|
|
if (ret < 0) {
|
|
--
|
|
2.41.0.windows.1
|
|
|