With BDRV_O_NO_IO, we suppress opening data-file to prevent opening
unchecked paths through `qemu-img info`. However, a future commit will
make qcow2_co_create() pass BDRV_O_NO_IO for the new image if possible,
and then we need data-file attached to be able to query its size.
qcow2_co_create() already has the data-file open, so it specifies it by
node name; and if we get the data-file by node name, there is no
security risk attaching it because it is already open.
So check whether the data-file option is a string, i.e. a node name, and
if so, allow attaching it despite BDRV_O_NO_IO.
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
---
block/qcow2.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/block/qcow2.c b/block/qcow2.c
index cf9189b829..edf18630f6 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1410,6 +1410,7 @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
uint64_t ext_end;
uint64_t l1_vm_state_index;
bool update_header = false;
+ bool suppress_data_file = false;
ret = bdrv_co_pread(bs->file, 0, sizeof(header), &header, 0);
if (ret < 0) {
@@ -1719,14 +1720,23 @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
- if (open_data_file && (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.
- */
+ /*
+ * 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.
+ *
+ * Exception: If the data-file option is a node name, attaching that
+ * node will not open a new file, so cannot pose a security risk.
+ *
+ * Note: This still makes has_data_file() return true.
+ */
+ if (flags & BDRV_O_NO_IO) {
+ QObject *data_file = qdict_get(options, "data-file");
+ suppress_data_file =
+ !data_file || qobject_type(data_file) != QTYPE_QSTRING;
+ }
+
+ if (open_data_file && suppress_data_file) {
if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
s->data_file = NULL;
} else {
--
2.53.0