diff options
author | Matthew Thode <prometheanfire@gentoo.org> | 2014-03-25 20:51:33 +0000 |
---|---|---|
committer | Matthew Thode <prometheanfire@gentoo.org> | 2014-03-25 20:51:33 +0000 |
commit | 58d139f5b8417f17e70c8cd1a998142722824ad3 (patch) | |
tree | d0960aa8c42b8c069610433a108ed0db3302ef12 /sys-cluster | |
parent | Fix inverted logic in popen binary patch #504504 by Jeroen Roovers. (diff) | |
download | gentoo-2-58d139f5b8417f17e70c8cd1a998142722824ad3.tar.gz gentoo-2-58d139f5b8417f17e70c8cd1a998142722824ad3.tar.bz2 gentoo-2-58d139f5b8417f17e70c8cd1a998142722824ad3.zip |
fix for nova CVE-2014-0134
(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 | 576 | ||||
-rw-r--r-- | sys-cluster/nova/nova-2013.2.2-r1.ebuild (renamed from sys-cluster/nova/nova-2013.2.2.ebuild) | 3 |
3 files changed, 586 insertions, 2 deletions
diff --git a/sys-cluster/nova/ChangeLog b/sys-cluster/nova/ChangeLog index bafdcf893e45..c9fe51c0e0dd 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.52 2014/03/23 20:32:06 prometheanfire Exp $ +# $Header: /var/cvsroot/gentoo-x86/sys-cluster/nova/ChangeLog,v 1.53 2014/03/25 20:51:33 prometheanfire Exp $ + +*nova-2013.2.2-r1 (25 Mar 2014) + + 25 Mar 2014; Matthew Thode <prometheanfire@gentoo.org> + +files/2013.2.2-CVE-2014-0134.patch, +nova-2013.2.2-r1.ebuild, + -nova-2013.2.2.ebuild: + fix for nova CVE-2014-0134 *nova-2013.1.5 (23 Mar 2014) 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 new file mode 100644 index 000000000000..4aab09443087 --- /dev/null +++ b/sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch @@ -0,0 +1,576 @@ +From e2527e64f77ca0211c744908031cf056cb144f07 Mon Sep 17 00:00:00 2001 +From: David Ripton <dripton@redhat.com> +Date: Mon, 17 Mar 2014 22:18:05 -0400 +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. Since glance takes the appropriate security precautions on +image upload, this should be sufficient and backward-compatible. + +Manually resolved one conflict in nova/virt/libvirt/imagebackend.py: +snapshot_delete was removed in icehouse, but is still there in havana + +Change-Id: I2016efdb3f49a44ec4d677ac596eacc97871f30a +Closes-bug: #1221190 +--- + nova/tests/virt/libvirt/test_imagebackend.py | 331 ++++++++++++++++++++++----- + nova/virt/libvirt/imagebackend.py | 57 ++++- + 2 files changed, 324 insertions(+), 64 deletions(-) + +diff --git a/nova/tests/virt/libvirt/test_imagebackend.py b/nova/tests/virt/libvirt/test_imagebackend.py +index 2455ec8..3df22fa 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 +@@ -31,7 +33,6 @@ CONF = cfg.CONF + + + class _ImageTestCase(object): +- INSTANCES_PATH = '/instances_path' + + def mock_create_image(self, image): + def create_image(fn, base, size, *args, **kwargs): +@@ -40,10 +41,13 @@ class _ImageTestCase(object): + + 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' + +@@ -61,6 +65,70 @@ class _ImageTestCase(object): + 'nova.virt.libvirt.imagebackend.libvirt_utils', + fake_libvirt_utils)) + ++ 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 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: +@@ -128,66 +196,6 @@ class _ImageTestCase(object): + + 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) +@@ -222,16 +230,17 @@ class RawTestCase(_ImageTestCase, test.NoDBTestCase): + 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') + + 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) +@@ -239,6 +248,11 @@ class RawTestCase(_ImageTestCase, test.NoDBTestCase): + + 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 +@@ -259,6 +273,77 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase): + 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) ++ 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) ++ 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) ++ 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) +@@ -277,6 +362,8 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase): + 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) +@@ -296,6 +383,8 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase): + 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) +@@ -314,6 +403,8 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase): + '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) + +@@ -340,6 +431,9 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase): + '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) + +@@ -353,6 +447,55 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase): + + 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(), ++ ['chown root:root %s' % self.DISK_INFO_PATH, ++ '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(), ++ ['chown root:root %s' % self.DISK_INFO_PATH]) ++ + + class LvmTestCase(_ImageTestCase, test.NoDBTestCase): + VG = 'FakeVG' +@@ -429,6 +572,56 @@ class LvmTestCase(_ImageTestCase, test.NoDBTestCase): + + 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) ++ ++ 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) ++ 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) + +@@ -594,6 +787,20 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase): + + self.mox.VerifyAll() + ++ def test_cache_base_dir_exists(self): ++ self.mox.StubOutWithMock(os.path, 'exists') ++ os.path.exists(self.TEMPLATE_DIR).AndReturn(True) ++ 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) +diff --git a/nova/virt/libvirt/imagebackend.py b/nova/virt/libvirt/imagebackend.py +index e900789..21c7641 100644 +--- a/nova/virt/libvirt/imagebackend.py ++++ b/nova/virt/libvirt/imagebackend.py +@@ -88,6 +88,11 @@ class Image(object): + 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,46 @@ class Image(object): + 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 ++ """ ++ @utils.synchronized(self.disk_info_path, external=False, ++ lock_path=self.lock_path) ++ def write_to_disk_info_file(): ++ with open(self.disk_info_path, "w") as disk_info_file: ++ disk_info_file.write('%s\n' % ++ jsonutils.dumps((self.path, driver_format))) ++ # Ensure the file is always owned by root so qemu can't write it. ++ utils.execute('chown', 'root:root', self.disk_info_path, ++ run_as_root=True) ++ ++ 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() ++ try: ++ parts = jsonutils.loads(line) ++ except (TypeError, ValueError): ++ parts = [] ++ if len(parts) == 2: ++ (path, driver_format) = parts ++ 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() ++ return driver_format ++ + + class Raw(Image): + def __init__(self, instance=None, disk_name=None, path=None, +@@ -243,12 +288,17 @@ class Raw(Image): + 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 +341,9 @@ class Qcow2(Image): + 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.3 + + + diff --git a/sys-cluster/nova/nova-2013.2.2.ebuild b/sys-cluster/nova/nova-2013.2.2-r1.ebuild index 25d94ea03322..917e62cd12d4 100644 --- a/sys-cluster/nova/nova-2013.2.2.ebuild +++ b/sys-cluster/nova/nova-2013.2.2-r1.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.ebuild,v 1.1 2014/02/20 21:15:02 prometheanfire Exp $ +# $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 $ EAPI=5 PYTHON_COMPAT=( python2_7 ) @@ -71,6 +71,7 @@ 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() { |