From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id A8721138819 for ; Fri, 13 Dec 2013 21:10:40 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 29034E0B1C; Fri, 13 Dec 2013 21:10:39 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 73905E0B1C for ; Fri, 13 Dec 2013 21:10:38 +0000 (UTC) Received: from flycatcher.gentoo.org (flycatcher.gentoo.org [81.93.255.6]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 723E933F4A9 for ; Fri, 13 Dec 2013 21:10:37 +0000 (UTC) Received: by flycatcher.gentoo.org (Postfix, from userid 2310) id 385EE2004E; Fri, 13 Dec 2013 21:10:36 +0000 (UTC) From: "Matt Thode (prometheanfire)" To: gentoo-commits@lists.gentoo.org Reply-To: gentoo-dev@lists.gentoo.org, prometheanfire@gentoo.org Subject: [gentoo-commits] gentoo-x86 commit in sys-cluster/nova/files: CVE-2013-6419_2013.2.patch CVE-2013-6419_2013.1.4.patch X-VCS-Repository: gentoo-x86 X-VCS-Files: CVE-2013-6419_2013.2.patch CVE-2013-6419_2013.1.4.patch X-VCS-Directories: sys-cluster/nova/files X-VCS-Committer: prometheanfire X-VCS-Committer-Name: Matt Thode Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Message-Id: <20131213211036.385EE2004E@flycatcher.gentoo.org> Date: Fri, 13 Dec 2013 21:10:36 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 04104de7-b2ba-40cc-a5bb-94bd7d55b046 X-Archives-Hash: f8da54f414a302c7e60705fec37b41f1 prometheanfire 13/12/13 21:10:36 Added: CVE-2013-6419_2013.2.patch CVE-2013-6419_2013.1.4.patch Log: fixes for CVE-2013-6419 (Portage version: 2.2.7/cvs/Linux x86_64, signed Manifest commit with key 0x2471eb3e40ac5ac3) Revision Changes Path 1.1 sys-cluster/nova/files/CVE-2013-6419_2013.2.patch file : http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-cluster/nova/files/CVE-2013-6419_2013.2.patch?rev=1.1&view=markup plain: http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-cluster/nova/files/CVE-2013-6419_2013.2.patch?rev=1.1&content-type=text/plain Index: CVE-2013-6419_2013.2.patch =================================================================== commit 2a95eee992b66cd65e401e31785c080f811476cf Author: Aaron Rosen 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() 1.1 sys-cluster/nova/files/CVE-2013-6419_2013.1.4.patch file : http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-cluster/nova/files/CVE-2013-6419_2013.1.4.patch?rev=1.1&view=markup plain: http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-cluster/nova/files/CVE-2013-6419_2013.1.4.patch?rev=1.1&content-type=text/plain Index: CVE-2013-6419_2013.1.4.patch =================================================================== commit d4155b806f52f2168742ceb37988fc7f405b44cd Author: Aaron Rosen 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)