@@ -113,6 +113,11 @@ SRC_URI = "https://download.qemu.org/${BPN}-${PV}.tar.xz \
file://CVE-2024-7409-0002.patch \
file://CVE-2024-7409-0003.patch \
file://CVE-2024-7409-0004.patch \
+ file://CVE-2024-4467-0001.patch \
+ file://CVE-2024-4467-0002.patch \
+ file://CVE-2024-4467-0003.patch \
+ file://CVE-2024-4467-0004.patch \
+ file://CVE-2024-4467-0005.patch \
"
UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar"
new file mode 100644
@@ -0,0 +1,214 @@
+From 5cdbc87ab24a8cc4cf926158ec429d43d8a45f15 Mon Sep 17 00:00:00 2001
+From: Jon Maloy <jmaloy@redhat.com>
+Date: Wed, 5 Jun 2024 19:56:51 -0400
+Subject: [PATCH 1/5] qcow2: Don't open data_file with BDRV_O_NO_IO
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+RH-Author: Jon Maloy <jmaloy@redhat.com>
+RH-MergeRequest: 5: EMBARGOED CVE-2024-4467 for rhel-8.10.z (PRDSC)
+RH-Jira: RHEL-35616
+RH-CVE: CVE-2024-4467
+RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
+RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
+RH-Commit: [1/5] 2e72d21c14d86645cf68eec78f49d5cc5d77581f
+
+Conflicts: qcow2_do_open(): missing boolean ´open_data_file'.
+ We assume it to be true.
+
+commit f9843ce5c519901654a7d8ba43ee95ce25ca13c2
+Author: Kevin Wolf <kwolf@redhat.com>
+Date: Thu Apr 11 15:06:01 2024 +0200
+
+ qcow2: Don't open data_file with BDRV_O_NO_IO
+
+ One use case for 'qemu-img info' is verifying that untrusted images
+ don't reference an unwanted external file, be it as a backing file or an
+ external data file. To make sure that calling 'qemu-img info' can't
+ already have undesired side effects with a malicious image, just don't
+ open the data file at all with BDRV_O_NO_IO. If nothing ever tries to do
+ I/O, we don't need to have it open.
+
+ This changes the output of iotests case 061, which used 'qemu-img info'
+ to show that opening an image with an invalid data file fails. After
+ this patch, it succeeds. Replace this part of the test with a qemu-io
+ call, but keep the final 'qemu-img info' to show that the invalid data
+ file is correctly displayed in the output.
+
+ Signed-off-by: Kevin Wolf <kwolf@redhat.com>
+ Reviewed-by: Eric Blake <eblake@redhat.com>
+ Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+ Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
+ Upstream: N/A, embargoed
+ Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
+
+Signed-off-by: Jon Maloy <jmaloy@redhat.com>
+
+Upstream-Status: Backport [import from rhel8 qemu-kvm-6.2.0-50.module+el8.10.0+22027+db0a70a4.src.rpm
+Upstream commit https://gitlab.com/qemu-project/qemu/-/commit/bd385a5298d7062668e804d73944d52aec9549f1]
+CVE: CVE-2024-4467
+Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
+---
+ block/qcow2.c | 87 +++++++++++++++++++++++---------------
+ tests/qemu-iotests/061 | 6 ++-
+ tests/qemu-iotests/061.out | 8 +++-
+ 3 files changed, 62 insertions(+), 39 deletions(-)
+
+diff --git a/block/qcow2.c b/block/qcow2.c
+index d509016756..6ee1919612 100644
+--- a/block/qcow2.c
++++ b/block/qcow2.c
+@@ -1613,50 +1613,67 @@ 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 (flags & BDRV_O_NO_IO) {
++ /*
++ * Don't open the data file for 'qemu-img info' so that it can be used
++ * to verify that an untrusted qcow2 image doesn't refer to external
++ * files.
++ *
++ * Note: This still makes has_data_file() return true.
++ */
++ if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
++ s->data_file = NULL;
++ } else {
++ s->data_file = bs->file;
++ }
++ qdict_extract_subqdict(options, NULL, "data-file.");
++ qdict_del(options, "data-file");
++ } else {
++ /* 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;
++ }
+ }
+ }
+
+diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
+index 9507c223bd..6a5bd47efc 100755
+--- a/tests/qemu-iotests/061
++++ b/tests/qemu-iotests/061
+@@ -322,12 +322,14 @@ $QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
+ echo
+ _make_test_img -o "compat=1.1,data_file=$TEST_IMG.data" 64M
+ $QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
+-_img_info --format-specific
++$QEMU_IO -c "read 0 4k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
++$QEMU_IO -c "open -o data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" -c "read 0 4k" | _filter_qemu_io
+ TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
+
+ echo
+ $QEMU_IMG amend -o "data_file=" --image-opts "data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG"
+-_img_info --format-specific
++$QEMU_IO -c "read 0 4k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
++$QEMU_IO -c "open -o data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" -c "read 0 4k" | _filter_qemu_io
+ TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
+
+ echo
+diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
+index 7ecbd4dea8..99b2307a23 100644
+--- a/tests/qemu-iotests/061.out
++++ b/tests/qemu-iotests/061.out
+@@ -545,7 +545,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+ qemu-img: data-file can only be set for images that use an external data file
+
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
+-qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'foo': No such file or directory
++qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open 'foo': No such file or directory
++read 4096/4096 bytes at offset 0
++4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+ image: TEST_DIR/t.IMGFMT
+ file format: IMGFMT
+ virtual size: 64 MiB (67108864 bytes)
+@@ -560,7 +562,9 @@ Format specific information:
+ corrupt: false
+ extended l2: false
+
+-qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'data-file' is required for this image
++qemu-io: can't open device TEST_DIR/t.IMGFMT: 'data-file' is required for this image
++read 4096/4096 bytes at offset 0
++4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+ image: TEST_DIR/t.IMGFMT
+ file format: IMGFMT
+ virtual size: 64 MiB (67108864 bytes)
+--
+2.39.3
+
new file mode 100644
@@ -0,0 +1,73 @@
+From 3cb587f460ec432f329fb83df034bbb7e79e17aa Mon Sep 17 00:00:00 2001
+From: Jon Maloy <jmaloy@redhat.com>
+Date: Wed, 5 Jun 2024 19:56:51 -0400
+Subject: [PATCH 2/5] iotests/244: Don't store data-file with protocol in image
+
+RH-Author: Jon Maloy <jmaloy@redhat.com>
+RH-MergeRequest: 5: EMBARGOED CVE-2024-4467 for rhel-8.10.z (PRDSC)
+RH-Jira: RHEL-35616
+RH-CVE: CVE-2024-4467
+RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
+RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
+RH-Commit: [2/5] a422cfdba938e1bd857008ccbbddc695011ae0ff
+
+commit 92e00dab8be1570b13172353d77d2af44cb4e22b
+Author: Kevin Wolf <kwolf@redhat.com>
+Date: Thu Apr 25 14:49:40 2024 +0200
+
+ iotests/244: Don't store data-file with protocol in image
+
+ We want to disable filename parsing for data files because it's too easy
+ to abuse in malicious image files. Make the test ready for the change by
+ passing the data file explicitly in command line options.
+
+ Signed-off-by: Kevin Wolf <kwolf@redhat.com>
+ Reviewed-by: Eric Blake <eblake@redhat.com>
+ Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+ Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
+ Upstream: N/A, embargoed
+ Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
+
+Signed-off-by: Jon Maloy <jmaloy@redhat.com>
+
+Upstream-Status: Backport [import from rhel8 qemu-kvm-6.2.0-50.module+el8.10.0+22027+db0a70a4.src.rpm
+Upstream commit https://gitlab.com/qemu-project/qemu/-/commit/2eb42a728d27a43fdcad5f37d3f65706ce6deba5]
+CVE: CVE-2024-4467
+Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
+---
+ tests/qemu-iotests/244 | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
+index 3e61fa25bb..bb9cc6512f 100755
+--- a/tests/qemu-iotests/244
++++ b/tests/qemu-iotests/244
+@@ -215,9 +215,22 @@ $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
+ $QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
+
+ # blkdebug doesn't support copy offloading, so this tests the error path
+-$QEMU_IMG amend -f $IMGFMT -o "data_file=blkdebug::$TEST_IMG.data" "$TEST_IMG"
+-$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
+-$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
++test_img_with_blkdebug="json:{
++ 'driver': 'qcow2',
++ 'file': {
++ 'driver': 'file',
++ 'filename': '$TEST_IMG'
++ },
++ 'data-file': {
++ 'driver': 'blkdebug',
++ 'image': {
++ 'driver': 'file',
++ 'filename': '$TEST_IMG.data'
++ }
++ }
++}"
++$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$test_img_with_blkdebug"
++$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$test_img_with_blkdebug"
+
+ echo
+ echo "=== Flushing should flush the data file ==="
+--
+2.39.3
+
new file mode 100644
@@ -0,0 +1,76 @@
+From 59a84673079f9763e9507733e308442397aba703 Mon Sep 17 00:00:00 2001
+From: Jon Maloy <jmaloy@redhat.com>
+Date: Wed, 5 Jun 2024 19:56:51 -0400
+Subject: [PATCH 3/5] iotests/270: Don't store data-file with json: prefix in
+ image
+
+RH-Author: Jon Maloy <jmaloy@redhat.com>
+RH-MergeRequest: 5: EMBARGOED CVE-2024-4467 for rhel-8.10.z (PRDSC)
+RH-Jira: RHEL-35616
+RH-CVE: CVE-2024-4467
+RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
+RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
+RH-Commit: [3/5] ac08690fd3ea3af6e24b2f6a8beedcfe469917a8
+
+commit 705bcc2819ce8e0f8b9d660a93bc48de26413aec
+Author: Kevin Wolf <kwolf@redhat.com>
+Date: Thu Apr 25 14:49:40 2024 +0200
+
+ iotests/270: Don't store data-file with json: prefix in image
+
+ We want to disable filename parsing for data files because it's too easy
+ to abuse in malicious image files. Make the test ready for the change by
+ passing the data file explicitly in command line options.
+
+ Signed-off-by: Kevin Wolf <kwolf@redhat.com>
+ Reviewed-by: Eric Blake <eblake@redhat.com>
+ Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+ Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
+ Upstream: N/A, embargoed
+ Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
+
+Signed-off-by: Jon Maloy <jmaloy@redhat.com>
+
+Upstream-Status: Backport [import from rhel8 qemu-kvm-6.2.0-50.module+el8.10.0+22027+db0a70a4.src.rpm
+Upstream commit https://gitlab.com/qemu-project/qemu/-/commit/7e1110664ecbc4826f3c978ccb06b6c1bce823e6]
+CVE: CVE-2024-4467
+Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
+---
+ tests/qemu-iotests/270 | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/tests/qemu-iotests/270 b/tests/qemu-iotests/270
+index 74352342db..c37b674aa2 100755
+--- a/tests/qemu-iotests/270
++++ b/tests/qemu-iotests/270
+@@ -60,8 +60,16 @@ _make_test_img -o cluster_size=2M,data_file="$TEST_IMG.orig" \
+ # "write" 2G of data without using any space.
+ # (qemu-img create does not like it, though, because null-co does not
+ # support image creation.)
+-$QEMU_IMG amend -o data_file="json:{'driver':'null-co',,'size':'4294967296'}" \
+- "$TEST_IMG"
++test_img_with_null_data="json:{
++ 'driver': '$IMGFMT',
++ 'file': {
++ 'filename': '$TEST_IMG'
++ },
++ 'data-file': {
++ 'driver': 'null-co',
++ 'size':'4294967296'
++ }
++}"
+
+ # This gives us a range of:
+ # 2^31 - 512 + 768 - 1 = 2^31 + 255 > 2^31
+@@ -74,7 +82,7 @@ $QEMU_IMG amend -o data_file="json:{'driver':'null-co',,'size':'4294967296'}" \
+ # on L2 boundaries, we need large L2 tables; hence the cluster size of
+ # 2 MB. (Anything from 256 kB should work, though, because then one L2
+ # table covers 8 GB.)
+-$QEMU_IO -c "write 768 $((2 ** 31 - 512))" "$TEST_IMG" | _filter_qemu_io
++$QEMU_IO -c "write 768 $((2 ** 31 - 512))" "$test_img_with_null_data" | _filter_qemu_io
+
+ _check_test_img
+
+--
+2.39.3
+
new file mode 100644
@@ -0,0 +1,571 @@
+From 996680dd6d5afd51918e600126dbfed4dfe89e05 Mon Sep 17 00:00:00 2001
+From: Jon Maloy <jmaloy@redhat.com>
+Date: Sun, 9 Jun 2024 23:08:39 -0400
+Subject: [PATCH 4/5] block: introduce bdrv_open_file_child() helper
+
+RH-Author: Jon Maloy <jmaloy@redhat.com>
+RH-MergeRequest: 5: EMBARGOED CVE-2024-4467 for rhel-8.10.z (PRDSC)
+RH-Jira: RHEL-35616
+RH-CVE: CVE-2024-4467
+RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
+RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
+RH-Commit: [4/5] 9f582a9aff740eb9ec6f64bfec94854038d8545f
+
+Conflicts: - copy-before-write.c::cbw_copy() is an older version than
+ upstream, but introduction of the new function is
+ straight-forward.
+ - include/block/block-global-state.h doesn't exist in this
+ code version. Adding the prototype to
+ include/block/block.h instead.
+ - struct BlockDriver has no field 'filtered_child_is_backing'
+ We remove the corresponding assert() in the new function.
+
+commit 83930780325b144a5908c45b3957b9b6457b3831
+Author: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
+Date: Tue Jul 26 23:11:21 2022 +0300
+
+ block: introduce bdrv_open_file_child() helper
+
+ Almost all drivers call bdrv_open_child() similarly. Let's create a
+ helper for this.
+
+ The only not updated drivers that call bdrv_open_child() to set
+ bs->file are raw-format and snapshot-access:
+ raw-format sometimes want to have filtered child but
+ don't set drv->is_filter to true.
+ snapshot-access wants only DATA | PRIMARY
+
+ Possibly we should implement drv->is_filter_func() handler, to consider
+ raw-format as filter when it works as filter.. But it's another story.
+
+ Note also, that we decrease assignments to bs->file in code: it helps
+ us restrict modifying this field in further commit.
+
+ Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
+ Reviewed-by: Hanna Reitz <hreitz@redhat.com>
+ Message-Id: <20220726201134.924743-3-vsementsov@yandex-team.ru>
+ Reviewed-by: Kevin Wolf <kwolf@redhat.com>
+ Signed-off-by: Kevin Wolf <kwolf@redhat.com>
+
+Signed-off-by: Jon Maloy <jmaloy@redhat.com>
+
+Upstream-Status: Backport [import from rhel8 qemu-kvm-6.2.0-50.module+el8.10.0+22027+db0a70a4.src.rpm
+Upstream commit https://gitlab.com/qemu-project/qemu/-/commit/83930780325b144a5908c45b3957b9b6457b3831]
+CVE: CVE-2024-4467
+Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
+---
+ block.c | 18 ++++++++++++++++++
+ block/blkdebug.c | 9 +++------
+ block/blklogwrites.c | 7 ++-----
+ block/blkreplay.c | 7 ++-----
+ block/blkverify.c | 9 +++------
+ block/bochs.c | 7 +++----
+ block/cloop.c | 7 +++----
+ block/copy-before-write.c | 9 ++++-----
+ block/copy-on-read.c | 9 ++++-----
+ block/crypto.c | 11 ++++++-----
+ block/dmg.c | 7 +++----
+ block/filter-compress.c | 8 +++-----
+ block/parallels.c | 7 +++----
+ block/preallocate.c | 9 ++++-----
+ block/qcow.c | 6 ++----
+ block/qcow2.c | 8 ++++----
+ block/qed.c | 8 ++++----
+ block/replication.c | 8 +++-----
+ block/throttle.c | 8 +++-----
+ block/vdi.c | 7 +++----
+ block/vhdx.c | 7 +++----
+ block/vmdk.c | 7 +++----
+ block/vpc.c | 7 +++----
+ include/block/block.h | 3 +++
+ 24 files changed, 92 insertions(+), 101 deletions(-)
+
+diff --git a/block.c b/block.c
+index 0ac5b163d2..889f878565 100644
+--- a/block.c
++++ b/block.c
+@@ -3546,6 +3546,24 @@ BdrvChild *bdrv_open_child(const char *filename,
+ errp);
+ }
+
++/*
++ * Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
++ */
++int bdrv_open_file_child(const char *filename,
++ QDict *options, const char *bdref_key,
++ BlockDriverState *parent, Error **errp)
++{
++ BdrvChildRole role;
++
++ role = parent->drv->is_filter ?
++ (BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY) : BDRV_CHILD_IMAGE;
++
++ parent->file = bdrv_open_child(filename, options, bdref_key, parent,
++ &child_of_bds, role, false, errp);
++
++ return parent->file ? 0 : -EINVAL;
++}
++
+ /*
+ * TODO Future callers may need to specify parent/child_class in order for
+ * option inheritance to work. Existing callers use it for the root node.
+diff --git a/block/blkdebug.c b/block/blkdebug.c
+index bbf2948703..5fcfc8ac6f 100644
+--- a/block/blkdebug.c
++++ b/block/blkdebug.c
+@@ -503,12 +503,9 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
+ }
+
+ /* Open the image file */
+- bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
+- bs, &child_of_bds,
+- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+- false, errp);
+- if (!bs->file) {
+- ret = -EINVAL;
++ ret = bdrv_open_file_child(qemu_opt_get(opts, "x-image"), options, "image",
++ bs, errp);
++ if (ret < 0) {
+ goto out;
+ }
+
+diff --git a/block/blklogwrites.c b/block/blklogwrites.c
+index f7a251e91f..f66a617eb3 100644
+--- a/block/blklogwrites.c
++++ b/block/blklogwrites.c
+@@ -155,11 +155,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
+ }
+
+ /* Open the file */
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, false,
+- errp);
+- if (!bs->file) {
+- ret = -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
+ goto fail;
+ }
+
+diff --git a/block/blkreplay.c b/block/blkreplay.c
+index dcbe780ddb..76a0b8d12a 100644
+--- a/block/blkreplay.c
++++ b/block/blkreplay.c
+@@ -26,11 +26,8 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
+ int ret;
+
+ /* Open the image file */
+- bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds,
+- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+- false, errp);
+- if (!bs->file) {
+- ret = -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "image", bs, errp);
++ if (ret < 0) {
+ goto fail;
+ }
+
+diff --git a/block/blkverify.c b/block/blkverify.c
+index d1facf5ba9..920e891684 100644
+--- a/block/blkverify.c
++++ b/block/blkverify.c
+@@ -121,12 +121,9 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
+ }
+
+ /* Open the raw file */
+- bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw",
+- bs, &child_of_bds,
+- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+- false, errp);
+- if (!bs->file) {
+- ret = -EINVAL;
++ ret = bdrv_open_file_child(qemu_opt_get(opts, "x-raw"), options, "raw",
++ bs, errp);
++ if (ret < 0) {
+ goto fail;
+ }
+
+diff --git a/block/bochs.c b/block/bochs.c
+index 4d68658087..b2dc06bbfd 100644
+--- a/block/bochs.c
++++ b/block/bochs.c
+@@ -110,10 +110,9 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
+ return ret;
+ }
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
+diff --git a/block/cloop.c b/block/cloop.c
+index b8c6d0eccd..bee87da173 100644
+--- a/block/cloop.c
++++ b/block/cloop.c
+@@ -71,10 +71,9 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
+ return ret;
+ }
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ /* read header */
+diff --git a/block/copy-before-write.c b/block/copy-before-write.c
+index c30a5ff8de..8aa2cb6a85 100644
+--- a/block/copy-before-write.c
++++ b/block/copy-before-write.c
+@@ -150,12 +150,11 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
+ {
+ BDRVCopyBeforeWriteState *s = bs->opaque;
+ BdrvDirtyBitmap *copy_bitmap;
++ int ret;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+- false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ s->target = bdrv_open_child(NULL, options, "target", bs, &child_of_bds,
+diff --git a/block/copy-on-read.c b/block/copy-on-read.c
+index 1fc7fb3333..815ac1d835 100644
+--- a/block/copy-on-read.c
++++ b/block/copy-on-read.c
+@@ -41,12 +41,11 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
+ BDRVStateCOR *state = bs->opaque;
+ /* Find a bottom node name, if any */
+ const char *bottom_node = qdict_get_try_str(options, "bottom");
++ int ret;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+- false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ bs->supported_read_flags = BDRV_REQ_PREFETCH;
+diff --git a/block/crypto.c b/block/crypto.c
+index c8ba4681e2..abfce39230 100644
+--- a/block/crypto.c
++++ b/block/crypto.c
+@@ -260,15 +260,14 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
+ {
+ BlockCrypto *crypto = bs->opaque;
+ QemuOpts *opts = NULL;
+- int ret = -EINVAL;
++ int ret;
+ QCryptoBlockOpenOptions *open_opts = NULL;
+ unsigned int cflags = 0;
+ QDict *cryptoopts = NULL;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ bs->supported_write_flags = BDRV_REQ_FUA &
+@@ -276,6 +275,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
+
+ opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
+ if (!qemu_opts_absorb_qdict(opts, options, errp)) {
++ ret = -EINVAL;
+ goto cleanup;
+ }
+
+@@ -284,6 +284,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
+
+ open_opts = block_crypto_open_opts_init(cryptoopts, errp);
+ if (!open_opts) {
++ ret = -EINVAL;
+ goto cleanup;
+ }
+
+diff --git a/block/dmg.c b/block/dmg.c
+index 447901fbb8..38c363dd39 100644
+--- a/block/dmg.c
++++ b/block/dmg.c
+@@ -439,10 +439,9 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
+ return ret;
+ }
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ block_module_load_one("dmg-bz2");
+diff --git a/block/filter-compress.c b/block/filter-compress.c
+index d5be538619..305716c86c 100644
+--- a/block/filter-compress.c
++++ b/block/filter-compress.c
+@@ -30,11 +30,9 @@
+ static int compress_open(BlockDriverState *bs, QDict *options, int flags,
+ Error **errp)
+ {
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+- false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ int ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {
+diff --git a/block/parallels.c b/block/parallels.c
+index 6ebad2a2bb..ed4debd899 100644
+--- a/block/parallels.c
++++ b/block/parallels.c
+@@ -735,10 +735,9 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
+ Error *local_err = NULL;
+ char *buf;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
+diff --git a/block/preallocate.c b/block/preallocate.c
+index 1d4233f730..332408bdc9 100644
+--- a/block/preallocate.c
++++ b/block/preallocate.c
+@@ -134,6 +134,7 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
+ Error **errp)
+ {
+ BDRVPreallocateState *s = bs->opaque;
++ int ret;
+
+ /*
+ * s->data_end and friends should be initialized on permission update.
+@@ -141,11 +142,9 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
+ */
+ s->file_end = s->zero_start = s->data_end = -EINVAL;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+- false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) {
+diff --git a/block/qcow.c b/block/qcow.c
+index c39940f33e..544a17261f 100644
+--- a/block/qcow.c
++++ b/block/qcow.c
+@@ -120,10 +120,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
+ qdict_extract_subqdict(options, &encryptopts, "encrypt.");
+ encryptfmt = qdict_get_try_str(encryptopts, "format");
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- ret = -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
+ goto fail;
+ }
+
+diff --git a/block/qcow2.c b/block/qcow2.c
+index 6ee1919612..29ea157e6b 100644
+--- a/block/qcow2.c
++++ b/block/qcow2.c
+@@ -1907,11 +1907,11 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
+ .errp = errp,
+ .ret = -EINPROGRESS
+ };
++ int ret;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ /* Initialise locks */
+diff --git a/block/qed.c b/block/qed.c
+index 558d3646c4..e3b06a3d00 100644
+--- a/block/qed.c
++++ b/block/qed.c
+@@ -558,11 +558,11 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
+ .errp = errp,
+ .ret = -EINPROGRESS
+ };
++ int ret;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ bdrv_qed_init_state(bs);
+diff --git a/block/replication.c b/block/replication.c
+index 55c8f894aa..2f17397764 100644
+--- a/block/replication.c
++++ b/block/replication.c
+@@ -88,11 +88,9 @@ static int replication_open(BlockDriverState *bs, QDict *options,
+ const char *mode;
+ const char *top_id;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+- false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ ret = -EINVAL;
+diff --git a/block/throttle.c b/block/throttle.c
+index 6e8d52fa24..4fb5798c27 100644
+--- a/block/throttle.c
++++ b/block/throttle.c
+@@ -78,11 +78,9 @@ static int throttle_open(BlockDriverState *bs, QDict *options,
+ char *group;
+ int ret;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+- false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+ bs->supported_write_flags = bs->file->bs->supported_write_flags |
+ BDRV_REQ_WRITE_UNCHANGED;
+diff --git a/block/vdi.c b/block/vdi.c
+index bdc58d726e..c50c0ed61f 100644
+--- a/block/vdi.c
++++ b/block/vdi.c
+@@ -376,10 +376,9 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
+ int ret;
+ QemuUUID uuid_link, uuid_parent;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ logout("\n");
+diff --git a/block/vhdx.c b/block/vhdx.c
+index 356ec4c455..e7d6d7509a 100644
+--- a/block/vhdx.c
++++ b/block/vhdx.c
+@@ -996,10 +996,9 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
+ uint64_t signature;
+ Error *local_err = NULL;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ s->bat = NULL;
+diff --git a/block/vmdk.c b/block/vmdk.c
+index 0dfab6e941..7d7e56b36c 100644
+--- a/block/vmdk.c
++++ b/block/vmdk.c
+@@ -1262,10 +1262,9 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
+ BDRVVmdkState *s = bs->opaque;
+ uint32_t magic;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ buf = vmdk_read_desc(bs->file, 0, errp);
+diff --git a/block/vpc.c b/block/vpc.c
+index 297a26262a..430cab1cbb 100644
+--- a/block/vpc.c
++++ b/block/vpc.c
+@@ -232,10 +232,9 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
+ int ret;
+ int64_t bs_size;
+
+- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+- BDRV_CHILD_IMAGE, false, errp);
+- if (!bs->file) {
+- return -EINVAL;
++ ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
++ if (ret < 0) {
++ return ret;
+ }
+
+ opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
+diff --git a/include/block/block.h b/include/block/block.h
+index e5dd22b034..f885f113ef 100644
+--- a/include/block/block.h
++++ b/include/block/block.h
+@@ -376,6 +376,9 @@ BdrvChild *bdrv_open_child(const char *filename,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
+ bool allow_none, Error **errp);
++int bdrv_open_file_child(const char *filename,
++ QDict *options, const char *bdref_key,
++ BlockDriverState *parent, Error **errp);
+ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
+ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
+ Error **errp);
+--
+2.39.3
+
new file mode 100644
@@ -0,0 +1,265 @@
+From c4ba1f1755031a0ac2f600ed8c17e7dcb6b2b857 Mon Sep 17 00:00:00 2001
+From: Jon Maloy <jmaloy@redhat.com>
+Date: Wed, 5 Jun 2024 19:56:51 -0400
+Subject: [PATCH 5/5] block: Parse filenames only when explicitly requested
+
+RH-Author: Jon Maloy <jmaloy@redhat.com>
+RH-MergeRequest: 5: EMBARGOED CVE-2024-4467 for rhel-8.10.z (PRDSC)
+RH-Jira: RHEL-35616
+RH-CVE: CVE-2024-4467
+RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
+RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
+RH-Commit: [5/5] a3e197add64fc6950c4ac576e34d833dfae7ee34
+
+Conflicts: - brdv_open_child_common(): bdrv_graph_wrlock/unlock()
+ don't exist in this code version. We ignore them.
+ bdrv_open_inherit(): no_coroutine_fn/GRAPH_UNLOCKED
+ doesn't exist. We ignore it.
+ - Changes to bdrv_open_file_child() didn't apply cleanly,
+ but fixing it is straight-forward.
+ - GLOBAL_STATE_CODE() not present in this code. Ignoring it.
+ - bdrv_open_file_child(): Need to continue setting of
+ parent->file.
+
+commit f44c2941d4419e60f16dea3e9adca164e75aa78d
+Author: Kevin Wolf <kwolf@redhat.com>
+Date: Thu Apr 25 14:56:02 2024 +0200
+
+ block: Parse filenames only when explicitly requested
+
+ When handling image filenames from legacy options such as -drive or from
+ tools, these filenames are parsed for protocol prefixes, including for
+ the json:{} pseudo-protocol.
+
+ This behaviour is intended for filenames that come directly from the
+ command line and for backing files, which may come from the image file
+ itself. Higher level management tools generally take care to verify that
+ untrusted images don't contain a bad (or any) backing file reference;
+ 'qemu-img info' is a suitable tool for this.
+
+ However, for other files that can be referenced in images, such as
+ qcow2 data files or VMDK extents, the string from the image file is
+ usually not verified by management tools - and 'qemu-img info' wouldn't
+ be suitable because in contrast to backing files, it already opens these
+ other referenced files. So here the string should be interpreted as a
+ literal local filename. More complex configurations need to be specified
+ explicitly on the command line or in QMP.
+
+ This patch changes bdrv_open_inherit() so that it only parses filenames
+ if a new parameter parse_filename is true. It is set for the top level
+ in bdrv_open(), for the file child and for the backing file child. All
+ other callers pass false and disable filename parsing this way.
+
+ Signed-off-by: Kevin Wolf <kwolf@redhat.com>
+ Reviewed-by: Eric Blake <eblake@redhat.com>
+ Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+ Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
+ Upstream: N/A, embargoed
+ Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
+
+Signed-off-by: Jon Maloy <jmaloy@redhat.com>
+
+Upstream-Status: Backport [import from rhel8 qemu-kvm-6.2.0-50.module+el8.10.0+22027+db0a70a4.src.rpm
+Upstream commit https://gitlab.com/qemu-project/qemu/-/commit/7ead946998610657d38d1a505d5f25300d4ca613]
+CVE: CVE-2024-4467
+Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
+---
+ block.c | 81 +++++++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 56 insertions(+), 25 deletions(-)
+
+diff --git a/block.c b/block.c
+index 889f878565..ddebf50efa 100644
+--- a/block.c
++++ b/block.c
+@@ -82,6 +82,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
+ BlockDriverState *parent,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
++ bool parse_filename,
+ Error **errp);
+
+ static bool bdrv_recurse_has_child(BlockDriverState *bs,
+@@ -1926,7 +1927,8 @@ static void parse_json_protocol(QDict *options, const char **pfilename,
+ * block driver has been specified explicitly.
+ */
+ static int bdrv_fill_options(QDict **options, const char *filename,
+- int *flags, Error **errp)
++ int *flags, bool allow_parse_filename,
++ Error **errp)
+ {
+ const char *drvname;
+ bool protocol = *flags & BDRV_O_PROTOCOL;
+@@ -1966,7 +1968,7 @@ static int bdrv_fill_options(QDict **options, const char *filename,
+ if (protocol && filename) {
+ if (!qdict_haskey(*options, "filename")) {
+ qdict_put_str(*options, "filename", filename);
+- parse_filename = true;
++ parse_filename = allow_parse_filename;
+ } else {
+ error_setg(errp, "Can't specify 'file' and 'filename' options at "
+ "the same time");
+@@ -3439,7 +3441,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
+ }
+
+ backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs,
+- &child_of_bds, bdrv_backing_role(bs), errp);
++ &child_of_bds, bdrv_backing_role(bs), true,
++ errp);
+ if (!backing_hd) {
+ bs->open_flags |= BDRV_O_NO_BACKING;
+ error_prepend(errp, "Could not open backing file: ");
+@@ -3472,7 +3475,8 @@ free_exit:
+ static BlockDriverState *
+ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
+ BlockDriverState *parent, const BdrvChildClass *child_class,
+- BdrvChildRole child_role, bool allow_none, Error **errp)
++ BdrvChildRole child_role, bool allow_none,
++ bool parse_filename, Error **errp)
+ {
+ BlockDriverState *bs = NULL;
+ QDict *image_options;
+@@ -3503,7 +3507,8 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
+ }
+
+ bs = bdrv_open_inherit(filename, reference, image_options, 0,
+- parent, child_class, child_role, errp);
++ parent, child_class, child_role, parse_filename,
++ errp);
+ if (!bs) {
+ goto done;
+ }
+@@ -3513,6 +3518,29 @@ done:
+ return bs;
+ }
+
++static BdrvChild *bdrv_open_child_common(const char *filename,
++ QDict *options, const char *bdref_key,
++ BlockDriverState *parent,
++ const BdrvChildClass *child_class,
++ BdrvChildRole child_role,
++ bool allow_none, bool parse_filename,
++ Error **errp)
++{
++ BlockDriverState *bs;
++ BdrvChild *child;
++
++ bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
++ child_role, allow_none, parse_filename, errp);
++ if (bs == NULL) {
++ return NULL;
++ }
++
++ child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
++ errp);
++
++ return child;
++}
++
+ /*
+ * Opens a disk image whose options are given as BlockdevRef in another block
+ * device's options.
+@@ -3534,20 +3562,17 @@ BdrvChild *bdrv_open_child(const char *filename,
+ BdrvChildRole child_role,
+ bool allow_none, Error **errp)
+ {
+- BlockDriverState *bs;
+-
+- bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
+- child_role, allow_none, errp);
+- if (bs == NULL) {
+- return NULL;
+- }
+-
+- return bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
+- errp);
++ return bdrv_open_child_common(filename, options, bdref_key, parent,
++ child_class, child_role, allow_none, false,
++ errp);
+ }
+
+ /*
+- * Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
++ * This does mostly the same as bdrv_open_child(), but for opening the primary
++ * child of a node. A notable difference from bdrv_open_child() is that it
++ * enables filename parsing for protocol names (including json:).
++ *
++ * @parent can move to a different AioContext in this function.
+ */
+ int bdrv_open_file_child(const char *filename,
+ QDict *options, const char *bdref_key,
+@@ -3558,8 +3583,9 @@ int bdrv_open_file_child(const char *filename,
+ role = parent->drv->is_filter ?
+ (BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY) : BDRV_CHILD_IMAGE;
+
+- parent->file = bdrv_open_child(filename, options, bdref_key, parent,
+- &child_of_bds, role, false, errp);
++ parent->file = bdrv_open_child_common(filename, options, bdref_key, parent,
++ &child_of_bds, role, false, true,
++ errp);
+
+ return parent->file ? 0 : -EINVAL;
+ }
+@@ -3599,7 +3625,8 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
+
+ }
+
+- bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, errp);
++ bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, false,
++ errp);
+ obj = NULL;
+ qobject_unref(obj);
+ visit_free(v);
+@@ -3690,6 +3717,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
+ BlockDriverState *parent,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
++ bool parse_filename,
+ Error **errp)
+ {
+ int ret;
+@@ -3733,9 +3761,11 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
+ }
+
+ /* json: syntax counts as explicit options, as if in the QDict */
+- parse_json_protocol(options, &filename, &local_err);
+- if (local_err) {
+- goto fail;
++ if (parse_filename) {
++ parse_json_protocol(options, &filename, &local_err);
++ if (local_err) {
++ goto fail;
++ }
+ }
+
+ bs->explicit_options = qdict_clone_shallow(options);
+@@ -3760,7 +3790,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
+ parent->open_flags, parent->options);
+ }
+
+- ret = bdrv_fill_options(&options, filename, &flags, &local_err);
++ ret = bdrv_fill_options(&options, filename, &flags, parse_filename,
++ &local_err);
+ if (ret < 0) {
+ goto fail;
+ }
+@@ -3829,7 +3860,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
+
+ file_bs = bdrv_open_child_bs(filename, options, "file", bs,
+ &child_of_bds, BDRV_CHILD_IMAGE,
+- true, &local_err);
++ true, true, &local_err);
+ if (local_err) {
+ goto fail;
+ }
+@@ -3974,7 +4005,7 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
+ QDict *options, int flags, Error **errp)
+ {
+ return bdrv_open_inherit(filename, reference, options, flags, NULL,
+- NULL, 0, errp);
++ NULL, 0, true, errp);
+ }
+
+ /* Return true if the NULL-terminated @list contains @str */
+--
+2.39.3
+