components/openstack/nova/patches/06-CVE-2013-6419.patch
branchs11-update
changeset 3028 5e73a3a3f66a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/nova/patches/06-CVE-2013-6419.patch	Mon Mar 31 16:44:02 2014 -0700
@@ -0,0 +1,133 @@
+Upstream patch fixed in Grizzly 2013.1.5, Havana 2013.2.1, Icehouse
+
+commit 07006be9165d1008ca0382b6f0ad25b13a676a55
+Author: Aaron Rosen <[email protected]>
+Date:   Mon Oct 7 13:33:31 2013 -0700
+
+    Prevent spoofing instance_id from neutron to nova
+    
+    Previously, one could update a port's device_id in neutron to be
+    that of another tenant's instance_id and then be able to retrieve
+    that instance's metadata. This patch prevents this from occurring by
+    checking that X-Tenant-ID received from the metadata request matches
+    the tenant_id in the nova database.
+    
+    DocImpact - This patch is dependent on another patch in neutron
+                which adds X-Tenant-ID to the request. Therefore to
+                minimize downtime one should upgrade Neutron first (then
+                restart neutron-metadata-agent) and lastly update nova.
+    
+    Change-Id: I93bf662797c3986324ca2099b403833c2e990fb4
+    Closes-Bug: #1235450
+
+diff --git a/nova/api/metadata/handler.py b/nova/api/metadata/handler.py
+index bbaeba5..2b7f659 100644
+--- a/nova/api/metadata/handler.py
++++ b/nova/api/metadata/handler.py
+@@ -144,6 +144,7 @@ class MetadataRequestHandler(wsgi.Application):
+ 
+     def _handle_instance_id_request(self, req):
+         instance_id = req.headers.get('X-Instance-ID')
++        tenant_id = req.headers.get('X-Tenant-ID')
+         signature = req.headers.get('X-Instance-ID-Signature')
+         remote_address = req.headers.get('X-Forwarded-For')
+ 
+@@ -151,8 +152,12 @@ class MetadataRequestHandler(wsgi.Application):
+ 
+         if instance_id is None:
+             msg = _('X-Instance-ID header is missing from request.')
++        elif tenant_id is None:
++            msg = _('X-Tenant-ID header is missing from request.')
+         elif not isinstance(instance_id, basestring):
+             msg = _('Multiple X-Instance-ID headers found within request.')
++        elif not isinstance(tenant_id, basestring):
++            msg = _('Multiple X-Tenant-ID headers found within request.')
+         else:
+             msg = None
+ 
+@@ -188,4 +193,12 @@ class MetadataRequestHandler(wsgi.Application):
+             LOG.error(_('Failed to get metadata for instance id: %s'),
+                       instance_id)
+ 
++        if meta_data.instance['project_id'] != tenant_id:
++            LOG.warning(_("Tenant_id %(tenant_id)s does not match tenant_id "
++                          "of instance %(instance_id)s."),
++                        {'tenant_id': tenant_id,
++                         'instance_id': instance_id})
++            # causes a 404 to be raised
++            meta_data = None
++
+         return meta_data
+diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py
+index 01f274f..51b6f72 100644
+--- a/nova/tests/test_metadata.py
++++ b/nova/tests/test_metadata.py
+@@ -510,6 +510,7 @@ class MetadataHandlerTestCase(test.TestCase):
+             relpath="/2009-04-04/user-data",
+             address="192.192.192.2",
+             headers={'X-Instance-ID': 'a-b-c-d',
++                     'X-Tenant-ID': 'test',
+                      'X-Instance-ID-Signature': signed})
+         self.assertEqual(response.status_int, 200)
+ 
+@@ -522,6 +523,7 @@ class MetadataHandlerTestCase(test.TestCase):
+             fake_get_metadata_by_instance_id=fake_get_metadata,
+             headers={'X-Forwarded-For': '192.192.192.2',
+                      'X-Instance-ID': 'a-b-c-d',
++                     'X-Tenant-ID': 'test',
+                      'X-Instance-ID-Signature': signed})
+ 
+         self.assertEqual(response.status_int, 200)
+@@ -536,10 +538,36 @@ class MetadataHandlerTestCase(test.TestCase):
+             fake_get_metadata_by_instance_id=fake_get_metadata,
+             headers={'X-Forwarded-For': '192.192.192.2',
+                      'X-Instance-ID': 'a-b-c-d',
++                     'X-Tenant-ID': 'test',
+                      'X-Instance-ID-Signature': ''})
+ 
+         self.assertEqual(response.status_int, 403)
+ 
++        # missing X-Tenant-ID from request
++        response = fake_request(
++            self.stubs, self.mdinst,
++            relpath="/2009-04-04/user-data",
++            address="192.192.192.2",
++            fake_get_metadata_by_instance_id=fake_get_metadata,
++            headers={'X-Forwarded-For': '192.192.192.2',
++                     'X-Instance-ID': 'a-b-c-d',
++                     'X-Instance-ID-Signature': signed})
++
++        self.assertEqual(response.status_int, 400)
++
++        # mismatched X-Tenant-ID
++        response = fake_request(
++            self.stubs, self.mdinst,
++            relpath="/2009-04-04/user-data",
++            address="192.192.192.2",
++            fake_get_metadata_by_instance_id=fake_get_metadata,
++            headers={'X-Forwarded-For': '192.192.192.2',
++                     'X-Instance-ID': 'a-b-c-d',
++                     'X-Tenant-ID': 'FAKE',
++                     'X-Instance-ID-Signature': signed})
++
++        self.assertEqual(response.status_int, 404)
++
+         # without X-Forwarded-For
+         response = fake_request(
+             self.stubs, self.mdinst,
+@@ -547,6 +575,7 @@ class MetadataHandlerTestCase(test.TestCase):
+             address="192.192.192.2",
+             fake_get_metadata_by_instance_id=fake_get_metadata,
+             headers={'X-Instance-ID': 'a-b-c-d',
++                     'X-Tenant-ID': 'test',
+                      'X-Instance-ID-Signature': signed})
+ 
+         self.assertEqual(response.status_int, 500)
+@@ -564,6 +593,7 @@ class MetadataHandlerTestCase(test.TestCase):
+             fake_get_metadata_by_instance_id=fake_get_metadata,
+             headers={'X-Forwarded-For': '192.192.192.2',
+                      'X-Instance-ID': 'z-z-z-z',
++                     'X-Tenant-ID': 'test',
+                      'X-Instance-ID-Signature': signed})
+         self.assertEqual(response.status_int, 500)
+