[openstack-nova/f16] fix host corruption through file injection vulnerabilty

Pádraig Brady pbrady at fedoraproject.org
Sat Jul 7 00:24:45 UTC 2012


commit 5653d28ab44e09b0d09195a5c923b9fb06f646c4
Author: Pádraig Brady <P at draigBrady.com>
Date:   Sat Jul 7 01:20:31 2012 +0100

    fix host corruption through file injection vulnerabilty
    
    CVE-2012-3361

 ...t-key-net-md-injection-writing-to-host-fs.patch |  138 ++++++++++++++++++++
 openstack-nova.spec                                |    7 +-
 2 files changed, 144 insertions(+), 1 deletions(-)
---
diff --git a/0023-Prevent-key-net-md-injection-writing-to-host-fs.patch b/0023-Prevent-key-net-md-injection-writing-to-host-fs.patch
new file mode 100644
index 0000000..f464a70
--- /dev/null
+++ b/0023-Prevent-key-net-md-injection-writing-to-host-fs.patch
@@ -0,0 +1,138 @@
+From acb534fd6dbecebabdae4ac8770eeedef776fbe6 Mon Sep 17 00:00:00 2001
+From: Thierry Carrez <thierry at openstack.org>
+Date: Tue, 3 Jul 2012 16:34:58 +0200
+Subject: [PATCH] Prevent key/net/md injection writing to host fs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fix bug 1015531, CVE-2012-3361
+
+Checks that the final normalized path that is about to be written
+to is always within the mounted guest filesystem.
+
+This is a Diablo backport of the part of Russell Bryant, Pádraig Brady
+and Mark McLoughlin's Folsom patch that applies to stable/diablo.
+
+Change-Id: I134c40258ff2c9c225bd6092decd9c10e4e22273
+---
+ nova/tests/test_virt.py |   20 +++++++++++++++++++
+ nova/virt/disk/base.py  |   49 ++++++++++++++++++++++++++++++++++++----------
+ 2 files changed, 58 insertions(+), 11 deletions(-)
+
+diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py
+index 388f075..c33d7b3 100644
+--- a/nova/tests/test_virt.py
++++ b/nova/tests/test_virt.py
+@@ -15,8 +15,10 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from nova import exception
+ from nova import flags
+ from nova import test
++from nova.virt import disk
+ from nova.virt import driver
+ 
+ FLAGS = flags.FLAGS
+@@ -81,3 +83,21 @@ class TestVirtDriver(test.TestCase):
+                                                 'swap_size': 0}))
+         self.assertTrue(driver.swap_is_usable({'device_name': '/dev/sdb',
+                                                 'swap_size': 1}))
++
++
++class TestVirtDisk(test.TestCase):
++    def test_check_safe_path(self):
++        ret = disk._join_and_check_path_within_fs('/foo', 'etc',
++                                                      'something.conf')
++        self.assertEquals(ret, '/foo/etc/something.conf')
++
++    def test_check_unsafe_path(self):
++        self.assertRaises(exception.Invalid,
++                          disk._join_and_check_path_within_fs,
++                          '/foo', 'etc/../../../something.conf')
++
++    def test_inject_files_with_bad_path(self):
++        self.assertRaises(exception.Invalid,
++                          disk._inject_file_into_fs,
++                          '/tmp', '/etc/../../../../etc/passwd',
++                         'hax')
+diff --git a/nova/virt/disk/base.py b/nova/virt/disk/base.py
+index 9ae0bd1..f708741 100644
+--- a/nova/virt/disk/base.py
++++ b/nova/virt/disk/base.py
+@@ -250,12 +250,39 @@ def inject_data_into_fs(fs, key, net, metadata, execute):
+         _inject_metadata_into_fs(metadata, fs, execute=execute)
+ 
+ 
++def _join_and_check_path_within_fs(fs, *args):
++    '''os.path.join() with safety check for injected file paths.
++
++    Join the supplied path components and make sure that the
++    resulting path we are injecting into is within the
++    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))
++    if not absolute_path.startswith(os.path.realpath(fs) + '/'):
++        raise exception.Invalid()
++    return absolute_path
++
++
++def _inject_file_into_fs(fs, path, contents, append=False):
++    absolute_path = _join_and_check_path_within_fs(fs, path.lstrip('/'))
++
++    parent_dir = os.path.dirname(absolute_path)
++    utils.execute('mkdir', '-p', parent_dir, run_as_root=True)
++
++    args = []
++    if append:
++        args.append('-a')
++    args.append(absolute_path)
++
++    kwargs = dict(process_input=contents, run_as_root=True)
++
++    utils.execute('tee', *args, **kwargs)
++
++
+ def _inject_metadata_into_fs(metadata, fs, execute=None):
+-    metadata_path = os.path.join(fs, "meta.js")
+     metadata = dict([(m.key, m.value) for m in metadata])
+-
+-    utils.execute('tee', metadata_path,
+-                  process_input=json.dumps(metadata), run_as_root=True)
++    _inject_file_into_fs(fs, 'meta.js', json.dumps(metadata))
+ 
+ 
+ def _inject_key_into_fs(key, fs, execute=None):
+@@ -264,13 +291,12 @@ def _inject_key_into_fs(key, fs, execute=None):
+     key is an ssh key string.
+     fs is the path to the base of the filesystem into which to inject the key.
+     """
+-    sshdir = os.path.join(fs, 'root', '.ssh')
++    sshdir = _join_and_check_path_within_fs(fs, 'root', '.ssh')
+     utils.execute('mkdir', '-p', sshdir, run_as_root=True)
+     utils.execute('chown', 'root', sshdir, run_as_root=True)
+     utils.execute('chmod', '700', sshdir, run_as_root=True)
+-    keyfile = os.path.join(sshdir, 'authorized_keys')
+-    utils.execute('tee', '-a', keyfile,
+-                  process_input='\n' + key.strip() + '\n', run_as_root=True)
++    keyfile = os.path.join('root', '.ssh', 'authorized_keys')
++    _inject_file_into_fs(fs, keyfile, '\n' + key.strip() + '\n', append=True)
+ 
+ 
+ def _inject_net_into_fs(net, fs, execute=None):
+@@ -278,9 +304,10 @@ def _inject_net_into_fs(net, fs, execute=None):
+ 
+     net is the contents of /etc/network/interfaces.
+     """
+-    netdir = os.path.join(os.path.join(fs, 'etc'), 'network')
++    netdir = _join_and_check_path_within_fs(fs, 'etc', 'network')
+     utils.execute('mkdir', '-p', netdir, run_as_root=True)
+     utils.execute('chown', 'root:root', netdir, run_as_root=True)
+     utils.execute('chmod', 755, netdir, run_as_root=True)
+-    netfile = os.path.join(netdir, 'interfaces')
+-    utils.execute('tee', netfile, process_input=net, run_as_root=True)
++
++    netfile = os.path.join('etc', 'network', 'interfaces')
++    _inject_file_into_fs(fs, netfile, net)
diff --git a/openstack-nova.spec b/openstack-nova.spec
index 031869e..05e763a 100644
--- a/openstack-nova.spec
+++ b/openstack-nova.spec
@@ -2,7 +2,7 @@
 
 Name:             openstack-nova
 Version:          2011.3.1
-Release:          10%{?dist}
+Release:          11%{?dist}
 Summary:          OpenStack Compute (nova)
 
 Group:            Applications/System
@@ -51,6 +51,7 @@ Patch0019: 0019-Bug-898257-support-handling-images-with-libguestfs.patch
 Patch0020: 0020-Fix-libguestfs-operation-with-specified-partitions.patch
 Patch0021: 0021-Ensure-we-don-t-access-the-net-when-building-docs.patch
 Patch0022: 0022-Fix-up-protocol-case-handling-for-security-groups.patch
+Patch0023: 0023-Prevent-key-net-md-injection-writing-to-host-fs.patch
 
 BuildArch:        noarch
 BuildRequires:    intltool
@@ -204,6 +205,7 @@ This package contains documentation files for nova.
 %patch0020 -p1
 %patch0021 -p1
 %patch0022 -p1
+%patch0023 -p1
 
 find . \( -name .gitignore -o -name .placeholder \) -delete
 
@@ -390,6 +392,9 @@ fi
 %endif
 
 %changelog
+* Thu Jul  5 2012 Pádraig Brady <P at draigBrady.com> - 2011.3.1-11
+- Prohibit host file corruption through file injection (CVE-2012-3361)
+
 * Wed Jun 13 2012 Pádraig Brady <P at draigBrady.com> - 2011.3.1-10
 - Fix issue with previous CVE-2012-2654 fix
 


More information about the scm-commits mailing list