VYPR
Medium severity5.3NVD Advisory· Published Apr 12, 2016· Updated May 6, 2026

CVE-2016-2140

CVE-2016-2140

Description

The libvirt driver in OpenStack Compute (Nova) before 2015.1.4 (kilo) and 12.0.x before 12.0.3 (liberty), when using raw storage and use_cow_images is set to false, allows remote authenticated users to read arbitrary files via a crafted qcow2 header in an ephemeral or root disk.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
novaPyPI
>= 12.0.0, < 12.0.312.0.3

Affected products

1
  • cpe:2.3:a:openstack:nova:*:*:*:*:*:*:*:*
    Range: >=12.0.0,<12.0.3

Patches

3
0b194187db9d

Add release note for CVE bug 1548450

https://github.com/openstack/novaMatt RiedemannMar 10, 2016via ghsa
1 file changed · +7 0
  • releasenotes/notes/12.0.3-cve-bugs-reno-561a450b346edf5e.yaml+7 0 added
    @@ -0,0 +1,7 @@
    +---
    +security:
    +  - |
    +    [OSSA 2016-007] Host data leak during resize/migrate for raw-backed instances  (CVE-2016-2140)
    +
    +    * `Bug 1548450 <https://bugs.launchpad.net/nova/+bug/1548450>`_
    +    * `Announcement <http://lists.openstack.org/pipermail/openstack-announce/2016-March/001009.html>`__
    \ No newline at end of file
    
116b1210ab77

libvirt: Always copy or recreate disk.info during a migration

https://github.com/openstack/novaLee YarwoodFeb 24, 2016via ghsa
2 files changed · +102 0
  • nova/tests/unit/virt/libvirt/test_driver.py+75 0 modified
    @@ -8636,6 +8636,43 @@ def check_instance_dir(context, instance,
                                fallback_from_host=instance.host)])
                 self.assertIsInstance(res, objects.LibvirtLiveMigrateData)
     
    +    def test_pre_live_migration_recreate_disk_info(self):
    +
    +        migrate_data = {'is_shared_block_storage': False,
    +                        'is_shared_instance_path': False,
    +                        'block_migration': True,
    +                        'instance_relative_path': '/some/path/'}
    +        disk_info = [{'disk_size': 5368709120, 'type': 'raw',
    +                      'virt_disk_size': 5368709120,
    +                      'path': '/some/path/disk',
    +                      'backing_file': '', 'over_committed_disk_size': 0},
    +                     {'disk_size': 1073741824, 'type': 'raw',
    +                      'virt_disk_size': 1073741824,
    +                      'path': '/some/path/disk.eph0',
    +                      'backing_file': '', 'over_committed_disk_size': 0}]
    +        image_disk_info = {'/some/path/disk': 'raw',
    +                           '/some/path/disk.eph0': 'raw'}
    +
    +        drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
    +        instance = objects.Instance(**self.test_instance)
    +        instance_path = os.path.dirname(disk_info[0]['path'])
    +        disk_info_path = os.path.join(instance_path, 'disk.info')
    +
    +        with test.nested(
    +            mock.patch.object(os, 'mkdir'),
    +            mock.patch.object(fake_libvirt_utils, 'write_to_file'),
    +            mock.patch.object(drvr, '_create_images_and_backing')
    +        ) as (
    +            mkdir, write_to_file, create_images_and_backing
    +        ):
    +            drvr.pre_live_migration(self.context, instance,
    +                                    block_device_info=None,
    +                                    network_info=[],
    +                                    disk_info=jsonutils.dumps(disk_info),
    +                                    migrate_data=migrate_data)
    +            write_to_file.assert_called_with(disk_info_path,
    +                                             jsonutils.dumps(image_disk_info))
    +
         def test_get_instance_disk_info_works_correctly(self):
             # Test data
             instance = objects.Instance(**self.test_instance)
    @@ -14170,6 +14207,44 @@ def test_migrate_disk_and_power_off_resize_error_eph(self, mock_get,
             flavor_obj = objects.Flavor(**flavor)
             self._test_migrate_disk_and_power_off(flavor_obj)
     
    +    @mock.patch('nova.utils.execute')
    +    @mock.patch('nova.virt.libvirt.utils.copy_image')
    +    @mock.patch('nova.virt.libvirt.driver.LibvirtDriver._destroy')
    +    @mock.patch('nova.virt.libvirt.utils.get_instance_path')
    +    @mock.patch('nova.virt.libvirt.driver.LibvirtDriver'
    +                '._is_storage_shared_with')
    +    @mock.patch('nova.virt.libvirt.driver.LibvirtDriver'
    +                '.get_instance_disk_info')
    +    def test_migrate_disk_and_power_off_resize_copy_disk_info(self,
    +                                                              mock_disk_info,
    +                                                              mock_shared,
    +                                                              mock_path,
    +                                                              mock_destroy,
    +                                                              mock_copy,
    +                                                              mock_execuate):
    +
    +        instance = self._create_instance()
    +        disk_info = self._disk_info()
    +        disk_info_text = jsonutils.loads(disk_info)
    +        instance_base = os.path.dirname(disk_info_text[0]['path'])
    +        flavor = {'root_gb': 10, 'ephemeral_gb': 25}
    +        flavor_obj = objects.Flavor(**flavor)
    +
    +        mock_disk_info.return_value = disk_info
    +        mock_path.return_value = instance_base
    +        mock_shared.return_value = False
    +
    +        self.drvr.migrate_disk_and_power_off(context.get_admin_context(),
    +                                             instance, mock.sentinel,
    +                                             flavor_obj, None)
    +
    +        src_disk_info_path = os.path.join(instance_base + '_resize',
    +                                          'disk.info')
    +        dst_disk_info_path = os.path.join(instance_base, 'disk.info')
    +        mock_copy.assert_any_call(src_disk_info_path, dst_disk_info_path,
    +                                  host=mock.sentinel, on_execute=mock.ANY,
    +                                  on_completion=mock.ANY, compression=mock.ANY)
    +
         def test_wait_for_running(self):
             def fake_get_info(instance):
                 if instance['name'] == "not_found":
    
  • nova/virt/libvirt/driver.py+27 0 modified
    @@ -6655,6 +6655,24 @@ def pre_live_migration(self, context, instance, block_device_info,
                           instance=instance)
                 os.mkdir(instance_dir)
     
    +            # Recreate the disk.info file and in doing so stop the
    +            # imagebackend from recreating it incorrectly by inspecting the
    +            # contents of each file when using the Raw backend.
    +            if disk_info:
    +                image_disk_info = {}
    +                for info in disk_info:
    +                    image_file = os.path.basename(info['path'])
    +                    image_path = os.path.join(instance_dir, image_file)
    +                    image_disk_info[image_path] = info['type']
    +
    +                LOG.debug('Creating disk.info with the contents: %s',
    +                          image_disk_info, instance=instance)
    +
    +                image_disk_info_path = os.path.join(instance_dir,
    +                                                    'disk.info')
    +                libvirt_utils.write_to_file(image_disk_info_path,
    +                                            jsonutils.dumps(image_disk_info))
    +
                 if not is_shared_block_storage:
                     # Ensure images and backing files are present.
                     LOG.debug('Checking to make sure images and backing files are '
    @@ -7242,6 +7260,15 @@ def migrate_disk_and_power_off(self, context, instance, dest,
                                                  on_execute=on_execute,
                                                  on_completion=on_completion,
                                                  compression=compression)
    +
    +            # Ensure disk.info is written to the new path to avoid disks being
    +            # reinspected and potentially changing format.
    +            src_disk_info_path = os.path.join(inst_base_resize, 'disk.info')
    +            dst_disk_info_path = os.path.join(inst_base, 'disk.info')
    +            libvirt_utils.copy_image(src_disk_info_path, dst_disk_info_path,
    +                                     host=dest, on_execute=on_execute,
    +                                     on_completion=on_completion,
    +                                     compression=compression)
             except Exception:
                 with excutils.save_and_reraise_exception():
                     self._cleanup_remote_migration(dest, inst_base,
    
f302bf04ab5d

libvirt: Always copy or recreate disk.info during a migration

https://github.com/openstack/novaLee YarwoodFeb 24, 2016via ghsa
2 files changed · +101 0
  • nova/tests/unit/virt/libvirt/test_driver.py+75 0 modified
    @@ -6608,6 +6608,43 @@ def test_pre_live_migration_block_migrate_fails(self):
                                   self.context, instance, block_device_info=None,
                                   network_info=[], disk_info={}, migrate_data={})
     
    +    def test_pre_live_migration_recreate_disk_info(self):
    +
    +        migrate_data = {'is_shared_block_storage': False,
    +                        'is_shared_instance_path': False,
    +                        'block_migration': True,
    +                        'instance_relative_path': '/some/path/'}
    +        disk_info = [{'disk_size': 5368709120, 'type': 'raw',
    +                      'virt_disk_size': 5368709120,
    +                      'path': '/some/path/disk',
    +                      'backing_file': '', 'over_committed_disk_size': 0},
    +                     {'disk_size': 1073741824, 'type': 'raw',
    +                      'virt_disk_size': 1073741824,
    +                      'path': '/some/path/disk.eph0',
    +                      'backing_file': '', 'over_committed_disk_size': 0}]
    +        image_disk_info = {'/some/path/disk': 'raw',
    +                           '/some/path/disk.eph0': 'raw'}
    +
    +        drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
    +        instance = objects.Instance(**self.test_instance)
    +        instance_path = os.path.dirname(disk_info[0]['path'])
    +        disk_info_path = os.path.join(instance_path, 'disk.info')
    +
    +        with contextlib.nested(
    +            mock.patch.object(os, 'mkdir'),
    +            mock.patch.object(fake_libvirt_utils, 'write_to_file'),
    +            mock.patch.object(drvr, '_create_images_and_backing')
    +        ) as (
    +            mkdir, write_to_file, create_images_and_backing
    +        ):
    +            drvr.pre_live_migration(self.context, instance,
    +                                    block_device_info=None,
    +                                    network_info=[],
    +                                    disk_info=disk_info,
    +                                    migrate_data=migrate_data)
    +            write_to_file.assert_called_with(disk_info_path,
    +                                             jsonutils.dumps(image_disk_info))
    +
         def test_get_instance_disk_info_works_correctly(self):
             # Test data
             instance = objects.Instance(**self.test_instance)
    @@ -11607,6 +11644,44 @@ def test_migrate_disk_and_power_off_resize_error_eph(self, mock_get,
             flavor_obj = objects.Flavor(**flavor)
             self._test_migrate_disk_and_power_off(flavor_obj)
     
    +    @mock.patch('nova.utils.execute')
    +    @mock.patch('nova.virt.libvirt.utils.copy_image')
    +    @mock.patch('nova.virt.libvirt.driver.LibvirtDriver._destroy')
    +    @mock.patch('nova.virt.libvirt.utils.get_instance_path')
    +    @mock.patch('nova.virt.libvirt.driver.LibvirtDriver'
    +                '._is_storage_shared_with')
    +    @mock.patch('nova.virt.libvirt.driver.LibvirtDriver'
    +                '.get_instance_disk_info')
    +    def test_migrate_disk_and_power_off_resize_copy_disk_info(self,
    +                                                              mock_disk_info,
    +                                                              mock_shared,
    +                                                              mock_path,
    +                                                              mock_destroy,
    +                                                              mock_copy,
    +                                                              mock_execuate):
    +
    +        instance = self._create_instance()
    +        disk_info = self._disk_info()
    +        disk_info_text = jsonutils.loads(disk_info)
    +        instance_base = os.path.dirname(disk_info_text[0]['path'])
    +        flavor = {'root_gb': 10, 'ephemeral_gb': 25}
    +        flavor_obj = objects.Flavor(**flavor)
    +
    +        mock_disk_info.return_value = disk_info
    +        mock_path.return_value = instance_base
    +        mock_shared.return_value = False
    +
    +        self.drvr.migrate_disk_and_power_off(context.get_admin_context(),
    +                                             instance, mock.sentinel,
    +                                             flavor_obj, None)
    +
    +        src_disk_info_path = os.path.join(instance_base + '_resize',
    +                                          'disk.info')
    +        dst_disk_info_path = os.path.join(instance_base, 'disk.info')
    +        mock_copy.assert_any_call(src_disk_info_path, dst_disk_info_path,
    +                                  host=mock.sentinel, on_execute=mock.ANY,
    +                                  on_completion=mock.ANY)
    +
         def test_wait_for_running(self):
             def fake_get_info(instance):
                 if instance['name'] == "not_found":
    
  • nova/virt/libvirt/driver.py+26 0 modified
    @@ -5825,6 +5825,24 @@ def pre_live_migration(self, context, instance, block_device_info,
                     raise exception.DestinationDiskExists(path=instance_dir)
                 os.mkdir(instance_dir)
     
    +            # Recreate the disk.info file and in doing so stop the
    +            # imagebackend from recreating it incorrectly by inspecting the
    +            # contents of each file when using the Raw backend.
    +            if disk_info:
    +                image_disk_info = {}
    +                for info in disk_info:
    +                    image_file = os.path.basename(info['path'])
    +                    image_path = os.path.join(instance_dir, image_file)
    +                    image_disk_info[image_path] = info['type']
    +
    +                LOG.debug('Creating disk.info with the contents: %s',
    +                          image_disk_info, instance=instance)
    +
    +                image_disk_info_path = os.path.join(instance_dir,
    +                                                    'disk.info')
    +                libvirt_utils.write_to_file(image_disk_info_path,
    +                                            jsonutils.dumps(image_disk_info))
    +
                 if not is_shared_block_storage:
                     # Ensure images and backing files are present.
                     self._create_images_and_backing(
    @@ -6362,6 +6380,14 @@ def migrate_disk_and_power_off(self, context, instance, dest,
                         libvirt_utils.copy_image(from_path, img_path, host=dest,
                                                  on_execute=on_execute,
                                                  on_completion=on_completion)
    +
    +            # Ensure disk.info is written to the new path to avoid disks being
    +            # reinspected and potentially changing format.
    +            src_disk_info_path = os.path.join(inst_base_resize, 'disk.info')
    +            dst_disk_info_path = os.path.join(inst_base, 'disk.info')
    +            libvirt_utils.copy_image(src_disk_info_path, dst_disk_info_path,
    +                                     host=dest, on_execute=on_execute,
    +                                     on_completion=on_completion)
             except Exception:
                 with excutils.save_and_reraise_exception():
                     self._cleanup_remote_migration(dest, inst_base,
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

16

News mentions

0

No linked articles in our index yet.