summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Thode <prometheanfire@gentoo.org>2016-01-07 11:55:40 -0600
committerMatthew Thode <prometheanfire@gentoo.org>2016-01-07 11:55:40 -0600
commit82b087e56b85822daadc9457c90a1c3b1b0a4da0 (patch)
treedd43baf09e68a16a63dc3f3d0ea87eb3a3d51317 /sys-cluster/nova/files
parentmedia-radio/svxlink: Version bump (bug #569512) (diff)
downloadgentoo-82b087e56b85822daadc9457c90a1c3b1b0a4da0.tar.gz
gentoo-82b087e56b85822daadc9457c90a1c3b1b0a4da0.tar.bz2
gentoo-82b087e56b85822daadc9457c90a1c3b1b0a4da0.zip
sys-cluster/nova: fixing CVE-2015-7548
Package-Manager: portage-2.2.26
Diffstat (limited to 'sys-cluster/nova/files')
-rw-r--r--sys-cluster/nova/files/cve-2015-7548-stable-liberty-0001.patch267
-rw-r--r--sys-cluster/nova/files/cve-2015-7548-stable-liberty-0002.patch168
-rw-r--r--sys-cluster/nova/files/cve-2015-7548-stable-liberty-0003.patch171
3 files changed, 606 insertions, 0 deletions
diff --git a/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0001.patch b/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0001.patch
new file mode 100644
index 000000000000..9f2429df1abc
--- /dev/null
+++ b/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0001.patch
@@ -0,0 +1,267 @@
+From f41488f828fda1370e1b017503711248a810d432 Mon Sep 17 00:00:00 2001
+From: Matthew Booth <mbooth@redhat.com>
+Date: Wed, 9 Dec 2015 15:36:32 +0000
+Subject: [PATCH 1/3] Fix format detection in libvirt snapshot
+
+The libvirt driver was using automatic format detection during
+snapshot for disks stored on the local filesystem. This opened an
+exploit if nova was configured to use local file storage, and
+additionally to store those files in raw format by specifying
+use_cow_images = False in nova.conf. An authenticated user could write
+a qcow2 header to their guest image with a backing file on the host.
+libvirt.utils.get_disk_type() would then misdetect the type of this
+image as qcow2 and pass this to the Qcow2 image backend, whose
+snapshot_extract method interprets the image as qcow2 and writes the
+backing file to glance. The authenticated user can then download the
+host file from glance.
+
+This patch makes 2 principal changes. libvirt.utils.get_disk_type,
+which ought to be removed entirely as soon as possible, is updated to
+no longer do format detection if the format can't be determined from
+the path. Its name is changed to get_disk_type_from_path to reflect
+its actual function.
+
+libvirt.utils.find_disk is updated to return both the path and format
+of the root disk, rather than just the path. This is the most reliable
+source of this information, as it reflects the actual format in use.
+The previous format detection function of get_disk_type is replaced by
+the format taken from libvirt.
+
+We replace a call to get_disk_type in _rebase_with_qemu_img with an
+explicit call to qemu_img_info, as the other behaviour of
+get_disk_type was not relevant in this context. qemu_img_info is safe
+from the backing file exploit when called on a file known to be a
+qcow2 image. As the file in this context is a volume snapshot, this is
+a safe use.
+
+(cherry picked from commit c69fbad4860a1ce931d80f3f0ce0f90da29e8e5f)
+
+ Conflicts:
+ nova/tests/unit/virt/libvirt/test_driver.py
+ nova/tests/unit/virt/libvirt/test_utils.py
+ nova/virt/libvirt/driver.py
+ nova/virt/libvirt/utils.py
+
+ Most about method _rebase_with_qemu_img which does not exist.
+
+Partial-Bug: #1524274
+Change-Id: I94c1c0d26215c061f71c3f95e1a6bf3a58fa19ea
+---
+ nova/tests/unit/virt/libvirt/fake_libvirt_utils.py | 10 +++--
+ nova/tests/unit/virt/libvirt/test_utils.py | 44 +++-------------------
+ nova/virt/libvirt/driver.py | 25 +++++++++---
+ nova/virt/libvirt/utils.py | 26 ++++++++++---
+ 4 files changed, 51 insertions(+), 54 deletions(-)
+
+diff --git a/nova/tests/unit/virt/libvirt/fake_libvirt_utils.py b/nova/tests/unit/virt/libvirt/fake_libvirt_utils.py
+index 302ccee..52d1e85 100644
+--- a/nova/tests/unit/virt/libvirt/fake_libvirt_utils.py
++++ b/nova/tests/unit/virt/libvirt/fake_libvirt_utils.py
+@@ -40,7 +40,9 @@ def get_disk_backing_file(path):
+ return disk_backing_files.get(path, None)
+
+
+-def get_disk_type(path):
++def get_disk_type_from_path(path):
++ if disk_type in ('raw', 'qcow2'):
++ return None
+ return disk_type
+
+
+@@ -99,11 +101,11 @@ def file_open(path, mode=None):
+
+ def find_disk(virt_dom):
+ if disk_type == 'lvm':
+- return "/dev/nova-vg/lv"
++ return ("/dev/nova-vg/lv", "raw")
+ elif disk_type in ['raw', 'qcow2']:
+- return "filename"
++ return ("filename", disk_type)
+ else:
+- return "unknown_type_disk"
++ return ("unknown_type_disk", None)
+
+
+ def load_file(path):
+diff --git a/nova/tests/unit/virt/libvirt/test_utils.py b/nova/tests/unit/virt/libvirt/test_utils.py
+index ac7ea8d..6773bea 100644
+--- a/nova/tests/unit/virt/libvirt/test_utils.py
++++ b/nova/tests/unit/virt/libvirt/test_utils.py
+@@ -39,24 +39,6 @@ CONF = cfg.CONF
+
+ class LibvirtUtilsTestCase(test.NoDBTestCase):
+
+- @mock.patch('os.path.exists', return_value=True)
+- @mock.patch('nova.utils.execute')
+- def test_get_disk_type(self, mock_execute, mock_exists):
+- path = "disk.config"
+- example_output = """image: disk.config
+-file format: raw
+-virtual size: 64M (67108864 bytes)
+-cluster_size: 65536
+-disk size: 96K
+-blah BLAH: bb
+-"""
+- mock_execute.return_value = (example_output, '')
+- disk_type = libvirt_utils.get_disk_type(path)
+- mock_execute.assert_called_once_with('env', 'LC_ALL=C', 'LANG=C',
+- 'qemu-img', 'info', path)
+- mock_exists.assert_called_once_with(path)
+- self.assertEqual('raw', disk_type)
+-
+ @mock.patch('nova.utils.execute')
+ def test_copy_image_local(self, mock_execute):
+ libvirt_utils.copy_image('src', 'dest')
+@@ -77,37 +59,21 @@ blah BLAH: bb
+ on_completion=None, on_execute=None, compression=True)
+
+ @mock.patch('os.path.exists', return_value=True)
+- def test_disk_type(self, mock_exists):
++ def test_disk_type_from_path(self, mock_exists):
+ # Seems like lvm detection
+ # if its in /dev ??
+ for p in ['/dev/b', '/dev/blah/blah']:
+- d_type = libvirt_utils.get_disk_type(p)
++ d_type = libvirt_utils.get_disk_type_from_path(p)
+ self.assertEqual('lvm', d_type)
+
+ # Try rbd detection
+- d_type = libvirt_utils.get_disk_type('rbd:pool/instance')
++ d_type = libvirt_utils.get_disk_type_from_path('rbd:pool/instance')
+ self.assertEqual('rbd', d_type)
+
+ # Try the other types
+- template_output = """image: %(path)s
+-file format: %(format)s
+-virtual size: 64M (67108864 bytes)
+-cluster_size: 65536
+-disk size: 96K
+-"""
+ path = '/myhome/disk.config'
+- for f in ['raw', 'qcow2']:
+- output = template_output % ({
+- 'format': f,
+- 'path': path,
+- })
+- with mock.patch('nova.utils.execute',
+- return_value=(output, '')) as mock_execute:
+- d_type = libvirt_utils.get_disk_type(path)
+- mock_execute.assert_called_once_with(
+- 'env', 'LC_ALL=C', 'LANG=C',
+- 'qemu-img', 'info', path)
+- self.assertEqual(f, d_type)
++ d_type = libvirt_utils.get_disk_type_from_path(path)
++ self.assertIsNone(d_type)
+
+ @mock.patch('os.path.exists', return_value=True)
+ @mock.patch('nova.utils.execute')
+diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
+index fc1c909..51b1e4b 100644
+--- a/nova/virt/libvirt/driver.py
++++ b/nova/virt/libvirt/driver.py
+@@ -1338,10 +1338,23 @@ class LibvirtDriver(driver.ComputeDriver):
+
+ snapshot = self._image_api.get(context, image_id)
+
+- disk_path = libvirt_utils.find_disk(virt_dom)
+- source_format = libvirt_utils.get_disk_type(disk_path)
+-
+- image_format = CONF.libvirt.snapshot_image_format or source_format
++ # source_format is an on-disk format
++ # source_type is a backend type
++ disk_path, source_format = libvirt_utils.find_disk(virt_dom)
++ source_type = libvirt_utils.get_disk_type_from_path(disk_path)
++
++ # We won't have source_type for raw or qcow2 disks, because we can't
++ # determine that from the path. We should have it from the libvirt
++ # xml, though.
++ if source_type is None:
++ source_type = source_format
++ # For lxc instances we won't have it either from libvirt xml
++ # (because we just gave libvirt the mounted filesystem), or the path,
++ # so source_type is still going to be None. In this case,
++ # snapshot_backend is going to default to CONF.libvirt.images_type
++ # below, which is still safe.
++
++ image_format = CONF.libvirt.snapshot_image_format or source_type
+
+ # NOTE(bfilippov): save lvm and rbd as raw
+ if image_format == 'lvm' or image_format == 'rbd':
+@@ -1367,7 +1380,7 @@ class LibvirtDriver(driver.ComputeDriver):
+ if (self._host.has_min_version(MIN_LIBVIRT_LIVESNAPSHOT_VERSION,
+ MIN_QEMU_LIVESNAPSHOT_VERSION,
+ host.HV_DRIVER_QEMU)
+- and source_format not in ('lvm', 'rbd')
++ and source_type not in ('lvm', 'rbd')
+ and not CONF.ephemeral_storage_encryption.enabled
+ and not CONF.workarounds.disable_libvirt_livesnapshot):
+ live_snapshot = True
+@@ -1402,7 +1415,7 @@ class LibvirtDriver(driver.ComputeDriver):
+
+ snapshot_backend = self.image_backend.snapshot(instance,
+ disk_path,
+- image_type=source_format)
++ image_type=source_type)
+
+ if live_snapshot:
+ LOG.info(_LI("Beginning live snapshot process"),
+diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py
+index 5573927..062b2fb 100644
+--- a/nova/virt/libvirt/utils.py
++++ b/nova/virt/libvirt/utils.py
+@@ -334,13 +334,20 @@ def find_disk(virt_dom):
+ """
+ xml_desc = virt_dom.XMLDesc(0)
+ domain = etree.fromstring(xml_desc)
++ driver = None
+ if CONF.libvirt.virt_type == 'lxc':
+- source = domain.find('devices/filesystem/source')
++ filesystem = domain.find('devices/filesystem')
++ driver = filesystem.find('driver')
++
++ source = filesystem.find('source')
+ disk_path = source.get('dir')
+ disk_path = disk_path[0:disk_path.rfind('rootfs')]
+ disk_path = os.path.join(disk_path, 'disk')
+ else:
+- source = domain.find('devices/disk/source')
++ disk = domain.find('devices/disk')
++ driver = disk.find('driver')
++
++ source = disk.find('source')
+ disk_path = source.get('file') or source.get('dev')
+ if not disk_path and CONF.libvirt.images_type == 'rbd':
+ disk_path = source.get('name')
+@@ -351,17 +358,26 @@ def find_disk(virt_dom):
+ raise RuntimeError(_("Can't retrieve root device path "
+ "from instance libvirt configuration"))
+
+- return disk_path
++ if driver is not None:
++ format = driver.get('type')
++ # This is a legacy quirk of libvirt/xen. Everything else should
++ # report the on-disk format in type.
++ if format == 'aio':
++ format = 'raw'
++ else:
++ format = None
++ return (disk_path, format)
+
+
+-def get_disk_type(path):
++def get_disk_type_from_path(path):
+ """Retrieve disk type (raw, qcow2, lvm) for given file."""
+ if path.startswith('/dev'):
+ return 'lvm'
+ elif path.startswith('rbd:'):
+ return 'rbd'
+
+- return images.qemu_img_info(path).file_format
++ # We can't reliably determine the type from this path
++ return None
+
+
+ def get_fs_info(path):
+--
+2.5.0
+
diff --git a/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0002.patch b/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0002.patch
new file mode 100644
index 000000000000..2ffca9f9cf8a
--- /dev/null
+++ b/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0002.patch
@@ -0,0 +1,168 @@
+From 0e6b4a06ad72ac68ec41bab2063f8d167e8e277e Mon Sep 17 00:00:00 2001
+From: Matthew Booth <mbooth@redhat.com>
+Date: Thu, 10 Dec 2015 16:34:19 +0000
+Subject: [PATCH 2/3] Fix format conversion in libvirt snapshot
+
+The libvirt driver was calling images.convert_image during snapshot to
+convert snapshots to the intended output format. However, this
+function does not take the input format as an argument, meaning it
+implicitly does format detection. This opened an exploit for setups
+using raw storage on the backend, including raw on filesystem, LVM,
+and RBD (Ceph). An authenticated user could write a qcow2 header to
+their instance's disk which specified an arbitrary backing file on the
+host. When convert_image ran during snapshot, this would then write
+the contents of the backing file to glance, which is then available to
+the user. If the setup uses an LVM backend this conversion runs as
+root, meaning the user can exfiltrate any file on the host, including
+raw disks.
+
+This change adds an input format to convert_image.
+
+Partial-Bug: #1524274
+
+Change-Id: If73e73718ecd5db262ed9904091024238f98dbc0
+(cherry picked from commit 840644d619e9560f205016eafc8799565ffd6d8c)
+---
+ nova/tests/unit/virt/libvirt/test_driver.py | 5 +++--
+ nova/tests/unit/virt/libvirt/test_utils.py | 3 ++-
+ nova/virt/images.py | 26 ++++++++++++++++++++++++--
+ nova/virt/libvirt/imagebackend.py | 19 ++++++++++++++-----
+ 4 files changed, 43 insertions(+), 10 deletions(-)
+
+diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py
+index 22ef56d..6fd8728 100644
+--- a/nova/tests/unit/virt/libvirt/test_driver.py
++++ b/nova/tests/unit/virt/libvirt/test_driver.py
+@@ -14985,7 +14985,7 @@ class LibvirtVolumeSnapshotTestCase(test.NoDBTestCase):
+ self.mox.VerifyAll()
+
+
+-def _fake_convert_image(source, dest, out_format,
++def _fake_convert_image(source, dest, in_format, out_format,
+ run_as_root=True):
+ libvirt_driver.libvirt_utils.files[dest] = ''
+
+@@ -15127,7 +15127,8 @@ class LVMSnapshotTests(_BaseSnapshotTests):
+
+ mock_volume_info.assert_has_calls([mock.call('/dev/nova-vg/lv')])
+ mock_convert_image.assert_called_once_with(
+- '/dev/nova-vg/lv', mock.ANY, disk_format, run_as_root=True)
++ '/dev/nova-vg/lv', mock.ANY, 'raw', disk_format,
++ run_as_root=True)
+
+ def test_raw(self):
+ self._test_lvm_snapshot('raw')
+diff --git a/nova/tests/unit/virt/libvirt/test_utils.py b/nova/tests/unit/virt/libvirt/test_utils.py
+index 6773bea..6f75a92 100644
+--- a/nova/tests/unit/virt/libvirt/test_utils.py
++++ b/nova/tests/unit/virt/libvirt/test_utils.py
+@@ -594,7 +594,8 @@ disk size: 4.4M
+ target = 't.qcow2'
+ self.executes = []
+ expected_commands = [('qemu-img', 'convert', '-O', 'raw',
+- 't.qcow2.part', 't.qcow2.converted'),
++ 't.qcow2.part', 't.qcow2.converted',
++ '-f', 'qcow2'),
+ ('rm', 't.qcow2.part'),
+ ('mv', 't.qcow2.converted', 't.qcow2')]
+ images.fetch_to_raw(context, image_id, target, user_id, project_id,
+diff --git a/nova/virt/images.py b/nova/virt/images.py
+index 5b9374b..e2b5b91 100644
+--- a/nova/virt/images.py
++++ b/nova/virt/images.py
+@@ -66,9 +66,31 @@ def qemu_img_info(path):
+ return imageutils.QemuImgInfo(out)
+
+
+-def convert_image(source, dest, out_format, run_as_root=False):
++def convert_image(source, dest, in_format, out_format, run_as_root=False):
+ """Convert image to other format."""
++ if in_format is None:
++ raise RuntimeError("convert_image without input format is a security"
++ "risk")
++ _convert_image(source, dest, in_format, out_format, run_as_root)
++
++
++def convert_image_unsafe(source, dest, out_format, run_as_root=False):
++ """Convert image to other format, doing unsafe automatic input format
++ detection. Do not call this function.
++ """
++
++ # NOTE: there is only 1 caller of this function:
++ # imagebackend.Lvm.create_image. It is not easy to fix that without a
++ # larger refactor, so for the moment it has been manually audited and
++ # allowed to continue. Remove this function when Lvm.create_image has
++ # been fixed.
++ _convert_image(source, dest, None, out_format, run_as_root)
++
++
++def _convert_image(source, dest, in_format, out_format, run_as_root):
+ cmd = ('qemu-img', 'convert', '-O', out_format, source, dest)
++ if in_format is not None:
++ cmd = cmd + ('-f', in_format)
+ utils.execute(*cmd, run_as_root=run_as_root)
+
+
+@@ -123,7 +145,7 @@ def fetch_to_raw(context, image_href, path, user_id, project_id, max_size=0):
+ staged = "%s.converted" % path
+ LOG.debug("%s was %s, converting to raw" % (image_href, fmt))
+ with fileutils.remove_path_on_error(staged):
+- convert_image(path_tmp, staged, 'raw')
++ convert_image(path_tmp, staged, fmt, 'raw')
+ os.unlink(path_tmp)
+
+ data = qemu_img_info(staged)
+diff --git a/nova/virt/libvirt/imagebackend.py b/nova/virt/libvirt/imagebackend.py
+index 5e14f61..151ebc4 100644
+--- a/nova/virt/libvirt/imagebackend.py
++++ b/nova/virt/libvirt/imagebackend.py
+@@ -477,7 +477,7 @@ class Raw(Image):
+ self.correct_format()
+
+ def snapshot_extract(self, target, out_format):
+- images.convert_image(self.path, target, out_format)
++ images.convert_image(self.path, target, self.driver_format, out_format)
+
+ @staticmethod
+ def is_file_in_instance_path():
+@@ -631,7 +631,16 @@ class Lvm(Image):
+ size, sparse=self.sparse)
+ if self.ephemeral_key_uuid is not None:
+ encrypt_lvm_image()
+- images.convert_image(base, self.path, 'raw', run_as_root=True)
++ # NOTE: by calling convert_image_unsafe here we're
++ # telling qemu-img convert to do format detection on the input,
++ # because we don't know what the format is. For example,
++ # we might have downloaded a qcow2 image, or created an
++ # ephemeral filesystem locally, we just don't know here. Having
++ # audited this, all current sources have been sanity checked,
++ # either because they're locally generated, or because they have
++ # come from images.fetch_to_raw. However, this is major code smell.
++ images.convert_image_unsafe(base, self.path, self.driver_format,
++ run_as_root=True)
+ if resize:
+ disk.resize2fs(self.path, run_as_root=True)
+
+@@ -678,8 +687,8 @@ class Lvm(Image):
+ lvm.remove_volumes([self.lv_path])
+
+ def snapshot_extract(self, target, out_format):
+- images.convert_image(self.path, target, out_format,
+- run_as_root=True)
++ images.convert_image(self.path, target, self.driver_format,
++ out_format, run_as_root=True)
+
+ def get_model(self, connection):
+ return imgmodel.LocalBlockImage(self.path)
+@@ -786,7 +795,7 @@ class Rbd(Image):
+ self.driver.resize(self.rbd_name, size)
+
+ def snapshot_extract(self, target, out_format):
+- images.convert_image(self.path, target, out_format)
++ images.convert_image(self.path, target, 'raw', out_format)
+
+ @staticmethod
+ def is_shared_block_storage():
+--
+2.5.0
+
diff --git a/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0003.patch b/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0003.patch
new file mode 100644
index 000000000000..b542041b5311
--- /dev/null
+++ b/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0003.patch
@@ -0,0 +1,171 @@
+From 62516194c424abad3bec12ea360dde06617fe97d Mon Sep 17 00:00:00 2001
+From: Matthew Booth <mbooth@redhat.com>
+Date: Fri, 11 Dec 2015 13:40:54 +0000
+Subject: [PATCH 3/3] Fix backing file detection in libvirt live snapshot
+
+When doing a live snapshot, the libvirt driver creates an intermediate
+qcow2 file with the same backing file as the original disk. However,
+it calls qemu-img info without specifying the input format explicitly.
+An authenticated user can write data to a raw disk which will cause
+this code to misinterpret the disk as a qcow2 file with a
+user-specified backing file on the host, and return an arbitrary host
+file as the backing file.
+
+This bug does not appear to result in a data leak in this case, but
+this is hard to verify. It certainly results in corrupt output.
+
+Closes-Bug: #1524274
+
+Change-Id: I11485f077d28f4e97529a691e55e3e3c0bea8872
+(cherry picked from commit ccea9095d9fb5bcdcb61ee5e352c4a8163754b9d)
+---
+ nova/tests/unit/virt/libvirt/fake_libvirt_utils.py | 4 ++--
+ nova/tests/unit/virt/libvirt/test_driver.py | 7 ++++---
+ nova/virt/images.py | 8 +++++---
+ nova/virt/libvirt/driver.py | 11 +++++++----
+ nova/virt/libvirt/utils.py | 9 +++++----
+ 5 files changed, 23 insertions(+), 16 deletions(-)
+
+diff --git a/nova/tests/unit/virt/libvirt/fake_libvirt_utils.py b/nova/tests/unit/virt/libvirt/fake_libvirt_utils.py
+index 52d1e85..b474687 100644
+--- a/nova/tests/unit/virt/libvirt/fake_libvirt_utils.py
++++ b/nova/tests/unit/virt/libvirt/fake_libvirt_utils.py
+@@ -32,11 +32,11 @@ def create_cow_image(backing_file, path):
+ pass
+
+
+-def get_disk_size(path):
++def get_disk_size(path, format=None):
+ return 0
+
+
+-def get_disk_backing_file(path):
++def get_disk_backing_file(path, format=None):
+ return disk_backing_files.get(path, None)
+
+
+diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py
+index 6fd8728..6d0afdf 100644
+--- a/nova/tests/unit/virt/libvirt/test_driver.py
++++ b/nova/tests/unit/virt/libvirt/test_driver.py
+@@ -12018,7 +12018,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
+
+ image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
+ drvr._live_snapshot(self.context, self.test_instance, guest,
+- srcfile, dstfile, "qcow2", image_meta)
++ srcfile, dstfile, "qcow2", "qcow2", image_meta)
+
+ mock_dom.XMLDesc.assert_called_once_with(flags=(
+ fakelibvirt.VIR_DOMAIN_XML_INACTIVE |
+@@ -12029,8 +12029,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
+ fakelibvirt.VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
+ fakelibvirt.VIR_DOMAIN_BLOCK_REBASE_SHALLOW))
+
+- mock_size.assert_called_once_with(srcfile)
+- mock_backing.assert_called_once_with(srcfile, basename=False)
++ mock_size.assert_called_once_with(srcfile, format="qcow2")
++ mock_backing.assert_called_once_with(srcfile, basename=False,
++ format="qcow2")
+ mock_create_cow.assert_called_once_with(bckfile, dltfile, 1004009)
+ mock_chown.assert_called_once_with(dltfile, os.getuid())
+ mock_snapshot.assert_called_once_with(dltfile, "qcow2",
+diff --git a/nova/virt/images.py b/nova/virt/images.py
+index e2b5b91..6f3e487 100644
+--- a/nova/virt/images.py
++++ b/nova/virt/images.py
+@@ -44,7 +44,7 @@ CONF.register_opts(image_opts)
+ IMAGE_API = image.API()
+
+
+-def qemu_img_info(path):
++def qemu_img_info(path, format=None):
+ """Return an object containing the parsed output from qemu-img info."""
+ # TODO(mikal): this code should not be referring to a libvirt specific
+ # flag.
+@@ -56,8 +56,10 @@ def qemu_img_info(path):
+ msg = (_("Path does not exist %(path)s") % {'path': path})
+ raise exception.InvalidDiskInfo(reason=msg)
+
+- out, err = utils.execute('env', 'LC_ALL=C', 'LANG=C',
+- 'qemu-img', 'info', path)
++ cmd = ('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path)
++ if format is not None:
++ cmd = cmd + ('-f', format)
++ out, err = utils.execute(*cmd)
+ if not out:
+ msg = (_("Failed to run qemu-img info on %(path)s : %(error)s") %
+ {'path': path, 'error': err})
+diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
+index 51b1e4b..53a27b2 100644
+--- a/nova/virt/libvirt/driver.py
++++ b/nova/virt/libvirt/driver.py
+@@ -1434,7 +1434,8 @@ class LibvirtDriver(driver.ComputeDriver):
+ # NOTE(xqueralt): libvirt needs o+x in the temp directory
+ os.chmod(tmpdir, 0o701)
+ self._live_snapshot(context, instance, guest, disk_path,
+- out_path, image_format, image_meta)
++ out_path, source_format, image_format,
++ image_meta)
+ else:
+ snapshot_backend.snapshot_extract(out_path, image_format)
+ finally:
+@@ -1540,7 +1541,7 @@ class LibvirtDriver(driver.ComputeDriver):
+ self._set_quiesced(context, instance, image_meta, False)
+
+ def _live_snapshot(self, context, instance, guest, disk_path, out_path,
+- image_format, image_meta):
++ source_format, image_format, image_meta):
+ """Snapshot an instance without downtime."""
+ dev = guest.get_block_device(disk_path)
+
+@@ -1558,9 +1559,11 @@ class LibvirtDriver(driver.ComputeDriver):
+ # in QEMU 1.3. In order to do this, we need to create
+ # a destination image with the original backing file
+ # and matching size of the instance root disk.
+- src_disk_size = libvirt_utils.get_disk_size(disk_path)
++ src_disk_size = libvirt_utils.get_disk_size(disk_path,
++ format=source_format)
+ src_back_path = libvirt_utils.get_disk_backing_file(disk_path,
+- basename=False)
++ format=source_format,
++ basename=False)
+ disk_delta = out_path + '.delta'
+ libvirt_utils.create_cow_image(src_back_path, disk_delta,
+ src_disk_size)
+diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py
+index 062b2fb..7b0cf42 100644
+--- a/nova/virt/libvirt/utils.py
++++ b/nova/virt/libvirt/utils.py
+@@ -160,24 +160,25 @@ def pick_disk_driver_name(hypervisor_version, is_block_dev=False):
+ return None
+
+
+-def get_disk_size(path):
++def get_disk_size(path, format=None):
+ """Get the (virtual) size of a disk image
+
+ :param path: Path to the disk image
++ :param format: the on-disk format of path
+ :returns: Size (in bytes) of the given disk image as it would be seen
+ by a virtual machine.
+ """
+- size = images.qemu_img_info(path).virtual_size
++ size = images.qemu_img_info(path, format).virtual_size
+ return int(size)
+
+
+-def get_disk_backing_file(path, basename=True):
++def get_disk_backing_file(path, basename=True, format=None):
+ """Get the backing file of a disk image
+
+ :param path: Path to the disk image
+ :returns: a path to the image's backing store
+ """
+- backing_file = images.qemu_img_info(path).backing_file
++ backing_file = images.qemu_img_info(path, format).backing_file
+ if backing_file and basename:
+ backing_file = os.path.basename(backing_file)
+
+--
+2.5.0
+