diff -r 097063f324c0 -r 4b1def16fe9b components/openstack/nova/patches/04-CVE-2014-0134-partial.patch --- a/components/openstack/nova/patches/04-CVE-2014-0134-partial.patch Thu Apr 16 01:36:32 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,182 +0,0 @@ -This proposed upstream patch is a follow-up to the original fix for -CVE-2014-0134 (Launchpad bug 1221190) but is tracked under the same CVE -and Launchpad bug as the original fix. It is designated as such below -('Partial-bug: #1221190'). - -From 63064a709162ba1a8a9a19643bd3acdf57c0c0b4 Mon Sep 17 00:00:00 2001 -From: Nikola Dipanov -Date: Wed, 9 Apr 2014 15:50:20 +0200 -Subject: [PATCH] Avoid the possibility of truncating disk info file - -Commit dc8de42 makes nova persist image format to a file to avoid -attacks based on changing it later. However the way it was implemented -leaves a small window of opportunity for the file to be truncated before -it gets written back to effectively making it possible for data to get -lost leaving us with a potential problem next time it is attempted to be -read. - -This patch changes the way file is updated to be atomic, thus closing -the race window (and also removes the chown that we did not really -need). - -It is worth noting that a better solution to this would be -to allow the code calling the imagebackend to write the file (once!) -and make it impossible to update after the boot process is done. This -approach would require more refactoring of the libvirt driver code, and -may be done in the future. - -Partial-bug: #1221190 -Change-Id: Ia1b073f38e096989f34d1774a12a1b4151773fc7 -(cherry picked from commit d416f4310bb946b4b127201ec3c37e530d988714) ---- - etc/nova/rootwrap.d/compute.filters | 1 - - nova/tests/virt/libvirt/test_imagebackend.py | 21 --------------------- - nova/utils.py | 14 -------------- - nova/virt/libvirt/imagebackend.py | 25 +++++++++++++------------ - 4 files changed, 13 insertions(+), 48 deletions(-) - -diff --git a/etc/nova/rootwrap.d/compute.filters b/etc/nova/rootwrap.d/compute.filters -index e98c3f2..ac67180 100644 ---- a/etc/nova/rootwrap.d/compute.filters -+++ b/etc/nova/rootwrap.d/compute.filters -@@ -41,7 +41,6 @@ mkdir: CommandFilter, mkdir, root - # nova/virt/libvirt/connection.py: 'chown', os.getuid( console_log - # nova/virt/libvirt/connection.py: 'chown', os.getuid( console_log - # nova/virt/libvirt/connection.py: 'chown', 'root', basepath('disk') --# nova/utils.py: 'chown', owner_uid, path - chown: CommandFilter, chown, root - - # nova/virt/disk/vfs/localfs.py: 'chmod' -diff --git a/nova/tests/virt/libvirt/test_imagebackend.py b/nova/tests/virt/libvirt/test_imagebackend.py -index 5424f7b..80ade57 100644 ---- a/nova/tests/virt/libvirt/test_imagebackend.py -+++ b/nova/tests/virt/libvirt/test_imagebackend.py -@@ -29,7 +29,6 @@ from nova.openstack.common import uuidutils - 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 -@@ -68,10 +67,6 @@ class _ImageTestCase(object): - '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) -@@ -128,10 +123,6 @@ class RawTestCase(_ImageTestCase, test.NoDBTestCase): - 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, -@@ -246,10 +237,6 @@ class RawTestCase(_ImageTestCase, test.NoDBTestCase): - 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() -@@ -278,10 +265,6 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase): - 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, -@@ -873,10 +856,6 @@ class BackendTestCase(test.NoDBTestCase): - 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/utils.py b/nova/utils.py -index 4757f3a..599cb64 100755 ---- a/nova/utils.py -+++ b/nova/utils.py -@@ -924,20 +924,6 @@ 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 ed11c90..29131d9 100644 ---- a/nova/virt/libvirt/imagebackend.py -+++ b/nova/virt/libvirt/imagebackend.py -@@ -264,20 +264,21 @@ class Image(object): - 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: -+ fd = os.open(self.disk_info_path, os.O_RDONLY | 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()) -+ -+ if self.path in dct: -+ msg = _("Attempted overwrite of an existing value.") -+ raise exception.InvalidDiskInfo(reason=msg) -+ dct.update({self.path: driver_format}) -+ -+ tmp_path = self.disk_info_path + ".tmp" -+ fd = os.open(tmp_path, os.O_WRONLY | os.O_CREAT, 0o644) -+ with os.fdopen(fd, "w") as tmp_file: -+ tmp_file.write('%s\n' % jsonutils.dumps(dct)) -+ os.rename(tmp_path, self.disk_info_path) - - try: - if (self.disk_info_path is not None and --- -1.7.9.2 -