[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#805024: jessie-pu: package glance/2014.1.3-12 (CVE-2015-5251)



Package: release.debian.org
Severity: normal
Tags: jessie
User: release.debian.org@packages.debian.org
Usertags: pu

Dear release team,

I've prepared an update for Glance CVE-2015-5251. The debdiff is attached.
The resulting binaries may be found here:
http://sid.gplhost.com/jessie-proposed-updates/glance/

Please authorize me to upload this to jessie-proposed-updates.

Cheers,

Thomas Goirand (zigo)
diff -Nru glance-2014.1.3/debian/changelog glance-2014.1.3/debian/changelog
--- glance-2014.1.3/debian/changelog	2015-01-29 15:22:59.000000000 +0000
+++ glance-2014.1.3/debian/changelog	2015-11-13 13:30:43.000000000 +0000
@@ -1,3 +1,10 @@
+glance (2014.1.3-12+deb8u1) jessie-proposed-updates; urgency=medium
+
+  * CVE-2015-5251: Glance image status manipulation. Applied upstream patch
+    after rebasing it from Juno to Icehouse (Closes: #799931).
+
+ -- Thomas Goirand <zigo@debian.org>  Fri, 13 Nov 2015 14:22:12 +0100
+
 glance (2014.1.3-12) unstable; urgency=high
 
   * CVE-2014-9623: Glance user storage quota bypass. Applied upstream patch:
diff -Nru glance-2014.1.3/debian/patches/CVE-2015-5251_Prevent_image_status_being_directly_modified_via_v1.patch glance-2014.1.3/debian/patches/CVE-2015-5251_Prevent_image_status_being_directly_modified_via_v1.patch
--- glance-2014.1.3/debian/patches/CVE-2015-5251_Prevent_image_status_being_directly_modified_via_v1.patch	1970-01-01 00:00:00.000000000 +0000
+++ glance-2014.1.3/debian/patches/CVE-2015-5251_Prevent_image_status_being_directly_modified_via_v1.patch	2015-11-13 13:30:43.000000000 +0000
@@ -0,0 +1,171 @@
+Description: Prevent image status being directly modified via v1
+ Users shouldn't be able to change an image's status directly via the v1 API.
+ .
+ Some existing consumers of Glance set the x-image-meta-status header in
+ requests to the Glance API, eg:
+ .
+  https://github.com/openstack/nova/blob/master/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance#L184
+ .
+ We should try to prevent users setting 'status' via v1, but without breaking
+ existing benign API calls such as these.
+ .
+ I've adopted the following approach (which has some prior art in 'protected properties').
+ .
+ If a PUT request is received which contains an x-image-meta-status header:
+ .
+  * The user provided status is ignored if it matches the current image
+    status (this prevents benign calls such as the nova one above from
+    breaking). The usual code (eg 200) will be returned.
+ .
+  * If the user provided status doesn't match the current image status (ie
+    there is a real attempt to change the value) 403 will be returned. This
+    will break any calls which currently intentionally change the status.
+Author: Stuart McLaren <stuart.mclaren@hp.com>
+Date: Tue, 11 Aug 2015 10:37:09 +0000 (+0000)
+X-Git-Url: https://review.openstack.org/gitweb?p=openstack%2Fglance.git;a=commitdiff_plain;h=45be8e1c620c50f3cbca76f561945200a8843bc8
+Bug-Ubuntu: https://bugs.launchpad.net/glance/+bug/1482371
+Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=799931
+Change-Id: I44fadf32abb57c962b67467091c3f51c1ccc25e6
+Origin: upstream, https://review.openstack.org/#/c/226338/
+Last-Update: 2015-10-13
+
+--- glance-2014.1.3.orig/glance/api/v1/__init__.py
++++ glance-2014.1.3/glance/api/v1/__init__.py
+@@ -21,3 +21,6 @@ SUPPORTED_PARAMS = ('limit', 'marker', '
+ 
+ # Metadata which only an admin can change once the image is active
+ ACTIVE_IMMUTABLE = ('size', 'checksum')
++
++# Metadata which cannot be changed (irrespective of the current image state)
++IMMUTABLE = ('status',)
+--- glance-2014.1.3.orig/glance/api/v1/images.py
++++ glance-2014.1.3/glance/api/v1/images.py
+@@ -53,6 +53,7 @@ LOG = logging.getLogger(__name__)
+ SUPPORTED_PARAMS = glance.api.v1.SUPPORTED_PARAMS
+ SUPPORTED_FILTERS = glance.api.v1.SUPPORTED_FILTERS
+ ACTIVE_IMMUTABLE = glance.api.v1.ACTIVE_IMMUTABLE
++IMMUTABLE = glance.api.v1.IMMUTABLE
+ 
+ CONF = cfg.CONF
+ CONF.import_opt('disk_formats', 'glance.common.config', group='image_format')
+@@ -843,6 +844,14 @@ class Controller(controller.BaseControll
+                                         request=req,
+                                         content_type="text/plain")
+ 
++        for key in IMMUTABLE:
++            if (image_meta.get(key) is not None and
++                    image_meta.get(key) != orig_image_meta.get(key)):
++                msg = _("Forbidden to modify '%s' of image.") % key
++                raise HTTPForbidden(explanation=msg,
++                                    request=req,
++                                    content_type="text/plain")
++
+         # The default behaviour for a PUT /images/<IMAGE_ID> is to
+         # override any properties that were previously set. This, however,
+         # leads to a number of issues for the common use case where a caller
+--- glance-2014.1.3.orig/glance/tests/functional/v1/test_api.py
++++ glance-2014.1.3/glance/tests/functional/v1/test_api.py
+@@ -550,3 +550,92 @@ class TestApi(functional.FunctionalTest)
+         self.assertEqual(len(images), 0)
+ 
+         self.stop_servers()
++
++    def test_status_cannot_be_manipulated_directly(self):
++        self.cleanup()
++        self.start_servers(**self.__dict__.copy())
++        headers = minimal_headers('Image1')
++
++        # Create a 'queued' image
++        http = httplib2.Http()
++        headers = {'Content-Type': 'application/octet-stream',
++                   'X-Image-Meta-Disk-Format': 'raw',
++                   'X-Image-Meta-Container-Format': 'bare'}
++        path = "http://%s:%d/v1/images"; % ("127.0.0.1", self.api_port)
++        response, content = http.request(path, 'POST', headers=headers,
++                                         body=None)
++        self.assertEqual(201, response.status)
++        image = jsonutils.loads(content)['image']
++        self.assertEqual('queued', image['status'])
++
++        # Ensure status of 'queued' image can't be changed
++        path = "http://%s:%d/v1/images/%s"; % ("127.0.0.1", self.api_port,
++                                              image['id'])
++        http = httplib2.Http()
++        headers = {'X-Image-Meta-Status': 'active'}
++        response, content = http.request(path, 'PUT', headers=headers)
++        self.assertEqual(403, response.status)
++        response, content = http.request(path, 'HEAD')
++        self.assertEqual(200, response.status)
++        self.assertEqual('queued', response['x-image-meta-status'])
++
++        # We allow 'setting' to the same status
++        http = httplib2.Http()
++        headers = {'X-Image-Meta-Status': 'queued'}
++        response, content = http.request(path, 'PUT', headers=headers)
++        self.assertEqual(200, response.status)
++        response, content = http.request(path, 'HEAD')
++        self.assertEqual(200, response.status)
++        self.assertEqual('queued', response['x-image-meta-status'])
++
++        # Make image active
++        http = httplib2.Http()
++        headers = {'Content-Type': 'application/octet-stream'}
++        response, content = http.request(path, 'PUT', headers=headers,
++                                         body='data')
++        self.assertEqual(200, response.status)
++        image = jsonutils.loads(content)['image']
++        self.assertEqual('active', image['status'])
++
++        # Ensure status of 'active' image can't be changed
++        http = httplib2.Http()
++        headers = {'X-Image-Meta-Status': 'queued'}
++        response, content = http.request(path, 'PUT', headers=headers)
++        self.assertEqual(403, response.status)
++        response, content = http.request(path, 'HEAD')
++        self.assertEqual(200, response.status)
++        self.assertEqual('active', response['x-image-meta-status'])
++
++        # We allow 'setting' to the same status
++        http = httplib2.Http()
++        headers = {'X-Image-Meta-Status': 'active'}
++        response, content = http.request(path, 'PUT', headers=headers)
++        self.assertEqual(200, response.status)
++        response, content = http.request(path, 'HEAD')
++        self.assertEqual(200, response.status)
++        self.assertEqual('active', response['x-image-meta-status'])
++
++        # Create a 'queued' image, ensure 'status' header is ignored
++        http = httplib2.Http()
++        path = "http://%s:%d/v1/images"; % ("127.0.0.1", self.api_port)
++        headers = {'Content-Type': 'application/octet-stream',
++                   'X-Image-Meta-Status': 'active'}
++        response, content = http.request(path, 'POST', headers=headers,
++                                         body=None)
++        self.assertEqual(201, response.status)
++        image = jsonutils.loads(content)['image']
++        self.assertEqual('queued', image['status'])
++
++        # Create an 'active' image, ensure 'status' header is ignored
++        http = httplib2.Http()
++        path = "http://%s:%d/v1/images"; % ("127.0.0.1", self.api_port)
++        headers = {'Content-Type': 'application/octet-stream',
++                   'X-Image-Meta-Disk-Format': 'raw',
++                   'X-Image-Meta-Status': 'queued',
++                   'X-Image-Meta-Container-Format': 'bare'}
++        response, content = http.request(path, 'POST', headers=headers,
++                                         body='data')
++        self.assertEqual(201, response.status)
++        image = jsonutils.loads(content)['image']
++        self.assertEqual('active', image['status'])
++        self.stop_servers()
+--- glance-2014.1.3.orig/glance/tests/integration/legacy_functional/test_v1_api.py
++++ glance-2014.1.3/glance/tests/integration/legacy_functional/test_v1_api.py
+@@ -357,6 +357,8 @@ class TestApi(base.ApiTest):
+         path = "/v1/images"
+         response, content = self.http.request(path, 'POST', headers=headers)
+         self.assertEqual(response.status, 201)
++        image = jsonutils.loads(content)['image']
++        self.assertEqual('active', image['status'])
+ 
+         # 2. HEAD image-location
+         # Verify image size is zero and the status is active
diff -Nru glance-2014.1.3/debian/patches/series glance-2014.1.3/debian/patches/series
--- glance-2014.1.3/debian/patches/series	2015-01-29 15:22:59.000000000 +0000
+++ glance-2014.1.3/debian/patches/series	2015-11-13 13:30:43.000000000 +0000
@@ -4,3 +4,4 @@
 restrict_client_download_and_delete_files_in_glance-api.patch
 CVE-2015-1195_Prevent_file_swift_config_and_filesystem_schemes.patch
 CVE-2014-9623_Cleanup_chunks_for_deleted_image_that_was_saving_icehouse.patch
+CVE-2015-5251_Prevent_image_status_being_directly_modified_via_v1.patch

Reply to: