diff options
author | Matthew Thode <prometheanfire@gentoo.org> | 2013-12-13 21:10:36 +0000 |
---|---|---|
committer | Matthew Thode <prometheanfire@gentoo.org> | 2013-12-13 21:10:36 +0000 |
commit | f82c5005d54e892e971e07ec44923dc3f31cd94c (patch) | |
tree | d70b1710a8f689085ff98a5d958bd2b1a3b7932e /sys-cluster/nova/files | |
parent | version bump (diff) | |
download | gentoo-2-f82c5005d54e892e971e07ec44923dc3f31cd94c.tar.gz gentoo-2-f82c5005d54e892e971e07ec44923dc3f31cd94c.tar.bz2 gentoo-2-f82c5005d54e892e971e07ec44923dc3f31cd94c.zip |
fixes for CVE-2013-6419
(Portage version: 2.2.7/cvs/Linux x86_64, signed Manifest commit with key 0x2471eb3e40ac5ac3)
Diffstat (limited to 'sys-cluster/nova/files')
-rw-r--r-- | sys-cluster/nova/files/CVE-2013-6419_2013.1.4.patch | 129 | ||||
-rw-r--r-- | sys-cluster/nova/files/CVE-2013-6419_2013.2.patch | 186 |
2 files changed, 315 insertions, 0 deletions
diff --git a/sys-cluster/nova/files/CVE-2013-6419_2013.1.4.patch b/sys-cluster/nova/files/CVE-2013-6419_2013.1.4.patch new file mode 100644 index 000000000000..541b794899d0 --- /dev/null +++ b/sys-cluster/nova/files/CVE-2013-6419_2013.1.4.patch @@ -0,0 +1,129 @@ +commit d4155b806f52f2168742ceb37988fc7f405b44cd +Author: Aaron Rosen <arosen@nicira.com> +Date: Mon Oct 7 13:33:31 2013 -0700 + + Prevent spoofing instance_id from neturon 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 occuring 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. + + Fixes 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) + diff --git a/sys-cluster/nova/files/CVE-2013-6419_2013.2.patch b/sys-cluster/nova/files/CVE-2013-6419_2013.2.patch new file mode 100644 index 000000000000..1dcfe1b9b68f --- /dev/null +++ b/sys-cluster/nova/files/CVE-2013-6419_2013.2.patch @@ -0,0 +1,186 @@ +commit 2a95eee992b66cd65e401e31785c080f811476cf +Author: Aaron Rosen <arosen@nicira.com> +Date: Mon Oct 7 13:33:31 2013 -0700 + + Prevent spoofing instance_id from neturon 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 occuring 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. + + Fixes bug: 1235450 + +diff --git a/nova/api/metadata/handler.py b/nova/api/metadata/handler.py +index 27f4d4e..7ac9023 100644 +--- a/nova/api/metadata/handler.py ++++ b/nova/api/metadata/handler.py +@@ -140,29 +140,34 @@ class MetadataRequestHandler(wsgi.Application): + 'Please try your request again.') + raise webob.exc.HTTPInternalServerError(explanation=unicode(msg)) + + if meta_data is None: + LOG.error(_('Failed to get metadata for ip: %s'), remote_address) + + return meta_data + + 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') + + # Ensure that only one header was passed + + 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 + + if msg: + raise webob.exc.HTTPBadRequest(explanation=msg) + + expected_signature = hmac.new( + CONF.neutron_metadata_proxy_shared_secret, + instance_id, + hashlib.sha256).hexdigest() +@@ -188,11 +193,19 @@ class MetadataRequestHandler(wsgi.Application): + LOG.exception(_('Failed to get metadata for instance id: %s'), + instance_id) + msg = _('An unknown error has occurred. ' + 'Please try your request again.') + raise webob.exc.HTTPInternalServerError(explanation=unicode(msg)) + + if meta_data is None: + 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 50f0d07..e75b51f 100644 +--- a/nova/tests/test_metadata.py ++++ b/nova/tests/test_metadata.py +@@ -594,74 +594,104 @@ class MetadataHandlerTestCase(test.TestCase): + CONF.neutron_metadata_proxy_shared_secret, + expected_instance_id, + hashlib.sha256).hexdigest() + + # try a request with service disabled + response = fake_request( + self.stubs, self.mdinst, + 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) + + # now enable the service + self.flags(service_neutron_metadata_proxy=True) + 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': 'test', + 'X-Instance-ID-Signature': signed}) + + self.assertEqual(response.status_int, 200) + self.assertEqual(response.body, + base64.b64decode(self.instance['user_data'])) + + # mismatched signature + 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': '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, + relpath="/2009-04-04/user-data", + 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) + + # unexpected Instance-ID + signed = hmac.new( + CONF.neutron_metadata_proxy_shared_secret, + 'z-z-z-z', + hashlib.sha256).hexdigest() + + 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': 'z-z-z-z', ++ 'X-Tenant-ID': 'test', + 'X-Instance-ID-Signature': signed}) + self.assertEqual(response.status_int, 500) + + + class MetadataPasswordTestCase(test.TestCase): + def setUp(self): + super(MetadataPasswordTestCase, self).setUp() + fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs) + self.instance = copy.copy(INSTANCES[0]) + self.instance['system_metadata'] = get_default_sys_meta() |