I spent a couple hours today debugging a bug in an older branch of libvirt (0.10.2) - one where libvirt only knew how to parse version 2 qcow2 images. Alas, that version of libvirt can be coerced into reading the header of a random file under the assumption that it is qcow2 data, and where it tries to find the backing format information in the header extensions without first validating that the file format actually matches qcow2 (that is, it looks for header extensions starting at offset 72 without first checking the version field (bytes 4-7) contains 2). So far, we've been lucky: since libvirt is trying to parse 72-75 as a version 2 extension header magic number, and the number is stored in big endian format, we end up reading the first 4 bytes of the version 3 incompatible_features field, which so far are always 0 (we don't have that many incompatible features yet), and that happens to be the magic number for end of extension headers; and thus libvirt quit trying to look for any further extension headers. Furthermore, since libvirt already refuses to probe backing file format unless explicitly allowed by user action (since mis-probing a raw file is CVE-worthy if done automatically), the damage stopped there, and the worst I could do (without intentionally bypassing the CVE safety valve) was fail a test in the libvirt testsuite when using version 3 files. But it DOES mean that libvirt fails to find the backing header format extension of a v3 file, even when one is present, because libvirt fails to start looking at the right offset. But it does raise a question: What happens if we eventually DO reach bit 32, so that bytes 72-75 is no longer all 0s and therefore no longer the end-of-extension marker? It might be possible to write a file that has one interpretation as a valid qcow2v3, while having a different interpretation by the older libvirt, such that libvirt tries to treat a backing file as an incorrect format if it is probing. Is it worth tweaking docs/specs/qcow2.txt to permanently change the incompatible_features field to be 4 bytes (76-79) and mandate that bytes 72-75 always be 0, as a conservative way to prevent other misbehavior of programs like libvirt 0.10.2 that have code paths that don't correctly validate for version 2 files? And if we ever really did hit a situation of having 31 or more incompatible features, I could envision using bit 31 as an incompatible_feature witness that tells new enough qemu to look at some other offset for remaining feature bits (thankfully, the semantics of the incompatible_feature field mean that older qemu that honors version 3 formats will reject a file with incompatible_feature bit 31 set), so this is no real loss in the number of potential incompatible features being added. If we had a time machine, I would suggest that we change 72-75 to have constant contents as a new magic number, and 76-79 encode the length of the remaining header, and delay the location of incompatible_features into the remaining header; such that this situation of libvirt looking for extensions would still find known could have still found the backing file format extension header. But that ship has sailed - all we can do now is decide to encode 72-75 as permanent 0s. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Attachment:
signature.asc
Description: OpenPGP digital signature
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list