diff options
author | Matthew Thode <prometheanfire@gentoo.org> | 2014-04-06 06:32:20 +0000 |
---|---|---|
committer | Matthew Thode <prometheanfire@gentoo.org> | 2014-04-06 06:32:20 +0000 |
commit | 23c0e71812e108809bcca973cea36b19f5ca9e0a (patch) | |
tree | b1cd2fb35a6df1b2cd227b90aeedb1eb71bb3cc3 /sys-cluster | |
parent | 2013.2.3 (diff) | |
download | gentoo-2-23c0e71812e108809bcca973cea36b19f5ca9e0a.tar.gz gentoo-2-23c0e71812e108809bcca973cea36b19f5ca9e0a.tar.bz2 gentoo-2-23c0e71812e108809bcca973cea36b19f5ca9e0a.zip |
2013.2.3
(Portage version: 2.2.8-r1/cvs/Linux x86_64, signed Manifest commit with key 0x2471eb3e40ac5ac3)
Diffstat (limited to 'sys-cluster')
-rw-r--r-- | sys-cluster/nova/ChangeLog | 9 | ||||
-rw-r--r-- | sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch | 732 | ||||
-rw-r--r-- | sys-cluster/nova/nova-2013.2.3.ebuild (renamed from sys-cluster/nova/nova-2013.2.2-r1.ebuild) | 39 | ||||
-rw-r--r-- | sys-cluster/nova/nova-2013.2.9999.ebuild | 4 |
4 files changed, 24 insertions, 760 deletions
diff --git a/sys-cluster/nova/ChangeLog b/sys-cluster/nova/ChangeLog index 9d5e539a0861..fc37b78f545e 100644 --- a/sys-cluster/nova/ChangeLog +++ b/sys-cluster/nova/ChangeLog @@ -1,6 +1,13 @@ # ChangeLog for sys-cluster/nova # Copyright 1999-2014 Gentoo Foundation; Distributed under the GPL v2 -# $Header: /var/cvsroot/gentoo-x86/sys-cluster/nova/ChangeLog,v 1.57 2014/04/06 05:05:47 prometheanfire Exp $ +# $Header: /var/cvsroot/gentoo-x86/sys-cluster/nova/ChangeLog,v 1.58 2014/04/06 06:32:19 prometheanfire Exp $ + +*nova-2013.2.3 (06 Apr 2014) + + 06 Apr 2014; Matthew Thode <prometheanfire@gentoo.org> +nova-2013.2.3.ebuild, + -files/2013.2.2-CVE-2014-0134.patch, -nova-2013.2.2-r1.ebuild, + nova-2013.2.9999.ebuild: + 2013.2.3 06 Apr 2014; Matthew Thode <prometheanfire@gentoo.org> -nova-2013.1.5.ebuild, -nova-2013.1.9999.ebuild: diff --git a/sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch b/sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch deleted file mode 100644 index 04d14cae392a..000000000000 --- a/sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch +++ /dev/null @@ -1,732 +0,0 @@ -From 25e761acd56d4c820273fc0245ada06c500c1637 Mon Sep 17 00:00:00 2001 -From: David Ripton <dripton@redhat.com> -Date: Tue, 28 Jan 2014 16:38:51 -0500 -Subject: [PATCH] Persist image format to a file, to prevent attacks based on - changing it - -The attack is based on creating a raw image that looks like a qcow2 -image, and taking advantage of the code that used 'qemu-img info' to -autodetect the image format. - -Now we store the image format to a 'disk.info' file, for Qcow2 and Raw -images, and only autodetect for images that have never been written to -that file. - -SecurityImpact - -Conflicts: - nova/virt/libvirt/imagebackend.py - -Manual tweaks to some mocking in test_imagebackend.py - -Change-Id: I2016efdb3f49a44ec4d677ac596eacc97871f30a -Co-authored-by: Nikola Dipanov <ndipanov@redhat.com> -Closes-bug: #1221190 ---- - nova/exception.py | 8 + - nova/tests/virt/libvirt/test_imagebackend.py | 359 ++++++++++++++++++++++----- - nova/tests/virt/libvirt/test_libvirt.py | 3 + - nova/tests/virt/test_virt_drivers.py | 7 + - nova/utils.py | 14 ++ - nova/virt/libvirt/imagebackend.py | 76 +++++- - 6 files changed, 403 insertions(+), 64 deletions(-) - -diff --git a/nova/exception.py b/nova/exception.py -index 7c17803..770a700 100644 ---- a/nova/exception.py -+++ b/nova/exception.py -@@ -449,6 +449,14 @@ class InvalidDiskFormat(Invalid): - msg_fmt = _("Disk format %(disk_format)s is not acceptable") - - -+class InvalidDiskInfo(Invalid): -+ msg_fmt = _("Disk info file is invalid: %(reason)s") -+ -+ -+class DiskInfoReadWriteFail(Invalid): -+ msg_fmt = _("Failed to read or write disk info file: %(reason)s") -+ -+ - class ImageUnacceptable(Invalid): - msg_fmt = _("Image %(image_id)s is unacceptable: %(reason)s") - -diff --git a/nova/tests/virt/libvirt/test_imagebackend.py b/nova/tests/virt/libvirt/test_imagebackend.py -index 5bfa94d..5424f7b 100644 ---- a/nova/tests/virt/libvirt/test_imagebackend.py -+++ b/nova/tests/virt/libvirt/test_imagebackend.py -@@ -16,6 +16,8 @@ - # under the License. - - import os -+import shutil -+import tempfile - - import fixtures - from oslo.config import cfg -@@ -27,13 +29,13 @@ - from nova import test - from nova.tests import fake_processutils - from nova.tests.virt.libvirt import fake_libvirt_utils -+from nova import utils - from nova.virt.libvirt import imagebackend - - CONF = cfg.CONF - - - class _ImageTestCase(object): -- INSTANCES_PATH = '/instances_path' - - def mock_create_image(self, image): - def create_image(fn, base, size, *args, **kwargs): -@@ -42,10 +44,13 @@ def create_image(fn, base, size, *args, **kwargs): - - def setUp(self): - super(_ImageTestCase, self).setUp() -+ self.INSTANCES_PATH = tempfile.mkdtemp(suffix='instances') - self.flags(disable_process_locking=True, - instances_path=self.INSTANCES_PATH) - self.INSTANCE = {'name': 'instance', - 'uuid': uuidutils.generate_uuid()} -+ self.DISK_INFO_PATH = os.path.join(self.INSTANCES_PATH, -+ self.INSTANCE['uuid'], 'disk.info') - self.NAME = 'fake.vm' - self.TEMPLATE = 'template' - -@@ -63,6 +68,78 @@ def setUp(self): - 'nova.virt.libvirt.imagebackend.libvirt_utils', - fake_libvirt_utils)) - -+ def fake_chown(path, owner_uid=None): -+ return None -+ self.stubs.Set(utils, 'chown', fake_chown) -+ -+ def tearDown(self): -+ super(_ImageTestCase, self).tearDown() -+ shutil.rmtree(self.INSTANCES_PATH) -+ -+ def test_prealloc_image(self): -+ CONF.set_override('preallocate_images', 'space') -+ -+ fake_processutils.fake_execute_clear_log() -+ fake_processutils.stub_out_processutils_execute(self.stubs) -+ image = self.image_class(self.INSTANCE, self.NAME) -+ -+ def fake_fetch(target, *args, **kwargs): -+ return -+ -+ self.stubs.Set(os.path, 'exists', lambda _: True) -+ self.stubs.Set(os, 'access', lambda p, w: True) -+ -+ # Call twice to verify testing fallocate is only called once. -+ image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE) -+ image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE) -+ -+ self.assertEqual(fake_processutils.fake_execute_get_log(), -+ ['fallocate -n -l 1 %s.fallocate_test' % self.PATH, -+ 'fallocate -n -l %s %s' % (self.SIZE, self.PATH), -+ 'fallocate -n -l %s %s' % (self.SIZE, self.PATH)]) -+ -+ def test_prealloc_image_without_write_access(self): -+ CONF.set_override('preallocate_images', 'space') -+ -+ fake_processutils.fake_execute_clear_log() -+ fake_processutils.stub_out_processutils_execute(self.stubs) -+ image = self.image_class(self.INSTANCE, self.NAME) -+ -+ def fake_fetch(target, *args, **kwargs): -+ return -+ -+ self.stubs.Set(image, 'check_image_exists', lambda: True) -+ self.stubs.Set(image, '_can_fallocate', lambda: True) -+ self.stubs.Set(os.path, 'exists', lambda _: True) -+ self.stubs.Set(os, 'access', lambda p, w: False) -+ -+ # Testing fallocate is only called when user has write access. -+ image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE) -+ -+ self.assertEqual(fake_processutils.fake_execute_get_log(), []) -+ -+ -+class RawTestCase(_ImageTestCase, test.NoDBTestCase): -+ -+ SIZE = 1024 -+ -+ def setUp(self): -+ self.image_class = imagebackend.Raw -+ super(RawTestCase, self).setUp() -+ self.stubs.Set(imagebackend.Raw, 'correct_format', lambda _: None) -+ -+ def fake_chown(path, owner_uid=None): -+ return None -+ self.stubs.Set(utils, 'chown', fake_chown) -+ -+ def prepare_mocks(self): -+ fn = self.mox.CreateMockAnything() -+ self.mox.StubOutWithMock(imagebackend.utils.synchronized, -+ '__call__') -+ self.mox.StubOutWithMock(imagebackend.libvirt_utils, 'copy_image') -+ self.mox.StubOutWithMock(imagebackend.disk, 'extend') -+ return fn -+ - def test_cache(self): - self.mox.StubOutWithMock(os.path, 'exists') - if self.OLD_STYLE_INSTANCE_PATH: -@@ -130,66 +207,6 @@ def test_cache_template_exists(self): - - self.mox.VerifyAll() - -- def test_prealloc_image(self): -- CONF.set_override('preallocate_images', 'space') -- -- fake_processutils.fake_execute_clear_log() -- fake_processutils.stub_out_processutils_execute(self.stubs) -- image = self.image_class(self.INSTANCE, self.NAME) -- -- def fake_fetch(target, *args, **kwargs): -- return -- -- self.stubs.Set(os.path, 'exists', lambda _: True) -- self.stubs.Set(os, 'access', lambda p, w: True) -- -- # Call twice to verify testing fallocate is only called once. -- image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE) -- image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE) -- -- self.assertEqual(fake_processutils.fake_execute_get_log(), -- ['fallocate -n -l 1 %s.fallocate_test' % self.PATH, -- 'fallocate -n -l %s %s' % (self.SIZE, self.PATH), -- 'fallocate -n -l %s %s' % (self.SIZE, self.PATH)]) -- -- def test_prealloc_image_without_write_access(self): -- CONF.set_override('preallocate_images', 'space') -- -- fake_processutils.fake_execute_clear_log() -- fake_processutils.stub_out_processutils_execute(self.stubs) -- image = self.image_class(self.INSTANCE, self.NAME) -- -- def fake_fetch(target, *args, **kwargs): -- return -- -- self.stubs.Set(image, 'check_image_exists', lambda: True) -- self.stubs.Set(image, '_can_fallocate', lambda: True) -- self.stubs.Set(os.path, 'exists', lambda _: True) -- self.stubs.Set(os, 'access', lambda p, w: False) -- -- # Testing fallocate is only called when user has write access. -- image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE) -- -- self.assertEqual(fake_processutils.fake_execute_get_log(), []) -- -- --class RawTestCase(_ImageTestCase, test.NoDBTestCase): -- -- SIZE = 1024 -- -- def setUp(self): -- self.image_class = imagebackend.Raw -- super(RawTestCase, self).setUp() -- self.stubs.Set(imagebackend.Raw, 'correct_format', lambda _: None) -- -- def prepare_mocks(self): -- fn = self.mox.CreateMockAnything() -- self.mox.StubOutWithMock(imagebackend.utils.synchronized, -- '__call__') -- self.mox.StubOutWithMock(imagebackend.libvirt_utils, 'copy_image') -- self.mox.StubOutWithMock(imagebackend.disk, 'extend') -- return fn -- - def test_create_image(self): - fn = self.prepare_mocks() - fn(target=self.TEMPLATE_PATH, max_size=None, image_id=None) -@@ -224,16 +241,21 @@ def test_create_image_extend(self): - self.mox.VerifyAll() - - def test_correct_format(self): -- info = self.mox.CreateMockAnything() - self.stubs.UnsetAll() - - self.mox.StubOutWithMock(os.path, 'exists') - self.mox.StubOutWithMock(imagebackend.images, 'qemu_img_info') - -+ def fake_chown(path, owner_uid=None): -+ return None -+ self.stubs.Set(utils, 'chown', fake_chown) -+ - os.path.exists(self.PATH).AndReturn(True) -+ os.path.exists(self.DISK_INFO_PATH).AndReturn(False) - info = self.mox.CreateMockAnything() - info.file_format = 'foo' - imagebackend.images.qemu_img_info(self.PATH).AndReturn(info) -+ os.path.exists(CONF.instances_path).AndReturn(True) - self.mox.ReplayAll() - - image = self.image_class(self.INSTANCE, self.NAME, path=self.PATH) -@@ -241,6 +263,11 @@ def test_correct_format(self): - - self.mox.VerifyAll() - -+ def test_resolve_driver_format(self): -+ image = self.image_class(self.INSTANCE, self.NAME) -+ driver_format = image.resolve_driver_format() -+ self.assertEqual(driver_format, 'raw') -+ - - class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase): - SIZE = 1024 * 1024 * 1024 -@@ -251,6 +278,10 @@ def setUp(self): - self.QCOW2_BASE = (self.TEMPLATE_PATH + - '_%d' % (self.SIZE / (1024 * 1024 * 1024))) - -+ def fake_chown(path, owner_uid=None): -+ return None -+ self.stubs.Set(utils, 'chown', fake_chown) -+ - def prepare_mocks(self): - fn = self.mox.CreateMockAnything() - self.mox.StubOutWithMock(imagebackend.utils.synchronized, -@@ -261,6 +292,80 @@ def prepare_mocks(self): - self.mox.StubOutWithMock(imagebackend.disk, 'extend') - return fn - -+ def test_cache(self): -+ self.mox.StubOutWithMock(os.path, 'exists') -+ if self.OLD_STYLE_INSTANCE_PATH: -+ os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.DISK_INFO_PATH).AndReturn(False) -+ os.path.exists(CONF.instances_path).AndReturn(True) -+ os.path.exists(self.TEMPLATE_DIR).AndReturn(False) -+ os.path.exists(self.INSTANCES_PATH).AndReturn(True) -+ os.path.exists(self.PATH).AndReturn(False) -+ os.path.exists(self.TEMPLATE_PATH).AndReturn(False) -+ fn = self.mox.CreateMockAnything() -+ fn(target=self.TEMPLATE_PATH) -+ self.mox.ReplayAll() -+ -+ image = self.image_class(self.INSTANCE, self.NAME) -+ self.mock_create_image(image) -+ image.cache(fn, self.TEMPLATE) -+ -+ self.mox.VerifyAll() -+ -+ def test_cache_image_exists(self): -+ self.mox.StubOutWithMock(os.path, 'exists') -+ if self.OLD_STYLE_INSTANCE_PATH: -+ os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.DISK_INFO_PATH).AndReturn(False) -+ os.path.exists(self.INSTANCES_PATH).AndReturn(True) -+ os.path.exists(self.TEMPLATE_DIR).AndReturn(True) -+ os.path.exists(self.PATH).AndReturn(True) -+ os.path.exists(self.TEMPLATE_PATH).AndReturn(True) -+ self.mox.ReplayAll() -+ -+ image = self.image_class(self.INSTANCE, self.NAME) -+ image.cache(None, self.TEMPLATE) -+ -+ self.mox.VerifyAll() -+ -+ def test_cache_base_dir_exists(self): -+ self.mox.StubOutWithMock(os.path, 'exists') -+ if self.OLD_STYLE_INSTANCE_PATH: -+ os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.DISK_INFO_PATH).AndReturn(False) -+ os.path.exists(self.INSTANCES_PATH).AndReturn(True) -+ os.path.exists(self.TEMPLATE_DIR).AndReturn(True) -+ os.path.exists(self.PATH).AndReturn(False) -+ os.path.exists(self.TEMPLATE_PATH).AndReturn(False) -+ fn = self.mox.CreateMockAnything() -+ fn(target=self.TEMPLATE_PATH) -+ self.mox.ReplayAll() -+ -+ image = self.image_class(self.INSTANCE, self.NAME) -+ self.mock_create_image(image) -+ image.cache(fn, self.TEMPLATE) -+ -+ self.mox.VerifyAll() -+ -+ def test_cache_template_exists(self): -+ self.mox.StubOutWithMock(os.path, 'exists') -+ if self.OLD_STYLE_INSTANCE_PATH: -+ os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.DISK_INFO_PATH).AndReturn(False) -+ os.path.exists(self.INSTANCES_PATH).AndReturn(True) -+ os.path.exists(self.TEMPLATE_DIR).AndReturn(True) -+ os.path.exists(self.PATH).AndReturn(False) -+ os.path.exists(self.TEMPLATE_PATH).AndReturn(False) -+ fn = self.mox.CreateMockAnything() -+ fn(target=self.TEMPLATE_PATH) -+ self.mox.ReplayAll() -+ -+ image = self.image_class(self.INSTANCE, self.NAME) -+ self.mock_create_image(image) -+ image.cache(fn, self.TEMPLATE) -+ -+ self.mox.VerifyAll() -+ - def test_create_image(self): - fn = self.prepare_mocks() - fn(max_size=None, target=self.TEMPLATE_PATH) -@@ -279,6 +384,8 @@ def test_create_image_with_size(self): - self.mox.StubOutWithMock(os.path, 'exists') - if self.OLD_STYLE_INSTANCE_PATH: - os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.DISK_INFO_PATH).AndReturn(False) -+ os.path.exists(self.INSTANCES_PATH).AndReturn(True) - os.path.exists(self.TEMPLATE_PATH).AndReturn(False) - os.path.exists(self.PATH).AndReturn(False) - os.path.exists(self.PATH).AndReturn(False) -@@ -298,6 +405,8 @@ def test_create_image_too_small(self): - self.mox.StubOutWithMock(imagebackend.disk, 'get_disk_size') - if self.OLD_STYLE_INSTANCE_PATH: - os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.DISK_INFO_PATH).AndReturn(False) -+ os.path.exists(self.INSTANCES_PATH).AndReturn(True) - os.path.exists(self.TEMPLATE_PATH).AndReturn(True) - imagebackend.disk.get_disk_size(self.TEMPLATE_PATH - ).AndReturn(self.SIZE) -@@ -316,6 +425,8 @@ def test_generate_resized_backing_files(self): - 'get_disk_backing_file') - if self.OLD_STYLE_INSTANCE_PATH: - os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.DISK_INFO_PATH).AndReturn(False) -+ os.path.exists(CONF.instances_path).AndReturn(True) - os.path.exists(self.TEMPLATE_PATH).AndReturn(False) - os.path.exists(self.PATH).AndReturn(True) - -@@ -342,6 +453,9 @@ def test_qcow2_exists_and_has_no_backing_file(self): - 'get_disk_backing_file') - if self.OLD_STYLE_INSTANCE_PATH: - os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.DISK_INFO_PATH).AndReturn(False) -+ os.path.exists(self.INSTANCES_PATH).AndReturn(True) -+ - os.path.exists(self.TEMPLATE_PATH).AndReturn(False) - os.path.exists(self.PATH).AndReturn(True) - -@@ -355,6 +469,53 @@ def test_qcow2_exists_and_has_no_backing_file(self): - - self.mox.VerifyAll() - -+ def test_resolve_driver_format(self): -+ image = self.image_class(self.INSTANCE, self.NAME) -+ driver_format = image.resolve_driver_format() -+ self.assertEqual(driver_format, 'qcow2') -+ -+ def test_prealloc_image(self): -+ CONF.set_override('preallocate_images', 'space') -+ -+ fake_processutils.fake_execute_clear_log() -+ fake_processutils.stub_out_processutils_execute(self.stubs) -+ image = self.image_class(self.INSTANCE, self.NAME) -+ -+ def fake_fetch(target, *args, **kwargs): -+ return -+ -+ self.stubs.Set(os.path, 'exists', lambda _: True) -+ self.stubs.Set(os, 'access', lambda p, w: True) -+ -+ # Call twice to verify testing fallocate is only called once. -+ image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE) -+ image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE) -+ -+ self.assertEqual(fake_processutils.fake_execute_get_log(), -+ ['fallocate -n -l 1 %s.fallocate_test' % self.PATH, -+ 'fallocate -n -l %s %s' % (self.SIZE, self.PATH), -+ 'fallocate -n -l %s %s' % (self.SIZE, self.PATH)]) -+ -+ def test_prealloc_image_without_write_access(self): -+ CONF.set_override('preallocate_images', 'space') -+ -+ fake_processutils.fake_execute_clear_log() -+ fake_processutils.stub_out_processutils_execute(self.stubs) -+ image = self.image_class(self.INSTANCE, self.NAME) -+ -+ def fake_fetch(target, *args, **kwargs): -+ return -+ -+ self.stubs.Set(image, 'check_image_exists', lambda: True) -+ self.stubs.Set(image, '_can_fallocate', lambda: True) -+ self.stubs.Set(os.path, 'exists', lambda _: True) -+ self.stubs.Set(os, 'access', lambda p, w: False) -+ -+ # Testing fallocate is only called when user has write access. -+ image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE) -+ -+ self.assertEqual(fake_processutils.fake_execute_get_log(), []) -+ - - class LvmTestCase(_ImageTestCase, test.NoDBTestCase): - VG = 'FakeVG' -@@ -431,6 +592,58 @@ def _create_image_resize(self, sparse): - - self.mox.VerifyAll() - -+ def test_cache(self): -+ self.mox.StubOutWithMock(os.path, 'exists') -+ if self.OLD_STYLE_INSTANCE_PATH: -+ os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.TEMPLATE_DIR).AndReturn(False) -+ os.path.exists(self.PATH).AndReturn(False) -+ os.path.exists(self.TEMPLATE_PATH).AndReturn(False) -+ -+ fn = self.mox.CreateMockAnything() -+ fn(target=self.TEMPLATE_PATH) -+ self.mox.StubOutWithMock(imagebackend.fileutils, 'ensure_tree') -+ imagebackend.fileutils.ensure_tree(self.TEMPLATE_DIR) -+ self.mox.ReplayAll() -+ -+ image = self.image_class(self.INSTANCE, self.NAME) -+ self.mock_create_image(image) -+ image.cache(fn, self.TEMPLATE) -+ -+ self.mox.VerifyAll() -+ -+ def test_cache_image_exists(self): -+ self.mox.StubOutWithMock(os.path, 'exists') -+ if self.OLD_STYLE_INSTANCE_PATH: -+ os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.TEMPLATE_DIR).AndReturn(True) -+ os.path.exists(self.PATH).AndReturn(True) -+ os.path.exists(self.TEMPLATE_PATH).AndReturn(True) -+ self.mox.ReplayAll() -+ -+ image = self.image_class(self.INSTANCE, self.NAME) -+ image.cache(None, self.TEMPLATE) -+ -+ self.mox.VerifyAll() -+ -+ def test_cache_base_dir_exists(self): -+ self.mox.StubOutWithMock(os.path, 'exists') -+ if self.OLD_STYLE_INSTANCE_PATH: -+ os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False) -+ os.path.exists(self.TEMPLATE_DIR).AndReturn(True) -+ os.path.exists(self.PATH).AndReturn(False) -+ os.path.exists(self.TEMPLATE_PATH).AndReturn(False) -+ fn = self.mox.CreateMockAnything() -+ fn(target=self.TEMPLATE_PATH) -+ self.mox.StubOutWithMock(imagebackend.fileutils, 'ensure_tree') -+ self.mox.ReplayAll() -+ -+ image = self.image_class(self.INSTANCE, self.NAME) -+ self.mock_create_image(image) -+ image.cache(fn, self.TEMPLATE) -+ -+ self.mox.VerifyAll() -+ - def test_create_image(self): - self._create_image(False) - -@@ -596,6 +809,21 @@ def test_cache_template_exists(self): - - self.mox.VerifyAll() - -+ def test_cache_base_dir_exists(self): -+ self.mox.StubOutWithMock(os.path, 'exists') -+ os.path.exists(self.TEMPLATE_DIR).AndReturn(True) -+ os.path.exists(self.TEMPLATE_PATH).AndReturn(False) -+ fn = self.mox.CreateMockAnything() -+ fn(target=self.TEMPLATE_PATH) -+ self.mox.StubOutWithMock(imagebackend.fileutils, 'ensure_tree') -+ self.mox.ReplayAll() -+ -+ image = self.image_class(self.INSTANCE, self.NAME) -+ self.mock_create_image(image) -+ image.cache(fn, self.TEMPLATE) -+ -+ self.mox.VerifyAll() -+ - def test_create_image(self): - fn = self.prepare_mocks() - fn(max_size=None, rbd=self.rbd, target=self.TEMPLATE_PATH) -@@ -642,6 +870,13 @@ class BackendTestCase(test.NoDBTestCase): - 'uuid': uuidutils.generate_uuid()} - NAME = 'fake-name.suffix' - -+ def setUp(self): -+ super(BackendTestCase, self).setUp() -+ -+ def fake_chown(path, owner_uid=None): -+ return None -+ self.stubs.Set(utils, 'chown', fake_chown) -+ - def get_image(self, use_cow, image_type): - return imagebackend.Backend(use_cow).image(self.INSTANCE, - self.NAME, -diff --git a/nova/tests/virt/libvirt/test_libvirt.py b/nova/tests/virt/libvirt/test_libvirt.py -index ba842ad..ea8ac13 100644 ---- a/nova/tests/virt/libvirt/test_libvirt.py -+++ b/nova/tests/virt/libvirt/test_libvirt.py -@@ -390,6 +390,9 @@ def fake_extend(image, size, use_cow=False): - - self.stubs.Set(libvirt_driver.disk, 'extend', fake_extend) - -+ self.stubs.Set(imagebackend.Image, 'resolve_driver_format', -+ imagebackend.Image._get_driver_format) -+ - class FakeConn(): - def getCapabilities(self): - """Ensure standard capabilities being returned.""" -diff --git a/nova/tests/virt/test_virt_drivers.py b/nova/tests/virt/test_virt_drivers.py -index 832d9d6..8f1bd23 100644 ---- a/nova/tests/virt/test_virt_drivers.py -+++ b/nova/tests/virt/test_virt_drivers.py -@@ -30,6 +30,7 @@ - from nova.tests.virt.libvirt import fake_libvirt_utils - from nova.virt import event as virtevent - from nova.virt import fake -+from nova.virt.libvirt import imagebackend - - LOG = logging.getLogger(__name__) - -@@ -201,6 +202,12 @@ def setUp(self): - fake.FakeVirtAPI()) - self.ctxt = test_utils.get_test_admin_context() - self.image_service = fake_image.FakeImageService() -+ # NOTE(dripton): resolve_driver_format does some file reading and -+ # writing and chowning that complicate testing too much by requiring -+ # using real directories with proper permissions. Just stub it out -+ # here; we test it in test_imagebackend.py -+ self.stubs.Set(imagebackend.Image, 'resolve_driver_format', -+ imagebackend.Image._get_driver_format) - - def _get_running_instance(self): - instance_ref = test_utils.get_test_instance() -diff --git a/nova/utils.py b/nova/utils.py -index 599cb64..4757f3a 100755 ---- a/nova/utils.py -+++ b/nova/utils.py -@@ -924,6 +924,20 @@ def temporary_chown(path, owner_uid=None): - execute('chown', orig_uid, path, run_as_root=True) - - -+def chown(path, owner_uid=None): -+ """chown a path. -+ -+ :param owner_uid: UID of owner (defaults to current user) -+ """ -+ if owner_uid is None: -+ owner_uid = os.getuid() -+ -+ orig_uid = os.stat(path).st_uid -+ -+ if orig_uid != owner_uid: -+ execute('chown', owner_uid, path, run_as_root=True) -+ -+ - @contextlib.contextmanager - def tempdir(**kwargs): - argdict = kwargs.copy() -diff --git a/nova/virt/libvirt/imagebackend.py b/nova/virt/libvirt/imagebackend.py -index 51872cf..ed11c90 100644 ---- a/nova/virt/libvirt/imagebackend.py -+++ b/nova/virt/libvirt/imagebackend.py -@@ -88,6 +88,11 @@ def __init__(self, source_type, driver_format, is_block_dev=False): - self.is_block_dev = is_block_dev - self.preallocate = False - -+ # NOTE(dripton): We store lines of json (path, disk_format) in this -+ # file, for some image types, to prevent attacks based on changing the -+ # disk_format. -+ self.disk_info_path = None -+ - # NOTE(mikal): We need a lock directory which is shared along with - # instance files, to cover the scenario where multiple compute nodes - # are trying to create a base file at the same time -@@ -232,6 +237,65 @@ def snapshot_extract(self, target, out_format): - def snapshot_delete(self): - raise NotImplementedError() - -+ def _get_driver_format(self): -+ return self.driver_format -+ -+ def resolve_driver_format(self): -+ """Return the driver format for self.path. -+ -+ First checks self.disk_info_path for an entry. -+ If it's not there, calls self._get_driver_format(), and then -+ stores the result in self.disk_info_path -+ -+ See https://bugs.launchpad.net/nova/+bug/1221190 -+ """ -+ def _dict_from_line(line): -+ if not line: -+ return {} -+ try: -+ return jsonutils.loads(line) -+ except (TypeError, ValueError) as e: -+ msg = (_("Could not load line %(line)s, got error " -+ "%(error)s") % -+ {'line': line, 'error': unicode(e)}) -+ raise exception.InvalidDiskInfo(reason=msg) -+ -+ @utils.synchronized(self.disk_info_path, external=False, -+ lock_path=self.lock_path) -+ def write_to_disk_info_file(): -+ # Use os.open to create it without group or world write permission. -+ fd = os.open(self.disk_info_path, os.O_RDWR | os.O_CREAT, 0o644) -+ with os.fdopen(fd, "r+") as disk_info_file: -+ line = disk_info_file.read().rstrip() -+ dct = _dict_from_line(line) -+ if self.path in dct: -+ msg = _("Attempted overwrite of an existing value.") -+ raise exception.InvalidDiskInfo(reason=msg) -+ dct.update({self.path: driver_format}) -+ disk_info_file.seek(0) -+ disk_info_file.truncate() -+ disk_info_file.write('%s\n' % jsonutils.dumps(dct)) -+ # Ensure the file is always owned by the nova user so qemu can't -+ # write it. -+ utils.chown(self.disk_info_path, owner_uid=os.getuid()) -+ -+ try: -+ if (self.disk_info_path is not None and -+ os.path.exists(self.disk_info_path)): -+ with open(self.disk_info_path) as disk_info_file: -+ line = disk_info_file.read().rstrip() -+ dct = _dict_from_line(line) -+ for path, driver_format in dct.iteritems(): -+ if path == self.path: -+ return driver_format -+ driver_format = self._get_driver_format() -+ if self.disk_info_path is not None: -+ fileutils.ensure_tree(os.path.dirname(self.disk_info_path)) -+ write_to_disk_info_file() -+ except OSError as e: -+ raise exception.DiskInfoReadWriteFail(reason=unicode(e)) -+ return driver_format -+ - - class Raw(Image): - def __init__(self, instance=None, disk_name=None, path=None, -@@ -243,12 +307,17 @@ def __init__(self, instance=None, disk_name=None, path=None, - disk_name)) - self.snapshot_name = snapshot_name - self.preallocate = CONF.preallocate_images != 'none' -+ self.disk_info_path = os.path.join(os.path.dirname(self.path), -+ 'disk.info') - self.correct_format() - -+ def _get_driver_format(self): -+ data = images.qemu_img_info(self.path) -+ return data.file_format or 'raw' -+ - def correct_format(self): - if os.path.exists(self.path): -- data = images.qemu_img_info(self.path) -- self.driver_format = data.file_format or 'raw' -+ self.driver_format = self.resolve_driver_format() - - def create_image(self, prepare_template, base, size, *args, **kwargs): - @utils.synchronized(base, external=True, lock_path=self.lock_path) -@@ -291,6 +360,9 @@ def __init__(self, instance=None, disk_name=None, path=None, - disk_name)) - self.snapshot_name = snapshot_name - self.preallocate = CONF.preallocate_images != 'none' -+ self.disk_info_path = os.path.join(os.path.dirname(self.path), -+ 'disk.info') -+ self.resolve_driver_format() - - def create_image(self, prepare_template, base, size, *args, **kwargs): - @utils.synchronized(base, external=True, lock_path=self.lock_path) --- -1.8.5.5 - diff --git a/sys-cluster/nova/nova-2013.2.2-r1.ebuild b/sys-cluster/nova/nova-2013.2.3.ebuild index 917e62cd12d4..2571904f99ba 100644 --- a/sys-cluster/nova/nova-2013.2.2-r1.ebuild +++ b/sys-cluster/nova/nova-2013.2.3.ebuild @@ -1,6 +1,6 @@ # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -# $Header: /var/cvsroot/gentoo-x86/sys-cluster/nova/nova-2013.2.2-r1.ebuild,v 1.1 2014/03/25 20:51:33 prometheanfire Exp $ +# $Header: /var/cvsroot/gentoo-x86/sys-cluster/nova/nova-2013.2.3.ebuild,v 1.1 2014/04/06 06:32:19 prometheanfire Exp $ EAPI=5 PYTHON_COMPAT=( python2_7 ) @@ -14,7 +14,7 @@ SRC_URI="http://launchpad.net/${PN}/havana/${PV}/+download/${P}.tar.gz" LICENSE="Apache-2.0" SLOT="0" KEYWORDS="~amd64 ~x86" -IUSE="+api +cert +compute +conductor +consoleauth +kvm +network +novncproxy +scheduler +spicehtml5proxy +xvpvncproxy sqlite mysql postgres xen" +IUSE="+compute +kvm +network +novncproxy sqlite mysql postgres xen" REQUIRED_USE="|| ( mysql postgres sqlite ) || ( kvm xen )" @@ -64,6 +64,7 @@ RDEPEND="sqlite? ( >=dev-python/sqlalchemy-0.7.8[sqlite,${PYTHON_USEDEP}] novncproxy? ( www-apps/novnc ) sys-apps/iproute2 net-misc/openvswitch + net-misc/rabbitmq-server sys-fs/sysfsutils sys-fs/multipath-tools kvm? ( app-emulation/qemu ) @@ -71,7 +72,6 @@ RDEPEND="sqlite? ( >=dev-python/sqlalchemy-0.7.8[sqlite,${PYTHON_USEDEP}] app-emulation/xen-tools )" PATCHES=( - "${FILESDIR}/2013.2.2-CVE-2014-0134.patch" ) pkg_setup() { @@ -81,47 +81,36 @@ pkg_setup() { python_install() { distutils-r1_python_install - newconfd "${FILESDIR}/nova-confd" "nova" - newinitd "${FILESDIR}/nova-initd" "nova" - use api && dosym /etc/init.d/nova /etc/init.d/nova-api - use cert && dosym /etc/init.d/nova /etc/init.d/nova-cert - use compute && dosym /etc/init.d/nova /etc/init.d/nova-compute - use conductor && dosym /etc/init.d/nova /etc/init.d/nova-conductor - use consoleauth && dosym /etc/init.d/nova /etc/init.d/nova-consoleauth - use network && dosym /etc/init.d/nova /etc/init.d/nova-network - use novncproxy &&dosym /etc/init.d/nova /etc/init.d/nova-novncproxy - use scheduler && dosym /etc/init.d/nova /etc/init.d/nova-scheduler - use spicehtml5proxy && dosym /etc/init.d/nova /etc/init.d/nova-spicehtml5proxy - use xvpvncproxy && dosym /etc/init.d/nova /etc/init.d/nova-xvpncproxy - diropts -m 0750 - dodir /var/run/nova /var/log/nova /var/lock/nova - fowners nova:nova /var/log/nova /var/lock/nova /var/run/nova + for svc in api cert compute conductor consoleauth network scheduler spicehtml5proxy xvpvncproxy; do + newinitd "${FILESDIR}/nova.initd" "nova-${svc}" + done + use compute && newinitd "${FILESDIR}/nova.initd" "nova-compute" + use novncproxy && newinitd "${FILESDIR}/nova.initd" "nova-novncproxy" - diropts -m 0755 - dodir /var/lib/nova/instances - fowners nova:nova /var/lib/nova/instances + diropts -m 0750 -o nova -g nova + dodir /var/log/nova /var/lib/nova/instances - keepdir /etc/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) 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 "isntalling CA files failed" + 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" } diff --git a/sys-cluster/nova/nova-2013.2.9999.ebuild b/sys-cluster/nova/nova-2013.2.9999.ebuild index 5326994f18e9..71685f993c32 100644 --- a/sys-cluster/nova/nova-2013.2.9999.ebuild +++ b/sys-cluster/nova/nova-2013.2.9999.ebuild @@ -1,6 +1,6 @@ # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -# $Header: /var/cvsroot/gentoo-x86/sys-cluster/nova/nova-2013.2.9999.ebuild,v 1.12 2014/04/01 03:46:51 prometheanfire Exp $ +# $Header: /var/cvsroot/gentoo-x86/sys-cluster/nova/nova-2013.2.9999.ebuild,v 1.13 2014/04/06 06:32:19 prometheanfire Exp $ EAPI=5 PYTHON_COMPAT=( python2_7 ) @@ -108,7 +108,7 @@ python_install() { 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 "isntalling CA files failed" + 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/ |