* CVE-2015-1195: Prevent file, swift+config and filesystem schemes (applied
upstream patch). (Closes: #775926).
Thomas Goirand
9 years ago
0 | glance (2014.2.1-4) experimental; urgency=medium | |
1 | ||
2 | * CVE-2015-1195: Prevent file, swift+config and filesystem schemes (applied | |
3 | upstream patch). (Closes: #775926). | |
4 | ||
5 | -- Thomas Goirand <zigo@debian.org> Wed, 21 Jan 2015 17:31:46 +0100 | |
6 | ||
0 | 7 | glance (2014.2.1-3) experimental; urgency=medium |
1 | 8 | |
2 | 9 | * Only runs pkgos_dbc_postinst if glance/configure_db is true. |
+110
-0
0 | Description: CVE-2015-1195: Prevent file, swift+config and filesystem schemes | |
1 | This change ensures that 'file', 'filesystem', and 'swift+config' URI schemes | |
2 | are not allowed when setting the location field. A previous fix to | |
3 | CVE-2014-9493 attempted to address this issue but did not include | |
4 | 'filesystem', a URI scheme allowed by the glance_store. | |
5 | . | |
6 | Without this fix in place it is possible for a client to access any file the | |
7 | glance-api server has read permissions for. | |
8 | Author: Grant Murphy <grant.murphy@hp.com> | |
9 | Date: Thu, 8 Jan 2015 00:09:38 +0000 (-0800) | |
10 | X-Git-Url: https://review.openstack.org/gitweb?p=openstack%2Fglance.git;a=commitdiff_plain;h=5191ed1879c5fd5b2694f922bcedec232f461088 | |
11 | Change-Id: I02cd099a8634b9c7e3cf8f172bcbd33f8edcbc83 | |
12 | Bug-Ubuntu: https://launchpad.net/bugs/1408663 | |
13 | Bug-Debian: https://bugs.debian.org/775926 | |
14 | Last-Update: 2014-01-21 | |
15 | ||
16 | diff --git a/glance/common/store_utils.py b/glance/common/store_utils.py | |
17 | index b7537ce..64cfa87 100644 | |
18 | --- a/glance/common/store_utils.py | |
19 | +++ b/glance/common/store_utils.py | |
20 | @@ -38,6 +38,8 @@ store_utils_opts = [ | |
21 | CONF = cfg.CONF | |
22 | CONF.register_opts(store_utils_opts) | |
23 | ||
24 | +RESTRICTED_URI_SCHEMAS = frozenset(['file', 'filesystem', 'swift+config']) | |
25 | + | |
26 | ||
27 | def safe_delete_from_backend(context, image_id, location): | |
28 | """ | |
29 | @@ -136,8 +138,7 @@ def validate_external_location(uri): | |
30 | """ | |
31 | ||
32 | # TODO(zhiyan): This function could be moved to glance_store. | |
33 | - | |
34 | - pieces = urlparse.urlparse(uri) | |
35 | - valid_schemes = [scheme for scheme in store_api.get_known_schemes() | |
36 | - if scheme != 'file' and scheme != 'swift+config'] | |
37 | - return pieces.scheme in valid_schemes | |
38 | + # TODO(gm): Use a whitelist of allowed schemes | |
39 | + scheme = urlparse.urlparse(uri).scheme | |
40 | + return (scheme in store_api.get_known_schemes() and | |
41 | + scheme not in RESTRICTED_URI_SCHEMAS) | |
42 | diff --git a/glance/tests/unit/test_store_location.py b/glance/tests/unit/test_store_location.py | |
43 | index c9ee44c..efaecd8 100644 | |
44 | --- a/glance/tests/unit/test_store_location.py | |
45 | +++ b/glance/tests/unit/test_store_location.py | |
46 | @@ -69,12 +69,15 @@ class TestStoreLocation(base.StoreClearingUnitTest): | |
47 | ||
48 | loc1 = {'url': 'file:///fake1.img.tar.gz', 'metadata': {}} | |
49 | loc2 = {'url': 'swift+config:///xxx', 'metadata': {}} | |
50 | + loc3 = {'url': 'filesystem:///foo.img.tar.gz', 'metadata': {}} | |
51 | ||
52 | # Test for insert location | |
53 | image1 = TestStoreLocation.FakeImageProxy() | |
54 | locations = glance.location.StoreLocations(image1, []) | |
55 | self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc1) | |
56 | + self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc3) | |
57 | self.assertNotIn(loc1, locations) | |
58 | + self.assertNotIn(loc3, locations) | |
59 | ||
60 | # Test for set_attr of _locations_proxy | |
61 | image2 = TestStoreLocation.FakeImageProxy() | |
62 | diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py | |
63 | index 4ec136d..39e9a44 100644 | |
64 | --- a/glance/tests/unit/v1/test_api.py | |
65 | +++ b/glance/tests/unit/v1/test_api.py | |
66 | @@ -1071,31 +1071,23 @@ class TestGlanceAPI(base.IsolatedUnitTest): | |
67 | ||
68 | def test_add_copy_from_with_restricted_sources(self): | |
69 | """Tests creates an image from copy-from with restricted sources""" | |
70 | - fixture_headers = {'x-image-meta-store': 'file', | |
71 | + header_template = {'x-image-meta-store': 'file', | |
72 | 'x-image-meta-disk-format': 'vhd', | |
73 | - 'x-glance-api-copy-from': 'file:///etc/passwd', | |
74 | 'x-image-meta-container-format': 'ovf', | |
75 | 'x-image-meta-name': 'fake image #F'} | |
76 | ||
77 | - req = webob.Request.blank("/images") | |
78 | - req.method = 'POST' | |
79 | - for k, v in six.iteritems(fixture_headers): | |
80 | - req.headers[k] = v | |
81 | - res = req.get_response(self.api) | |
82 | - self.assertEqual(400, res.status_int) | |
83 | + schemas = ["file:///etc/passwd", | |
84 | + "swift+config:///xxx", | |
85 | + "filesystem:///etc/passwd"] | |
86 | ||
87 | - fixture_headers = {'x-image-meta-store': 'file', | |
88 | - 'x-image-meta-disk-format': 'vhd', | |
89 | - 'x-glance-api-copy-from': 'swift+config://xxx', | |
90 | - 'x-image-meta-container-format': 'ovf', | |
91 | - 'x-image-meta-name': 'fake image #F'} | |
92 | - | |
93 | - req = webob.Request.blank("/images") | |
94 | - req.method = 'POST' | |
95 | - for k, v in six.iteritems(fixture_headers): | |
96 | - req.headers[k] = v | |
97 | - res = req.get_response(self.api) | |
98 | - self.assertEqual(400, res.status_int) | |
99 | + for schema in schemas: | |
100 | + req = webob.Request.blank("/images") | |
101 | + req.method = 'POST' | |
102 | + for k, v in six.iteritems(header_template): | |
103 | + req.headers[k] = v | |
104 | + req.headers['x-glance-api-copy-from'] = schema | |
105 | + res = req.get_response(self.api) | |
106 | + self.assertEqual(400, res.status_int) | |
107 | ||
108 | def test_add_copy_from_upload_image_unauthorized_with_body(self): | |
109 | rules = {"upload_image": '!', "modify_image": '@', |