components/openstack/nova/patches/06-CVE-2013-6419.patch
changeset 1944 56ac2df1785b
parent 1943 1a27f000029f
child 1945 3dc1935a2189
equal deleted inserted replaced
1943:1a27f000029f 1944:56ac2df1785b
     1 Upstream patch fixed in Grizzly 2013.1.5, Havana 2013.2.1, Icehouse
       
     2 
       
     3 commit 07006be9165d1008ca0382b6f0ad25b13a676a55
       
     4 Author: Aaron Rosen <[email protected]>
       
     5 Date:   Mon Oct 7 13:33:31 2013 -0700
       
     6 
       
     7     Prevent spoofing instance_id from neutron to nova
       
     8     
       
     9     Previously, one could update a port's device_id in neutron to be
       
    10     that of another tenant's instance_id and then be able to retrieve
       
    11     that instance's metadata. This patch prevents this from occurring by
       
    12     checking that X-Tenant-ID received from the metadata request matches
       
    13     the tenant_id in the nova database.
       
    14     
       
    15     DocImpact - This patch is dependent on another patch in neutron
       
    16                 which adds X-Tenant-ID to the request. Therefore to
       
    17                 minimize downtime one should upgrade Neutron first (then
       
    18                 restart neutron-metadata-agent) and lastly update nova.
       
    19     
       
    20     Change-Id: I93bf662797c3986324ca2099b403833c2e990fb4
       
    21     Closes-Bug: #1235450
       
    22 
       
    23 diff --git a/nova/api/metadata/handler.py b/nova/api/metadata/handler.py
       
    24 index bbaeba5..2b7f659 100644
       
    25 --- a/nova/api/metadata/handler.py
       
    26 +++ b/nova/api/metadata/handler.py
       
    27 @@ -144,6 +144,7 @@ class MetadataRequestHandler(wsgi.Application):
       
    28  
       
    29      def _handle_instance_id_request(self, req):
       
    30          instance_id = req.headers.get('X-Instance-ID')
       
    31 +        tenant_id = req.headers.get('X-Tenant-ID')
       
    32          signature = req.headers.get('X-Instance-ID-Signature')
       
    33          remote_address = req.headers.get('X-Forwarded-For')
       
    34  
       
    35 @@ -151,8 +152,12 @@ class MetadataRequestHandler(wsgi.Application):
       
    36  
       
    37          if instance_id is None:
       
    38              msg = _('X-Instance-ID header is missing from request.')
       
    39 +        elif tenant_id is None:
       
    40 +            msg = _('X-Tenant-ID header is missing from request.')
       
    41          elif not isinstance(instance_id, basestring):
       
    42              msg = _('Multiple X-Instance-ID headers found within request.')
       
    43 +        elif not isinstance(tenant_id, basestring):
       
    44 +            msg = _('Multiple X-Tenant-ID headers found within request.')
       
    45          else:
       
    46              msg = None
       
    47  
       
    48 @@ -188,4 +193,12 @@ class MetadataRequestHandler(wsgi.Application):
       
    49              LOG.error(_('Failed to get metadata for instance id: %s'),
       
    50                        instance_id)
       
    51  
       
    52 +        if meta_data.instance['project_id'] != tenant_id:
       
    53 +            LOG.warning(_("Tenant_id %(tenant_id)s does not match tenant_id "
       
    54 +                          "of instance %(instance_id)s."),
       
    55 +                        {'tenant_id': tenant_id,
       
    56 +                         'instance_id': instance_id})
       
    57 +            # causes a 404 to be raised
       
    58 +            meta_data = None
       
    59 +
       
    60          return meta_data
       
    61 diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py
       
    62 index 01f274f..51b6f72 100644
       
    63 --- a/nova/tests/test_metadata.py
       
    64 +++ b/nova/tests/test_metadata.py
       
    65 @@ -510,6 +510,7 @@ class MetadataHandlerTestCase(test.TestCase):
       
    66              relpath="/2009-04-04/user-data",
       
    67              address="192.192.192.2",
       
    68              headers={'X-Instance-ID': 'a-b-c-d',
       
    69 +                     'X-Tenant-ID': 'test',
       
    70                       'X-Instance-ID-Signature': signed})
       
    71          self.assertEqual(response.status_int, 200)
       
    72  
       
    73 @@ -522,6 +523,7 @@ class MetadataHandlerTestCase(test.TestCase):
       
    74              fake_get_metadata_by_instance_id=fake_get_metadata,
       
    75              headers={'X-Forwarded-For': '192.192.192.2',
       
    76                       'X-Instance-ID': 'a-b-c-d',
       
    77 +                     'X-Tenant-ID': 'test',
       
    78                       'X-Instance-ID-Signature': signed})
       
    79  
       
    80          self.assertEqual(response.status_int, 200)
       
    81 @@ -536,10 +538,36 @@ class MetadataHandlerTestCase(test.TestCase):
       
    82              fake_get_metadata_by_instance_id=fake_get_metadata,
       
    83              headers={'X-Forwarded-For': '192.192.192.2',
       
    84                       'X-Instance-ID': 'a-b-c-d',
       
    85 +                     'X-Tenant-ID': 'test',
       
    86                       'X-Instance-ID-Signature': ''})
       
    87  
       
    88          self.assertEqual(response.status_int, 403)
       
    89  
       
    90 +        # missing X-Tenant-ID from request
       
    91 +        response = fake_request(
       
    92 +            self.stubs, self.mdinst,
       
    93 +            relpath="/2009-04-04/user-data",
       
    94 +            address="192.192.192.2",
       
    95 +            fake_get_metadata_by_instance_id=fake_get_metadata,
       
    96 +            headers={'X-Forwarded-For': '192.192.192.2',
       
    97 +                     'X-Instance-ID': 'a-b-c-d',
       
    98 +                     'X-Instance-ID-Signature': signed})
       
    99 +
       
   100 +        self.assertEqual(response.status_int, 400)
       
   101 +
       
   102 +        # mismatched X-Tenant-ID
       
   103 +        response = fake_request(
       
   104 +            self.stubs, self.mdinst,
       
   105 +            relpath="/2009-04-04/user-data",
       
   106 +            address="192.192.192.2",
       
   107 +            fake_get_metadata_by_instance_id=fake_get_metadata,
       
   108 +            headers={'X-Forwarded-For': '192.192.192.2',
       
   109 +                     'X-Instance-ID': 'a-b-c-d',
       
   110 +                     'X-Tenant-ID': 'FAKE',
       
   111 +                     'X-Instance-ID-Signature': signed})
       
   112 +
       
   113 +        self.assertEqual(response.status_int, 404)
       
   114 +
       
   115          # without X-Forwarded-For
       
   116          response = fake_request(
       
   117              self.stubs, self.mdinst,
       
   118 @@ -547,6 +575,7 @@ class MetadataHandlerTestCase(test.TestCase):
       
   119              address="192.192.192.2",
       
   120              fake_get_metadata_by_instance_id=fake_get_metadata,
       
   121              headers={'X-Instance-ID': 'a-b-c-d',
       
   122 +                     'X-Tenant-ID': 'test',
       
   123                       'X-Instance-ID-Signature': signed})
       
   124  
       
   125          self.assertEqual(response.status_int, 500)
       
   126 @@ -564,6 +593,7 @@ class MetadataHandlerTestCase(test.TestCase):
       
   127              fake_get_metadata_by_instance_id=fake_get_metadata,
       
   128              headers={'X-Forwarded-For': '192.192.192.2',
       
   129                       'X-Instance-ID': 'z-z-z-z',
       
   130 +                     'X-Tenant-ID': 'test',
       
   131                       'X-Instance-ID-Signature': signed})
       
   132          self.assertEqual(response.status_int, 500)
       
   133