On Sat, Feb 22, 2020 at 05:23:41 -0600, Eric Blake wrote: > Creating an image that requires format probing of the backing image is > inherently unsafe (we've had several CVEs over the years based on > probes leaking information to the guest on a subsequent boot). If our > probing algorithm ever changes, or if other tools like libvirt > determine a different probe result than we do, then subsequent use of > that backing file under a different format will present corrupted data > to the guest. Start a deprecation clock so that future qemu-img can > refuse to create unsafe backing chains that would rely on probing. > > However, there is one time where probing is safe: when we first create > an image, no guest has yet used the new image, so as long as we record > what we probed, all future uses of the image will see the same data - I disagree. If you are creating an overlay on top of an existing image it's not safe to probe the format any more generally. (obviously you'd have to trust the image and express the trust somehow) The image may have been used in a VM as raw and that means that the VM might have recorded a valid qcow2 header into it. Creating the overlay with probing would legitimize this. Let's assume we have a malicious image written by the guest but we simulate it by: $ qemu-img create -f qcow2 -F raw -b /etc/passwd /tmp/malicious Formatting '/tmp/malicious', fmt=qcow2 size=2560 backing_file=/etc/passwd backing_fmt=raw cluster_size=65536 lazy_refcounts=off refcount_bits=16 Now we want to create an overlay. a) without this patchset: $ qemu-img create -f qcow2 -b /tmp/malicious /tmp/pre-patch.qcow2 Formatting '/tmp/pre-patch.qcow2', fmt=qcow2 size=2560 backing_file=/tmp/malicious cluster_size=65536 lazy_refcounts=off refcount_bits=16 $ qemu-img info /tmp/pre-patch.qcow2 image: /tmp/pre-patch.qcow2 file format: qcow2 virtual size: 2.5 KiB (2560 bytes) disk size: 196 KiB cluster_size: 65536 backing file: /tmp/malicious Format specific information: compat: 1.1 lazy refcounts: false refcount bits: 16 corrupt: false There's no 'backing file format'. When used by libvirt we'd not allow the VM to touch the backing file of /tmp/malicious in pre-blockdev era and in libvirt-6.0 we'd report an error right away. b) Now with this patchset: $ ./qemu-img create -f qcow2 -b /tmp/malicious /tmp/post-patch.qcow2 qemu-img: warning: Deprecated use of non-raw backing file without explicit backing format, using detected format of qcow2 Formatting '/tmp/post-patch.qcow2', fmt=qcow2 size=2560 backing_file=/tmp/malicious backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 $ qemu-img info /tmp/post-patch.qcow2 image: /tmp/post-patch.qcow2 file format: qcow2 virtual size: 2.5 KiB (2560 bytes) disk size: 196 KiB cluster_size: 65536 backing file: /tmp/malicious backing file format: qcow2 Format specific information: compat: 1.1 lazy refcounts: false refcount bits: 16 corrupt: false You now get a warning, but "backing file format" is now recorded in the overlay. Now this is WAY worse than it was before. The overlay now legitimizes the format recorded by the malicious guest which circumvents libvirt's protections. The warning is very easy to miss, and if you run it in scripts you might never get to see it. We can't allow that. > so the code now records the probe results as if the user had passed > -F. When this happens, it is unconditionally safe to record a probe > of 'raw', but any other probe is still worth warning the user in case While it's safe I don't think it should be encouraged. IMO -F should be made mandatory with -b. > our probe differed from their expectations. Similarly, if the backing > file name uses the json: psuedo-protocol, the backing name includes > the format. Not necessarily. The backing store string can be e.g.: $ ./qemu-img create -f qcow1 -b 'json:{"driver":"file","filename":"/tmp/malicious"}' /tmp/json.qcow2 Formatting '/tmp/json.qcow1', fmt=qcow2 size=197120 backing_file=json:{"driver":"file",,"filename":"/tmp/malicious"} cluster_size=65536 lazy_refcounts=off refcount_bits=16 $ qemu-img info /tmp/json.qcow1 image: /tmp/json.qcow1 file format: qcow1 virtual size: 191 KiB (197120 bytes) disk size: 195 KiB cluster_size: 65535 backing file: json:{"driver":"file","filename":"/tmp/malicious"} Format specific information: compat: 0.1 lazy refcounts: false refcount bits: 15 corrupt: false Now this has the old semantics but we didn't even get the warning. But at least the backing file format is not written into the overlay. > iotest 114 specifically wants to create an unsafe image for later > amendment rather than defaulting to our new default of recording a > probed format, so it needs an update. > > Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> > --- > block.c | 17 ++++++++++++++++- > qemu-deprecated.texi | 12 ++++++++++++ > qemu-img.c | 8 +++++++- > tests/qemu-iotests/114 | 4 ++-- > tests/qemu-iotests/114.out | 1 + > 5 files changed, 38 insertions(+), 4 deletions(-) > > diff --git a/block.c b/block.c > index 695decbfd7b7..6595683ac52a 100644 > --- a/block.c > +++ b/block.c > @@ -6013,6 +6013,15 @@ void bdrv_img_create(const char *filename, const char *fmt, > "Could not open backing image to determine size.\n"); > goto out; > } else { > + if (!backing_fmt && !strstart(backing_file, "json:", NULL)) { > + backing_fmt = bs->drv->format_name; > + qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, backing_fmt, NULL); We must never write the detected format into the overlay. Not even when we print a warning. This can legitimize a malicious file if the user mises the warning.