summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Thode <prometheanfire@gentoo.org>2014-03-25 20:51:33 +0000
committerMatthew Thode <prometheanfire@gentoo.org>2014-03-25 20:51:33 +0000
commit58d139f5b8417f17e70c8cd1a998142722824ad3 (patch)
treed0960aa8c42b8c069610433a108ed0db3302ef12 /sys-cluster
parentFix inverted logic in popen binary patch #504504 by Jeroen Roovers. (diff)
downloadgentoo-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/ChangeLog9
-rw-r--r--sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch576
-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() {