diff options
author | Matthew Thode <prometheanfire@gentoo.org> | 2016-02-09 19:08:11 -0600 |
---|---|---|
committer | Matthew Thode <prometheanfire@gentoo.org> | 2016-02-09 19:08:11 -0600 |
commit | b0f835980e4771c9b75b43d787181d41c4dc2c57 (patch) | |
tree | 6f8caff44087b61d86b6e590b02677114ee6e5d6 /sys-cluster | |
parent | Revert "net-fs/samba: add ebuild for 4.4.0rc2" (diff) | |
download | gentoo-b0f835980e4771c9b75b43d787181d41c4dc2c57.tar.gz gentoo-b0f835980e4771c9b75b43d787181d41c4dc2c57.tar.bz2 gentoo-b0f835980e4771c9b75b43d787181d41c4dc2c57.zip |
sys-cluster/nova: cleanup
Package-Manager: portage-2.2.26
Diffstat (limited to 'sys-cluster')
7 files changed, 0 insertions, 1550 deletions
diff --git a/sys-cluster/nova/files/CVE-2015-3241-kilo.patch b/sys-cluster/nova/files/CVE-2015-3241-kilo.patch deleted file mode 100644 index 24835e02277e..000000000000 --- a/sys-cluster/nova/files/CVE-2015-3241-kilo.patch +++ /dev/null @@ -1,351 +0,0 @@ -From b5020a047fc487f35b76fc05f31e52665a1afda1 Mon Sep 17 00:00:00 2001 -From: abhishekkekane <abhishek.kekane@nttdata.com> -Date: Mon, 6 Jul 2015 01:51:26 -0700 -Subject: [PATCH] libvirt: Kill rsync/scp processes before deleting instance - -In the resize operation, during copying files from source to -destination compute node scp/rsync processes are not aborted after -the instance is deleted because linux kernel doesn't delete instance -files physically until all processes using the file handle is closed -completely. Hence rsync/scp process keeps on running until it -transfers 100% of file data. - -Added new module instancejobtracker to libvirt driver which will add, -remove or terminate the processes running against particular instances. -Added callback methods to execute call which will store the pid of -scp/rsync process in cache as a key: value pair and to remove the -pid from the cache after process completion. Process id will be used to -kill the process if it is running while deleting the instance. Instance -uuid is used as a key in the cache and pid will be the value. - -Conflicts: - nova/virt/libvirt/driver.py - -SecurityImpact - -Closes-bug: #1387543 -Change-Id: Ie03acc00a7c904aec13c90ae6a53938d08e5e0c9 -(cherry picked from commit 7ab75d5b0b75fc3426323bef19bf436a258b9707) ---- - nova/tests/unit/virt/libvirt/test_driver.py | 38 +++++++++++ - nova/tests/unit/virt/libvirt/test_utils.py | 9 ++- - nova/virt/libvirt/driver.py | 18 +++++- - nova/virt/libvirt/instancejobtracker.py | 98 +++++++++++++++++++++++++++++ - nova/virt/libvirt/utils.py | 14 +++-- - 5 files changed, 168 insertions(+), 9 deletions(-) - create mode 100644 nova/virt/libvirt/instancejobtracker.py - -diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py -index 859df95..5ff978a 100644 ---- a/nova/tests/unit/virt/libvirt/test_driver.py -+++ b/nova/tests/unit/virt/libvirt/test_driver.py -@@ -23,6 +23,7 @@ - import random - import re - import shutil -+import signal - import threading - import time - import uuid -@@ -9817,6 +9818,15 @@ def test_shared_storage_detection_easy(self): - self.mox.ReplayAll() - self.assertTrue(drvr._is_storage_shared_with('foo', '/path')) - -+ def test_store_pid_remove_pid(self): -+ instance = objects.Instance(**self.test_instance) -+ drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) -+ popen = mock.Mock(pid=3) -+ drvr.job_tracker.add_job(instance, popen.pid) -+ self.assertIn(3, drvr.job_tracker.jobs[instance.uuid]) -+ drvr.job_tracker.remove_job(instance, popen.pid) -+ self.assertNotIn(instance.uuid, drvr.job_tracker.jobs) -+ - @mock.patch('nova.virt.libvirt.host.Host.get_domain') - def test_get_domain_info_with_more_return(self, mock_get_domain): - instance = objects.Instance(**self.test_instance) -@@ -11316,12 +11326,18 @@ def fake_get_host_ip_addr(): - def fake_execute(*args, **kwargs): - pass - -+ def fake_copy_image(src, dest, host=None, receive=False, -+ on_execute=None, on_completion=None): -+ self.assertIsNotNone(on_execute) -+ self.assertIsNotNone(on_completion) -+ - self.stubs.Set(self.drvr, 'get_instance_disk_info', - fake_get_instance_disk_info) - self.stubs.Set(self.drvr, '_destroy', fake_destroy) - self.stubs.Set(self.drvr, 'get_host_ip_addr', - fake_get_host_ip_addr) - self.stubs.Set(utils, 'execute', fake_execute) -+ self.stubs.Set(libvirt_utils, 'copy_image', fake_copy_image) - - ins_ref = self._create_instance(params=params_for_instance) - -@@ -12428,6 +12444,28 @@ def test_delete_instance_files(self, get_instance_path, exists, exe, - @mock.patch('shutil.rmtree') - @mock.patch('nova.utils.execute') - @mock.patch('os.path.exists') -+ @mock.patch('os.kill') -+ @mock.patch('nova.virt.libvirt.utils.get_instance_path') -+ def test_delete_instance_files_kill_running( -+ self, get_instance_path, kill, exists, exe, shutil): -+ get_instance_path.return_value = '/path' -+ instance = objects.Instance(uuid='fake-uuid', id=1) -+ self.drvr.job_tracker.jobs[instance.uuid] = [3, 4] -+ -+ exists.side_effect = [False, False, True, False] -+ -+ result = self.drvr.delete_instance_files(instance) -+ get_instance_path.assert_called_with(instance) -+ exe.assert_called_with('mv', '/path', '/path_del') -+ kill.assert_has_calls([mock.call(3, signal.SIGKILL), mock.call(3, 0), -+ mock.call(4, signal.SIGKILL), mock.call(4, 0)]) -+ shutil.assert_called_with('/path_del') -+ self.assertTrue(result) -+ self.assertNotIn(instance.uuid, self.drvr.job_tracker.jobs) -+ -+ @mock.patch('shutil.rmtree') -+ @mock.patch('nova.utils.execute') -+ @mock.patch('os.path.exists') - @mock.patch('nova.virt.libvirt.utils.get_instance_path') - def test_delete_instance_files_resize(self, get_instance_path, exists, - exe, shutil): -diff --git a/nova/tests/unit/virt/libvirt/test_utils.py b/nova/tests/unit/virt/libvirt/test_utils.py -index 7fa0326..14bf822 100644 ---- a/nova/tests/unit/virt/libvirt/test_utils.py -+++ b/nova/tests/unit/virt/libvirt/test_utils.py -@@ -62,7 +62,8 @@ def test_copy_image_local_cp(self, mock_execute): - mock_execute.assert_called_once_with('cp', 'src', 'dest') - - _rsync_call = functools.partial(mock.call, -- 'rsync', '--sparse', '--compress') -+ 'rsync', '--sparse', '--compress', -+ on_execute=None, on_completion=None) - - @mock.patch('nova.utils.execute') - def test_copy_image_rsync(self, mock_execute): -@@ -85,7 +86,8 @@ def test_copy_image_scp(self, mock_execute): - - mock_execute.assert_has_calls([ - self._rsync_call('--dry-run', 'src', 'host:dest'), -- mock.call('scp', 'src', 'host:dest'), -+ mock.call('scp', 'src', 'host:dest', -+ on_execute=None, on_completion=None), - ]) - self.assertEqual(2, mock_execute.call_count) - -@@ -110,7 +112,8 @@ def test_copy_image_scp_ipv6(self, mock_execute): - - mock_execute.assert_has_calls([ - self._rsync_call('--dry-run', 'src', '[2600::]:dest'), -- mock.call('scp', 'src', '[2600::]:dest'), -+ mock.call('scp', 'src', '[2600::]:dest', -+ on_execute=None, on_completion=None), - ]) - self.assertEqual(2, mock_execute.call_count) - -diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py -index 40ee080..0a94d5a 100644 ---- a/nova/virt/libvirt/driver.py -+++ b/nova/virt/libvirt/driver.py -@@ -95,6 +95,7 @@ - from nova.virt.libvirt import host - from nova.virt.libvirt import imagebackend - from nova.virt.libvirt import imagecache -+from nova.virt.libvirt import instancejobtracker - from nova.virt.libvirt import lvm - from nova.virt.libvirt import rbd_utils - from nova.virt.libvirt import utils as libvirt_utils -@@ -465,6 +466,8 @@ def __init__(self, virtapi, read_only=False): - 'expect': ', '.join("'%s'" % k for k in - sysinfo_serial_funcs.keys())}) - -+ self.job_tracker = instancejobtracker.InstanceJobTracker() -+ - def _get_volume_drivers(self): - return libvirt_volume_drivers - -@@ -6301,6 +6304,11 @@ def migrate_disk_and_power_off(self, context, instance, dest, - # finish_migration/_create_image to re-create it for us. - continue - -+ on_execute = lambda process: self.job_tracker.add_job( -+ instance, process.pid) -+ on_completion = lambda process: self.job_tracker.remove_job( -+ instance, process.pid) -+ - if info['type'] == 'qcow2' and info['backing_file']: - tmp_path = from_path + "_rbase" - # merge backing file -@@ -6310,11 +6318,15 @@ def migrate_disk_and_power_off(self, context, instance, dest, - if shared_storage: - utils.execute('mv', tmp_path, img_path) - else: -- libvirt_utils.copy_image(tmp_path, img_path, host=dest) -+ libvirt_utils.copy_image(tmp_path, img_path, host=dest, -+ on_execute=on_execute, -+ on_completion=on_completion) - utils.execute('rm', '-f', tmp_path) - - else: # raw or qcow2 with no backing file -- libvirt_utils.copy_image(from_path, img_path, host=dest) -+ libvirt_utils.copy_image(from_path, img_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, -@@ -6683,6 +6695,8 @@ def delete_instance_files(self, instance): - # invocation failed due to the absence of both target and - # target_resize. - if not remaining_path and os.path.exists(target_del): -+ self.job_tracker.terminate_jobs(instance) -+ - LOG.info(_LI('Deleting instance files %s'), target_del, - instance=instance) - remaining_path = target_del -diff --git a/nova/virt/libvirt/instancejobtracker.py b/nova/virt/libvirt/instancejobtracker.py -new file mode 100644 -index 0000000..d47fb45 ---- /dev/null -+++ b/nova/virt/libvirt/instancejobtracker.py -@@ -0,0 +1,98 @@ -+# Copyright 2015 NTT corp. -+# All Rights Reserved. -+# Licensed under the Apache License, Version 2.0 (the "License"); you may -+# not use this file except in compliance with the License. You may obtain -+# a copy of the License at -+# -+# http://www.apache.org/licenses/LICENSE-2.0 -+# -+# Unless required by applicable law or agreed to in writing, software -+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -+# License for the specific language governing permissions and limitations -+# under the License. -+ -+ -+import collections -+import errno -+import os -+import signal -+ -+from oslo_log import log as logging -+ -+from nova.i18n import _LE -+from nova.i18n import _LW -+ -+ -+LOG = logging.getLogger(__name__) -+ -+ -+class InstanceJobTracker(object): -+ def __init__(self): -+ self.jobs = collections.defaultdict(list) -+ -+ def add_job(self, instance, pid): -+ """Appends process_id of instance to cache. -+ -+ This method will store the pid of a process in cache as -+ a key: value pair which will be used to kill the process if it -+ is running while deleting the instance. Instance uuid is used as -+ a key in the cache and pid will be the value. -+ -+ :param instance: Object of instance -+ :param pid: Id of the process -+ """ -+ self.jobs[instance.uuid].append(pid) -+ -+ def remove_job(self, instance, pid): -+ """Removes pid of process from cache. -+ -+ This method will remove the pid of a process from the cache. -+ -+ :param instance: Object of instance -+ :param pid: Id of the process -+ """ -+ uuid = instance.uuid -+ if uuid in self.jobs and pid in self.jobs[uuid]: -+ self.jobs[uuid].remove(pid) -+ -+ # remove instance.uuid if no pid's remaining -+ if not self.jobs[uuid]: -+ self.jobs.pop(uuid, None) -+ -+ def terminate_jobs(self, instance): -+ """Kills the running processes for given instance. -+ -+ This method is used to kill all running processes of the instance if -+ it is deleted in between. -+ -+ :param instance: Object of instance -+ """ -+ pids_to_remove = list(self.jobs.get(instance.uuid, [])) -+ for pid in pids_to_remove: -+ try: -+ # Try to kill the process -+ os.kill(pid, signal.SIGKILL) -+ except OSError as exc: -+ if exc.errno != errno.ESRCH: -+ LOG.error(_LE('Failed to kill process %(pid)s ' -+ 'due to %(reason)s, while deleting the ' -+ 'instance.'), {'pid': pid, 'reason': exc}, -+ instance=instance) -+ -+ try: -+ # Check if the process is still alive. -+ os.kill(pid, 0) -+ except OSError as exc: -+ if exc.errno != errno.ESRCH: -+ LOG.error(_LE('Unexpected error while checking process ' -+ '%(pid)s.'), {'pid': pid}, -+ instance=instance) -+ else: -+ # The process is still around -+ LOG.warn(_LW("Failed to kill a long running process " -+ "%(pid)s related to the instance when " -+ "deleting it."), {'pid': pid}, -+ instance=instance) -+ -+ self.remove_job(instance, pid) -diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py -index 7b80464..83d5ba3 100644 ---- a/nova/virt/libvirt/utils.py -+++ b/nova/virt/libvirt/utils.py -@@ -294,13 +294,16 @@ def get_disk_backing_file(path, basename=True): - return backing_file - - --def copy_image(src, dest, host=None, receive=False): -+def copy_image(src, dest, host=None, receive=False, -+ on_execute=None, on_completion=None): - """Copy a disk image to an existing directory - - :param src: Source image - :param dest: Destination path - :param host: Remote host - :param receive: Reverse the rsync direction -+ :param on_execute: Callback method to store pid of process in cache -+ :param on_completion: Callback method to remove pid of process from cache - """ - - if not host: -@@ -322,11 +325,14 @@ def copy_image(src, dest, host=None, receive=False): - # Do a relatively light weight test first, so that we - # can fall back to scp, without having run out of space - # on the destination for example. -- execute('rsync', '--sparse', '--compress', '--dry-run', src, dest) -+ execute('rsync', '--sparse', '--compress', '--dry-run', src, dest, -+ on_execute=on_execute, on_completion=on_completion) - except processutils.ProcessExecutionError: -- execute('scp', src, dest) -+ execute('scp', src, dest, on_execute=on_execute, -+ on_completion=on_completion) - else: -- execute('rsync', '--sparse', '--compress', src, dest) -+ execute('rsync', '--sparse', '--compress', src, dest, -+ on_execute=on_execute, on_completion=on_completion) - - - def write_to_file(path, contents, umask=None): diff --git a/sys-cluster/nova/files/CVE-2015-3280_2015.1.1.patch.patch b/sys-cluster/nova/files/CVE-2015-3280_2015.1.1.patch.patch deleted file mode 100644 index ff3b3eeb0b36..000000000000 --- a/sys-cluster/nova/files/CVE-2015-3280_2015.1.1.patch.patch +++ /dev/null @@ -1,210 +0,0 @@ -From 690c05ca495f1d55a469724c94e1551cbfa836f2 Mon Sep 17 00:00:00 2001 -From: Rajesh Tailor <rajesh.tailor@nttdata.com> -Date: Wed, 4 Mar 2015 05:05:19 -0800 -Subject: [PATCH] Delete orphaned instance files from compute nodes - -While resizing/revert-resizing instance, if instance gets deleted -in between, then instance files remains either on the source or -destination compute node. - -To address this issue, added a new periodic task -'_cleanup_incomplete_migrations' which takes care of deleting -instance files from source/destination compute nodes and then -mark migration record as failed so that it doesn't appear again -in the next periodic task run. - -SecurityImpact - -Closes-Bug: 1392527 -Change-Id: I9866d8e32e99b9f907921f4b226edf7b62bd83a7 -(cherry picked from commit 4655751cdd97a4b527a25c7c0a96044ba212cd19) ---- - nova/compute/manager.py | 61 ++++++++++++++++++++++-- - nova/tests/unit/compute/test_compute_mgr.py | 72 +++++++++++++++++++++++++++++ - 2 files changed, 129 insertions(+), 4 deletions(-) - -diff --git a/nova/compute/manager.py b/nova/compute/manager.py -index bf5585e..24a5811 100644 ---- a/nova/compute/manager.py -+++ b/nova/compute/manager.py -@@ -267,15 +267,21 @@ def errors_out_migration(function): - def decorated_function(self, context, *args, **kwargs): - try: - return function(self, context, *args, **kwargs) -- except Exception: -+ except Exception as ex: - with excutils.save_and_reraise_exception(): - wrapped_func = utils.get_wrapped_function(function) - keyed_args = safe_utils.getcallargs(wrapped_func, context, - *args, **kwargs) - migration = keyed_args['migration'] -- status = migration.status -- if status not in ['migrating', 'post-migrating']: -- return -+ -+ # NOTE(rajesht): If InstanceNotFound error is thrown from -+ # decorated function, migration status should be set to -+ # 'error', without checking current migration status. -+ if not isinstance(ex, exception.InstanceNotFound): -+ status = migration.status -+ if status not in ['migrating', 'post-migrating']: -+ return -+ - migration.status = 'error' - try: - with migration.obj_as_admin(): -@@ -3727,6 +3733,7 @@ class ComputeManager(manager.Manager): - @wrap_exception() - @reverts_task_state - @wrap_instance_event -+ @errors_out_migration - @wrap_instance_fault - def revert_resize(self, context, instance, migration, reservations): - """Destroys the new instance on the destination machine. -@@ -3783,6 +3790,7 @@ class ComputeManager(manager.Manager): - @wrap_exception() - @reverts_task_state - @wrap_instance_event -+ @errors_out_migration - @wrap_instance_fault - def finish_revert_resize(self, context, instance, reservations, migration): - """Finishes the second half of reverting a resize. -@@ -6578,6 +6586,51 @@ class ComputeManager(manager.Manager): - with utils.temporary_mutation(context, read_deleted='yes'): - instance.save() - -+ @periodic_task.periodic_task(spacing=CONF.instance_delete_interval) -+ def _cleanup_incomplete_migrations(self, context): -+ """Delete instance files on failed resize/revert-resize operation -+ -+ During resize/revert-resize operation, if that instance gets deleted -+ in-between then instance files might remain either on source or -+ destination compute node because of race condition. -+ """ -+ LOG.debug('Cleaning up deleted instances with incomplete migration ') -+ migration_filters = {'host': CONF.host, -+ 'status': 'error'} -+ migrations = objects.MigrationList.get_by_filters(context, -+ migration_filters) -+ -+ if not migrations: -+ return -+ -+ inst_uuid_from_migrations = set([migration.instance_uuid for migration -+ in migrations]) -+ -+ inst_filters = {'deleted': True, 'soft_deleted': False, -+ 'uuid': inst_uuid_from_migrations} -+ attrs = ['info_cache', 'security_groups', 'system_metadata'] -+ with utils.temporary_mutation(context, read_deleted='yes'): -+ instances = objects.InstanceList.get_by_filters( -+ context, inst_filters, expected_attrs=attrs, use_slave=True) -+ -+ for instance in instances: -+ if instance.host != CONF.host: -+ for migration in migrations: -+ if instance.uuid == migration.instance_uuid: -+ # Delete instance files if not cleanup properly either -+ # from the source or destination compute nodes when -+ # the instance is deleted during resizing. -+ self.driver.delete_instance_files(instance) -+ try: -+ migration.status = 'failed' -+ with migration.obj_as_admin(): -+ migration.save() -+ except exception.MigrationNotFound: -+ LOG.warning(_LW("Migration %s is not found."), -+ migration.id, context=context, -+ instance=instance) -+ break -+ - @messaging.expected_exceptions(exception.InstanceQuiesceNotSupported, - exception.NovaException, - NotImplementedError) -diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py -index 4b7234e..ee1ab47 100644 ---- a/nova/tests/unit/compute/test_compute_mgr.py -+++ b/nova/tests/unit/compute/test_compute_mgr.py -@@ -1374,6 +1374,78 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): - self.assertFalse(c.cleaned) - self.assertEqual('1', c.system_metadata['clean_attempts']) - -+ @mock.patch.object(objects.Migration, 'obj_as_admin') -+ @mock.patch.object(objects.Migration, 'save') -+ @mock.patch.object(objects.MigrationList, 'get_by_filters') -+ @mock.patch.object(objects.InstanceList, 'get_by_filters') -+ def _test_cleanup_incomplete_migrations(self, inst_host, -+ mock_inst_get_by_filters, -+ mock_migration_get_by_filters, -+ mock_save, mock_obj_as_admin): -+ def fake_inst(context, uuid, host): -+ inst = objects.Instance(context) -+ inst.uuid = uuid -+ inst.host = host -+ return inst -+ -+ def fake_migration(uuid, status, inst_uuid, src_host, dest_host): -+ migration = objects.Migration() -+ migration.uuid = uuid -+ migration.status = status -+ migration.instance_uuid = inst_uuid -+ migration.source_compute = src_host -+ migration.dest_compute = dest_host -+ return migration -+ -+ fake_instances = [fake_inst(self.context, '111', inst_host), -+ fake_inst(self.context, '222', inst_host)] -+ -+ fake_migrations = [fake_migration('123', 'error', '111', -+ 'fake-host', 'fake-mini'), -+ fake_migration('456', 'error', '222', -+ 'fake-host', 'fake-mini')] -+ -+ mock_migration_get_by_filters.return_value = fake_migrations -+ mock_inst_get_by_filters.return_value = fake_instances -+ -+ with mock.patch.object(self.compute.driver, 'delete_instance_files'): -+ self.compute._cleanup_incomplete_migrations(self.context) -+ -+ # Ensure that migration status is set to 'failed' after instance -+ # files deletion for those instances whose instance.host is not -+ # same as compute host where periodic task is running. -+ for inst in fake_instances: -+ if inst.host != CONF.host: -+ for mig in fake_migrations: -+ if inst.uuid == mig.instance_uuid: -+ self.assertEqual('failed', mig.status) -+ -+ def test_cleanup_incomplete_migrations_dest_node(self): -+ """Test to ensure instance files are deleted from destination node. -+ -+ If instance gets deleted during resizing/revert-resizing operation, -+ in that case instance files gets deleted from instance.host (source -+ host here), but there is possibility that instance files could be -+ present on destination node. -+ This test ensures that `_cleanup_incomplete_migration` periodic -+ task deletes orphaned instance files from destination compute node. -+ """ -+ self.flags(host='fake-mini') -+ self._test_cleanup_incomplete_migrations('fake-host') -+ -+ def test_cleanup_incomplete_migrations_source_node(self): -+ """Test to ensure instance files are deleted from source node. -+ -+ If instance gets deleted during resizing/revert-resizing operation, -+ in that case instance files gets deleted from instance.host (dest -+ host here), but there is possibility that instance files could be -+ present on source node. -+ This test ensures that `_cleanup_incomplete_migration` periodic -+ task deletes orphaned instance files from source compute node. -+ """ -+ self.flags(host='fake-host') -+ self._test_cleanup_incomplete_migrations('fake-mini') -+ - def test_attach_interface_failure(self): - # Test that the fault methods are invoked when an attach fails - db_instance = fake_instance.fake_db_instance() --- -2.4.5 - - 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 deleted file mode 100644 index 9f2429df1abc..000000000000 --- a/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0001.patch +++ /dev/null @@ -1,267 +0,0 @@ -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 deleted file mode 100644 index 2ffca9f9cf8a..000000000000 --- a/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0002.patch +++ /dev/null @@ -1,168 +0,0 @@ -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 deleted file mode 100644 index b542041b5311..000000000000 --- a/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0003.patch +++ /dev/null @@ -1,171 +0,0 @@ -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 - diff --git a/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0004.patch b/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0004.patch deleted file mode 100644 index 113e9f4736b1..000000000000 --- a/sys-cluster/nova/files/cve-2015-7548-stable-liberty-0004.patch +++ /dev/null @@ -1,132 +0,0 @@ -From cf197ec2d682fb4da777df2291ca7ef101f73b77 Mon Sep 17 00:00:00 2001 -From: Matt Riedemann <mriedem@us.ibm.com> -Date: Mon, 16 Nov 2015 13:11:09 -0800 -Subject: xen: mask passwords in volume connection_data dict - -The connection_data dict can have credentials in it, so we need to scrub -those before putting the stringified dict into the StorageError message -and raising that up and when logging the dict. - -Note that strutils.mask_password converts the dict to a string using -six.text_type so we don't have to do that conversion first. - -SecurityImpact - -Change-Id: Ic5f4d4c26794550a92481bf2b725ef5eafa581b2 -Closes-Bug: #1516765 -(cherry picked from commit 8b289237ed6d53738c22878decf0c429301cf3d0) ---- - nova/tests/unit/virt/xenapi/test_volume_utils.py | 16 ++++++++++++++-- - nova/tests/unit/virt/xenapi/test_volumeops.py | 16 ++++++++++++++++ - nova/virt/xenapi/volume_utils.py | 3 ++- - nova/virt/xenapi/volumeops.py | 6 +++++- - 4 files changed, 37 insertions(+), 4 deletions(-) - -diff --git a/nova/tests/unit/virt/xenapi/test_volume_utils.py b/nova/tests/unit/virt/xenapi/test_volume_utils.py -index 6bd80b0..d08eede 100644 ---- a/nova/tests/unit/virt/xenapi/test_volume_utils.py -+++ b/nova/tests/unit/virt/xenapi/test_volume_utils.py -@@ -165,14 +165,26 @@ class ParseVolumeInfoTestCase(stubs.XenAPITestBaseNoDB): - 'target_lun': None, - 'auth_method': 'CHAP', - 'auth_username': 'username', -- 'auth_password': 'password'}} -+ 'auth_password': 'verybadpass'}} - - def test_parse_volume_info_parsing_auth_details(self): - conn_info = self._make_connection_info() - result = volume_utils._parse_volume_info(conn_info['data']) - - self.assertEqual('username', result['chapuser']) -- self.assertEqual('password', result['chappassword']) -+ self.assertEqual('verybadpass', result['chappassword']) -+ -+ def test_parse_volume_info_missing_details(self): -+ # Tests that a StorageError is raised if volume_id, target_host, or -+ # target_ign is missing from connection_data. Also ensures that the -+ # auth_password value is not present in the StorageError message. -+ for data_key_to_null in ('volume_id', 'target_portal', 'target_iqn'): -+ conn_info = self._make_connection_info() -+ conn_info['data'][data_key_to_null] = None -+ ex = self.assertRaises(exception.StorageError, -+ volume_utils._parse_volume_info, -+ conn_info['data']) -+ self.assertNotIn('verybadpass', six.text_type(ex)) - - def test_get_device_number_raise_exception_on_wrong_mountpoint(self): - self.assertRaises( -diff --git a/nova/tests/unit/virt/xenapi/test_volumeops.py b/nova/tests/unit/virt/xenapi/test_volumeops.py -index 0e840bb..58c3fa5 100644 ---- a/nova/tests/unit/virt/xenapi/test_volumeops.py -+++ b/nova/tests/unit/virt/xenapi/test_volumeops.py -@@ -381,6 +381,22 @@ class AttachVolumeTestCase(VolumeOpsTestBase): - mock_intro.assert_called_once_with(self.session, "sr", - target_lun="lun") - -+ @mock.patch.object(volume_utils, "introduce_vdi") -+ @mock.patch.object(volumeops.LOG, 'debug') -+ def test_connect_hypervisor_to_volume_mask_password(self, mock_debug, -+ mock_intro): -+ # Tests that the connection_data is scrubbed before logging. -+ data = {'auth_password': 'verybadpass'} -+ self.ops._connect_hypervisor_to_volume("sr", data) -+ self.assertTrue(mock_debug.called, 'LOG.debug was not called') -+ password_logged = False -+ for call in mock_debug.call_args_list: -+ # The call object is a tuple of (args, kwargs) -+ if 'verybadpass' in call[0]: -+ password_logged = True -+ break -+ self.assertFalse(password_logged, 'connection_data was not scrubbed') -+ - @mock.patch.object(vm_utils, "is_vm_shutdown") - @mock.patch.object(vm_utils, "create_vbd") - def test_attach_volume_to_vm_plug(self, mock_vbd, mock_shutdown): -diff --git a/nova/virt/xenapi/volume_utils.py b/nova/virt/xenapi/volume_utils.py -index c7bfe32..af47e26 100644 ---- a/nova/virt/xenapi/volume_utils.py -+++ b/nova/virt/xenapi/volume_utils.py -@@ -24,6 +24,7 @@ import string - from eventlet import greenthread - from oslo_config import cfg - from oslo_log import log as logging -+from oslo_utils import strutils - - from nova import exception - from nova.i18n import _, _LE, _LW -@@ -84,7 +85,7 @@ def _parse_volume_info(connection_data): - target_iqn is None): - raise exception.StorageError( - reason=_('Unable to obtain target information %s') % -- connection_data) -+ strutils.mask_password(connection_data)) - volume_info = {} - volume_info['id'] = volume_id - volume_info['target'] = target_host -diff --git a/nova/virt/xenapi/volumeops.py b/nova/virt/xenapi/volumeops.py -index f816853..b9e73e2 100644 ---- a/nova/virt/xenapi/volumeops.py -+++ b/nova/virt/xenapi/volumeops.py -@@ -19,6 +19,7 @@ Management class for Storage-related functions (attach, detach, etc). - - from oslo_log import log as logging - from oslo_utils import excutils -+from oslo_utils import strutils - - from nova import exception - from nova.i18n import _LI, _LW -@@ -91,7 +92,10 @@ class VolumeOps(object): - return (sr_ref, sr_uuid) - - def _connect_hypervisor_to_volume(self, sr_ref, connection_data): -- LOG.debug("Connect volume to hypervisor: %s", connection_data) -+ # connection_data can have credentials in it so make sure to scrub -+ # those before logging. -+ LOG.debug("Connect volume to hypervisor: %s", -+ strutils.mask_password(connection_data)) - if 'vdi_uuid' in connection_data: - vdi_ref = volume_utils.introduce_vdi( - self._session, sr_ref, --- -cgit v0.11.2 - diff --git a/sys-cluster/nova/nova-2015.1.9999.ebuild b/sys-cluster/nova/nova-2015.1.9999.ebuild deleted file mode 100644 index 517c097312d1..000000000000 --- a/sys-cluster/nova/nova-2015.1.9999.ebuild +++ /dev/null @@ -1,251 +0,0 @@ -# Copyright 1999-2015 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 -# $Id$ - -EAPI=5 -PYTHON_COMPAT=( python2_7 ) - -inherit distutils-r1 eutils git-r3 linux-info multilib user - -DESCRIPTION="Cloud computing fabric controller (main part of an IaaS system) in Python" -HOMEPAGE="https://launchpad.net/nova" -EGIT_REPO_URI="https://github.com/openstack/nova.git" -EGIT_BRANCH="stable/kilo" - -LICENSE="Apache-2.0" -SLOT="0" -KEYWORDS="" -IUSE="+compute compute-only iscsi +memcached mysql +novncproxy openvswitch postgres +rabbitmq sqlite test" -REQUIRED_USE=" - !compute-only? ( || ( mysql postgres sqlite ) ) - compute-only? ( compute !rabbitmq !memcached !mysql !postgres !sqlite )" - -DEPEND=" - dev-python/setuptools[${PYTHON_USEDEP}] - >=dev-python/pbr-0.8[${PYTHON_USEDEP}] - <dev-python/pbr-1.0[${PYTHON_USEDEP}] - app-admin/sudo - test? ( - ${RDEPEND} - >=dev-python/coverage-3.6[${PYTHON_USEDEP}] - >=dev-python/fixtures-0.3.14[${PYTHON_USEDEP}] - <dev-python/fixtures-1.3.0[${PYTHON_USEDEP}] - >=dev-python/mock-1.0[${PYTHON_USEDEP}] - <dev-python/mock-1.1.0[${PYTHON_USEDEP}] - >=dev-python/mox3-0.7.0[${PYTHON_USEDEP}] - <dev-python/mox3-0.8.0[${PYTHON_USEDEP}] - dev-python/mysql-python[${PYTHON_USEDEP}] - dev-python/psycopg[${PYTHON_USEDEP}] - >=dev-python/python-barbicanclient-3.0.1[${PYTHON_USEDEP}] - <dev-python/python-barbicanclient-3.1.0[${PYTHON_USEDEP}] - >=dev-python/python-ironicclient-0.4.1[${PYTHON_USEDEP}] - <dev-python/python-ironicclient-0.6.0[${PYTHON_USEDEP}] - >=dev-python/subunit-0.0.18[${PYTHON_USEDEP}] - >=dev-python/requests-mock-0.6.0[${PYTHON_USEDEP}] - >=dev-python/sphinx-1.1.2[${PYTHON_USEDEP}] - !~dev-python/sphinx-1.2.0[${PYTHON_USEDEP}] - <dev-python/sphinx-1.3[${PYTHON_USEDEP}] - >=dev-python/oslo-sphinx-2.5.0[${PYTHON_USEDEP}] - <dev-python/oslo-sphinx-2.6.0[${PYTHON_USEDEP}] - >=dev-python/oslotest-1.5.1[${PYTHON_USEDEP}] - <dev-python/oslotest-1.6.0[${PYTHON_USEDEP}] - >=dev-python/testrepository-0.0.18[${PYTHON_USEDEP}] - >=dev-python/testtools-0.9.36[${PYTHON_USEDEP}] - !~dev-python/testtools-1.2.0[${PYTHON_USEDEP}] - >=dev-python/tempest-lib-0.4.0[${PYTHON_USEDEP}] - <dev-python/tempest-lib-0.5.0[${PYTHON_USEDEP}] - >=dev-python/suds-0.4[${PYTHON_USEDEP}] - >=dev-python/oslo-vmware-0.11.1[${PYTHON_USEDEP}] - <dev-python/oslo-vmware-0.12.0[${PYTHON_USEDEP}] - )" - -# barbicanclient is in here for doc generation -RDEPEND=" - compute-only? ( - >=dev-python/sqlalchemy-0.9.7[${PYTHON_USEDEP}] - <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}] - ) - sqlite? ( - >=dev-python/sqlalchemy-0.9.7[sqlite,${PYTHON_USEDEP}] - <=dev-python/sqlalchemy-0.9.99[sqlite,${PYTHON_USEDEP}] - ) - mysql? ( - dev-python/mysql-python - >=dev-python/sqlalchemy-0.9.7[${PYTHON_USEDEP}] - <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}] - ) - postgres? ( - dev-python/psycopg:2 - >=dev-python/sqlalchemy-0.9.7[${PYTHON_USEDEP}] - <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}] - ) - >=dev-python/boto-2.32.1[${PYTHON_USEDEP}] - >=dev-python/decorator-3.4.0[${PYTHON_USEDEP}] - >=dev-python/eventlet-0.16.1[${PYTHON_USEDEP}] - !~dev-python/eventlet-0.17.0[${PYTHON_USEDEP}] - >=dev-python/jinja-2.6[${PYTHON_USEDEP}] - >=dev-python/keystonemiddleware-1.5.0[${PYTHON_USEDEP}] - <dev-python/keystonemiddleware-1.6.0[${PYTHON_USEDEP}] - >=dev-python/lxml-2.3[${PYTHON_USEDEP}] - >=dev-python/routes-1.12.3-r1[${PYTHON_USEDEP}] - !~dev-python/routes-2.0[${PYTHON_USEDEP}] - >=dev-python/webob-1.2.3[${PYTHON_USEDEP}] - >=dev-python/greenlet-0.3.2[${PYTHON_USEDEP}] - >=dev-python/pastedeploy-1.5.0-r1[${PYTHON_USEDEP}] - dev-python/paste[${PYTHON_USEDEP}] - >=dev-python/sqlalchemy-migrate-0.9.5[${PYTHON_USEDEP}] - !~dev-python/sqlalchemy-migrate-0.9.8[${PYTHON_USEDEP}] - <dev-python/sqlalchemy-migrate-0.10.0[${PYTHON_USEDEP}] - >=dev-python/netaddr-0.7.12[${PYTHON_USEDEP}] - >=dev-python/paramiko-1.13.0[${PYTHON_USEDEP}] - dev-python/pyasn1[${PYTHON_USEDEP}] - >=dev-python/Babel-1.3[${PYTHON_USEDEP}] - >=dev-python/iso8601-0.1.9[${PYTHON_USEDEP}] - >=dev-python/jsonschema-2.0.0[${PYTHON_USEDEP}] - <dev-python/jsonschema-3.0.0[${PYTHON_USEDEP}] - >=dev-python/python-cinderclient-1.1.0[${PYTHON_USEDEP}] - <dev-python/python-cinderclient-1.2.0[${PYTHON_USEDEP}] - >=dev-python/python-neutronclient-2.4.0[${PYTHON_USEDEP}] - <dev-python/python-neutronclient-2.5.0[${PYTHON_USEDEP}] - >=dev-python/python-glanceclient-0.15.0[${PYTHON_USEDEP}] - <dev-python/python-glanceclient-0.18.0[${PYTHON_USEDEP}] - >=dev-python/python-barbicanclient-3.0.1[${PYTHON_USEDEP}] - <dev-python/python-barbicanclient-3.1.0[${PYTHON_USEDEP}] - >=dev-python/six-1.9.0[${PYTHON_USEDEP}] - >=dev-python/stevedore-1.3.0[${PYTHON_USEDEP}] - <dev-python/stevedore-1.4.0[${PYTHON_USEDEP}] - >=dev-python/websockify-0.6.0[${PYTHON_USEDEP}] - <dev-python/websockify-0.7.0[${PYTHON_USEDEP}] - >=dev-python/oslo-concurrency-1.8.2[${PYTHON_USEDEP}] - <dev-python/oslo-concurrency-1.9.0[${PYTHON_USEDEP}] - >=dev-python/oslo-config-1.9.3[${PYTHON_USEDEP}] - <dev-python/oslo-config-1.10.0[${PYTHON_USEDEP}] - >=dev-python/oslo-context-0.2.0[${PYTHON_USEDEP}] - <dev-python/oslo-context-0.3.0[${PYTHON_USEDEP}] - >=dev-python/oslo-log-1.0.0[${PYTHON_USEDEP}] - <dev-python/oslo-log-1.1.0[${PYTHON_USEDEP}] - >=dev-python/oslo-serialization-1.4.0[${PYTHON_USEDEP}] - <dev-python/oslo-serialization-1.5.0[${PYTHON_USEDEP}] - >=dev-python/oslo-utils-1.4.0[${PYTHON_USEDEP}] - !~dev-python/oslo-utils-1.4.1[${PYTHON_USEDEP}] - <dev-python/oslo-utils-1.5.0[${PYTHON_USEDEP}] - >=dev-python/oslo-db-1.7.0[${PYTHON_USEDEP}] - <dev-python/oslo-db-1.8.0[${PYTHON_USEDEP}] - >=dev-python/oslo-rootwrap-1.6.0[${PYTHON_USEDEP}] - <dev-python/oslo-rootwrap-1.7.0[${PYTHON_USEDEP}] - >=dev-python/oslo-messaging-1.8.0[${PYTHON_USEDEP}] - <dev-python/oslo-messaging-1.9.0[${PYTHON_USEDEP}] - >=dev-python/oslo-i18n-1.5.0[${PYTHON_USEDEP}] - <dev-python/oslo-i18n-1.6.0[${PYTHON_USEDEP}] - >=dev-python/rfc3986-0.2.0[${PYTHON_USEDEP}] - >=dev-python/oslo-middleware-1.0.0[${PYTHON_USEDEP}] - <dev-python/oslo-middleware-1.1.0[${PYTHON_USEDEP}] - >=dev-python/psutil-1.1.1[${PYTHON_USEDEP}] - <dev-python/psutil-2.0.0[${PYTHON_USEDEP}] - dev-python/libvirt-python[${PYTHON_USEDEP}] - app-emulation/libvirt[iscsi?] - novncproxy? ( www-apps/novnc ) - sys-apps/iproute2 - openvswitch? ( net-misc/openvswitch ) - rabbitmq? ( net-misc/rabbitmq-server ) - memcached? ( net-misc/memcached - dev-python/python-memcached ) - sys-fs/sysfsutils - sys-fs/multipath-tools - net-misc/bridge-utils - compute? ( - app-cdr/cdrkit - app-emulation/qemu - ) - iscsi? ( - sys-fs/lsscsi - >=sys-block/open-iscsi-2.0.872-r3 - )" - -PATCHES=( -) - -pkg_setup() { - linux-info_pkg_setup - CONFIG_CHECK_MODULES="BLK_DEV_NBD VHOST_NET IP6_NF_FILTER IP6_NF_IPTABLES IP_NF_TARGET_REJECT \ - IP_NF_MANGLE IP_NF_TARGET_MASQUERADE NF_NAT_IPV4 IP_NF_FILTER IP_NF_IPTABLES \ - NF_CONNTRACK_IPV4 NF_DEFRAG_IPV4 NF_NAT_IPV4 NF_NAT NF_CONNTRACK NETFILTER_XTABLES \ - ISCSI_TCP SCSI_DH DM_MULTIPATH DM_SNAPSHOT" - if linux_config_exists; then - for module in ${CONFIG_CHECK_MODULES}; do - linux_chkconfig_present ${module} || ewarn "${module} needs to be enabled in kernel" - done - fi - enewgroup nova - enewuser nova -1 -1 /var/lib/nova nova -} - -python_prepare_all() { - sed -i '/^hacking/d' test-requirements.txt || die - sed -i 's/python/python2\.7/g' tools/config/generate_sample.sh || die - distutils-r1_python_prepare_all -} - -python_compile() { - distutils-r1_python_compile - ./tools/config/generate_sample.sh -b ./ -p nova -o etc/nova || die -} - -python_test() { - testr init - testr run --parallel || die "failed testsuite under python2.7" -} - -python_install() { - distutils-r1_python_install - - if use !compute-only; then - for svc in api cert conductor consoleauth network scheduler spicehtml5proxy xvpvncproxy; do - newinitd "${FILESDIR}/nova.initd" "nova-${svc}" - done - fi - use compute && newinitd "${FILESDIR}/nova.initd" "nova-compute" - use novncproxy && newinitd "${FILESDIR}/nova.initd" "nova-novncproxy" - - diropts -m 0750 -o nova -g qemu - dodir /var/log/nova /var/lib/nova/instances - diropts -m 0750 -o nova -g nova - - insinto /etc/nova - insopts -m 0640 -o nova -g nova - newins "etc/nova/nova.conf.sample" "nova.conf" - doins "etc/nova/api-paste.ini" - doins "etc/nova/logging_sample.conf" - doins "etc/nova/policy.json" - doins "etc/nova/rootwrap.conf" - #rootwrap filters - insinto /etc/nova/rootwrap.d - doins "etc/nova/rootwrap.d/api-metadata.filters" - doins "etc/nova/rootwrap.d/compute.filters" - doins "etc/nova/rootwrap.d/network.filters" - #copy migration conf file (not coppied on install via setup.py script) - insopts -m 0644 - insinto /usr/$(get_libdir)/python2.7/site-packages/nova/db/sqlalchemy/migrate_repo/ - doins "nova/db/sqlalchemy/migrate_repo/migrate.cfg" - #copy the CA cert dir (not coppied on install via setup.py script) - cp -R "${S}/nova/CA" "${D}/usr/$(get_libdir)/python2.7/site-packages/nova/" || die "installing CA files failed" - - #add sudoers definitions for user nova - insinto /etc/sudoers.d/ - insopts -m 0600 -o root -g root - doins "${FILESDIR}/nova-sudoers" - - if use iscsi ; then - # Install udev rules for handle iscsi disk with right links under /dev - udev_newrules "${FILESDIR}/openstack-scsi-disk.rules" 60-openstack-scsi-disk.rules - - insinto /etc/nova/ - doins "${FILESDIR}/scsi-openscsi-link.sh" - fi -} - -pkg_postinst() { - if use iscsi ; then - elog "iscsid needs to be running if you want cinder to connect" - fi -} |