High severityNVD Advisory· Published Feb 24, 2015· Updated May 6, 2026
CVE-2015-1881
CVE-2015-1881
Description
OpenStack Image Registry and Delivery Service (Glance) 2014.2 through 2014.2.2 does not properly remove images, which allows remote authenticated users to cause a denial of service (disk consumption) by creating a large number of images using the task v2 API and then deleting them, a different vulnerability than CVE-2014-9684.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
glancePyPI | < 11.0.0a0 | 11.0.0a0 |
Affected products
3cpe:2.3:a:openstack:image_registry_and_delivery_service_\(glance\):2014.2:*:*:*:*:*:*:*+ 2 more
- cpe:2.3:a:openstack:image_registry_and_delivery_service_\(glance\):2014.2:*:*:*:*:*:*:*
- cpe:2.3:a:openstack:image_registry_and_delivery_service_\(glance\):2014.2.1:*:*:*:*:*:*:*
- cpe:2.3:a:openstack:image_registry_and_delivery_service_\(glance\):2014.2.2:*:*:*:*:*:*:*
Patches
225a722e614eaImage data remains in backend for deleted image
2 files changed · +17 −16
glance/common/scripts/image_import/main.py+15 −15 modified@@ -84,29 +84,29 @@ def import_image(image_repo, image_factory, task_input, task_id, uri): # NOTE: set image status to saving just before setting data original_image.status = 'saving' image_repo.save(original_image) - set_image_data(original_image, uri, None) - - # NOTE: Check if the Image is not deleted after setting the data - # before setting it's status to active. We need to set the status - # explicitly here using the Image object returned from image_repo .The - # Image object returned from create_image method does not have appropriate - # factories wrapped around it. image_id = original_image.image_id + + # NOTE: Retrieving image from the database because the Image object + # returned from create_image method does not have appropriate factories + # wrapped around it. new_image = image_repo.get(image_id) - if new_image.status in ['saving']: - new_image.status = 'active' - new_image.size = original_image.size - new_image.virtual_size = original_image.virtual_size - new_image.checksum = original_image.checksum + set_image_data(new_image, uri, None) + + # NOTE: Check if the Image is not deleted after setting the data + # before saving the active image. Here if image status is + # saving, then new_image is saved as it contains updated location, + # size, virtual_size and checksum information and the status of + # new_image is already set to active in set_image_data() call. + image = image_repo.get(image_id) + if image.status == 'saving': + image_repo.save(new_image) + return image_id else: msg = _LE("The Image %(image_id)s object being created by this task " "%(task_id)s, is no longer in valid status for further " "processing." % {"image_id": new_image.image_id, "task_id": task_id}) raise exception.Conflict(msg) - image_repo.save(new_image) - - return image_id def create_image(image_repo, image_factory, image_properties, task_id):
glance/tests/unit/common/scripts/image_import/test_main.py+2 −1 modified@@ -56,7 +56,8 @@ def test_import_image(self): image_id, image_import_script.import_image(image_repo, image_factory, task_input, None, uri)) - self.assertEqual('active', image.status) + # Check image is in saving state before image_repo.save called + self.assertEqual('saving', image.status) self.assertTrue(image_repo.save.called) mock_set_img_data.assert_called_once_with(image, uri, None) self.assertTrue(image_repo.get.called)
78b5b0a9575cImage data remains in backend for deleted image
2 files changed · +23 −22
glance/common/scripts/image_import/main.py+21 −21 modified@@ -86,37 +86,37 @@ def import_image(image_repo, image_factory, task_input, task_id, uri): # NOTE: set image status to saving just before setting data original_image.status = 'saving' image_repo.save(original_image) - set_image_data(original_image, uri, None) - - # NOTE: Check if the Image is not deleted after setting the data - # before setting it's status to active. We need to set the status - # explicitly here using the Image object returned from image_repo .The - # Image object returned from create_image method does not have appropriate - # factories wrapped around it. image_id = original_image.image_id + + # NOTE: Retrieving image from the database because the Image object + # returned from create_image method does not have appropriate factories + # wrapped around it. + new_image = image_repo.get(image_id) + set_image_data(new_image, uri, None) + try: - new_image = image_repo.get(image_id) - if new_image.status == 'saving': - new_image.status = 'active' - new_image.size = original_image.size - new_image.virtual_size = original_image.virtual_size - new_image.checksum = original_image.checksum + # NOTE: Check if the Image is not deleted after setting the data + # before saving the active image. Here if image status is + # saving, then new_image is saved as it contains updated location, + # size, virtual_size and checksum information and the status of + # new_image is already set to active in set_image_data() call. + image = image_repo.get(image_id) + if image.status == 'saving': + image_repo.save(new_image) + return image_id else: msg = _("The Image %(image_id)s object being created by this task " "%(task_id)s, is no longer in valid status for further " - "processing.") % {"image_id": new_image.image_id, + "processing.") % {"image_id": image_id, "task_id": task_id} raise exception.Conflict(msg) - image_repo.save(new_image) - - return image_id except (exception.Conflict, exception.NotFound): with excutils.save_and_reraise_exception(): - if original_image.locations: - for location in original_image.locations: + if new_image.locations: + for location in new_image.locations: store_utils.delete_image_location_from_backend( - original_image.context, - original_image.image_id, + new_image.context, + image_id, location)
glance/tests/unit/common/scripts/image_import/test_main.py+2 −1 modified@@ -56,7 +56,8 @@ def test_import_image(self): image_id, image_import_script.import_image(image_repo, image_factory, task_input, None, uri)) - self.assertEqual('active', image.status) + # Check image is in saving state before image_repo.save called + self.assertEqual('saving', image.status) self.assertTrue(image_repo.save.called) mock_set_img_data.assert_called_once_with(image, uri, None) self.assertTrue(image_repo.get.called)
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
9- bugs.launchpad.net/glance/+bug/1420696nvdExploitWEB
- lists.openstack.org/pipermail/openstack-announce/2015-February/000336.htmlnvdVendor AdvisoryWEB
- github.com/advisories/GHSA-4jp4-3c62-r8jvghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2015-1881ghsaADVISORY
- rhn.redhat.com/errata/RHSA-2015-0938.htmlnvdWEB
- github.com/openstack/glance/commit/25a722e614eacc47e4658f0bca6343fa52f7d03fghsaWEB
- github.com/openstack/glance/commit/78b5b0a9575cd5e9c4543ec0e8fd6072af1f0ebbghsaWEB
- github.com/pypa/advisory-database/tree/main/vulns/glance/PYSEC-2015-38.yamlghsaWEB
- www.securityfocus.com/bid/72694nvd
News mentions
0No linked articles in our index yet.