Description: Prohibit file injection writing to host filesystem
 This is a refinement of the previous fix in commit 2427d4a,
 which does the file name canonicalization as the root user.
 This is required so that guest images could not for example,
 protect malicious symlinks in a directory only readable by root.
Author: A1draig Brady <pbrady@redhat.com>
Bug-Debian: http://bugs.debian.org/684256
Origin: https://github.com/openstack/nova/commit/d9577ce9f266166a297488445b5b0c93c1ddb368
Bug: 1031311, CVE-2012-3447
Bug-Ubuntu: https://launchpad.net/bugs/1031311
Last-Update: 2012-08-07

--- nova-2012.1.1.orig/nova/tests/test_virt.py
+++ nova-2012.1.1/nova/tests/test_virt.py
@@ -18,6 +18,7 @@
 from nova import exception
 from nova import flags
 from nova import test
+from nova import utils
 from nova.virt.disk import api as disk_api
 from nova.virt import driver
 
@@ -86,6 +87,17 @@ class TestVirtDriver(test.TestCase):
 
 
 class TestVirtDisk(test.TestCase):
+    def setUp(self):
+        super(TestVirtDisk, self).setUp()
+
+        real_execute = utils.execute
+
+        def nonroot_execute(*cmd_parts, **kwargs):
+            kwargs.pop('run_as_root', None)
+            return real_execute(*cmd_parts, **kwargs)
+
+        self.stubs.Set(utils, 'execute', nonroot_execute)
+
     def test_check_safe_path(self):
         ret = disk_api._join_and_check_path_within_fs('/foo', 'etc',
                                                       'something.conf')
--- nova-2012.1.1.orig/nova/tests/test_xenapi.py
+++ nova-2012.1.1/nova/tests/test_xenapi.py
@@ -597,9 +597,13 @@ class XenAPIVMTestCase(test.TestCase):
             self._tee_executed = True
             return '', ''
 
+        def _readlink_handler(cmd_parts, **kwargs):
+            return os.path.realpath(cmd_parts[2]), ''
+
         fake_utils.fake_execute_set_repliers([
             # Capture the tee .../etc/network/interfaces command
             (r'tee.*interfaces', _tee_handler),
+            (r'readlink -nm.*', _readlink_handler),
         ])
         self._test_spawn(glance_stubs.FakeGlance.IMAGE_MACHINE,
                          glance_stubs.FakeGlance.IMAGE_KERNEL,
--- nova-2012.1.1.orig/nova/rootwrap/compute.py
+++ nova-2012.1.1/nova/rootwrap/compute.py
@@ -182,6 +182,10 @@ filterlist = [
     # nova/virt/libvirt/utils.py: 'qemu-img'
     filters.CommandFilter("/usr/bin/qemu-img", "root"),
 
+    # nova/virt/disk/api.py: 'readlink', '-e'
+    filters.CommandFilter("/usr/bin/readlink", "root"),
+    filters.CommandFilter("/bin/readlink", "root"),
+
     # nova/virt/disk/api.py: 'touch', target
     filters.CommandFilter("/usr/bin/touch", "root"),
 
--- nova-2012.1.1.orig/nova/virt/disk/api.py
+++ nova-2012.1.1/nova/virt/disk/api.py
@@ -314,7 +314,9 @@ def _join_and_check_path_within_fs(fs, *
     mounted guest fs.  Trying to be clever and specifying a
     path with '..' in it will hit this safeguard.
     '''
-    absolute_path = os.path.realpath(os.path.join(fs, *args))
+    absolute_path, _err = utils.execute('readlink', '-nm',
+                                        os.path.join(fs, *args),
+                                        run_as_root=True)
     if not absolute_path.startswith(os.path.realpath(fs) + '/'):
         raise exception.Invalid(_('injected file path not valid'))
     return absolute_path
