Skip to content

Commit

Permalink
Verify size in addition to checksum of uploaded image
Browse files Browse the repository at this point in the history
Fixes bug 1092584

Previously only the supplied checksum was verified against the actual
checksum calculated by the backend store, with the image being killed
on mismatch.

Now we also similarly verify the supplied image size, if provided.

Change-Id: I87fa3ff77715111f1095f3ebe64cd699776ec27e
  • Loading branch information
Eoghan Glynn committed Jan 3, 2013
1 parent 35260a7 commit 5e5e722
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 15 deletions.
28 changes: 16 additions & 12 deletions glance/api/v1/images.py
Expand Up @@ -436,19 +436,23 @@ def _upload(self, req, image_meta):
utils.CooperativeReader(image_data),
image_meta['size'])

# Verify any supplied checksum value matches checksum
def _kill_mismatched(image_meta, attr, actual):
supplied = image_meta.get(attr)
if supplied and supplied != actual:
msg = _("Supplied %(attr)s (%(supplied)s) and "
"%(attr)s generated from uploaded image "
"(%(actual)s) did not match. Setting image "
"status to 'killed'.") % locals()
LOG.error(msg)
self._safe_kill(req, image_id)
raise HTTPBadRequest(explanation=msg,
content_type="text/plain",
request=req)

# Verify any supplied size/checksum value matches size/checksum
# returned from store when adding image
supplied_checksum = image_meta.get('checksum')
if supplied_checksum and supplied_checksum != checksum:
msg = _("Supplied checksum (%(supplied_checksum)s) and "
"checksum generated from uploaded image "
"(%(checksum)s) did not match. Setting image "
"status to 'killed'.") % locals()
LOG.error(msg)
self._safe_kill(req, image_id)
raise HTTPBadRequest(explanation=msg,
content_type="text/plain",
request=req)
_kill_mismatched(image_meta, 'size', size)
_kill_mismatched(image_meta, 'checksum', checksum)

# Update the database with the checksum returned
# from the backend store
Expand Down
19 changes: 19 additions & 0 deletions glance/tests/functional/v1/test_api.py
Expand Up @@ -1451,3 +1451,22 @@ def test_ownership(self):
self.assertEqual('tenant2', response['x-image-meta-owner'])

self.stop_servers()

@skip_if_disabled
def test_mismatched_size(self):
"""
Test mismatched size.
"""
self.cleanup()
self.start_servers(**self.__dict__.copy())

image_data = "*" * FIVE_KB
headers = minimal_headers('Image1')
headers['x-image-meta-size'] = str(FIVE_KB + 1)
path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
http = httplib2.Http()
response, content = http.request(path, 'POST', headers=headers,
body=image_data)
self.assertEqual(response.status, 400)

self.stop_servers()
24 changes: 21 additions & 3 deletions glance/tests/unit/v1/test_api.py
Expand Up @@ -2189,12 +2189,11 @@ def test_add_image_zero_size(self):
self.assertEqual(res.status_int, 200)
self.assertEqual(len(res.body), 0)

def test_add_image_checksum_mismatch(self):
def _do_test_add_image_attribute_mismatch(self, attributes):
fixture_headers = {
'x-image-meta-checksum': 'asdf',
'x-image-meta-size': '4',
'x-image-meta-name': 'fake image #3',
}
fixture_headers.update(attributes)

req = webob.Request.blank("/images")
req.method = 'POST'
Expand All @@ -2206,6 +2205,25 @@ def test_add_image_checksum_mismatch(self):
res = req.get_response(self.api)
self.assertEquals(res.status_int, 400)

def test_add_image_checksum_mismatch(self):
attributes = {
'x-image-meta-checksum': 'asdf',
}
self._do_test_add_image_attribute_mismatch(attributes)

def test_add_image_size_mismatch(self):
attributes = {
'x-image-meta-size': str(len("XXXX") + 1),
}
self._do_test_add_image_attribute_mismatch(attributes)

def test_add_image_checksum_and_size_mismatch(self):
attributes = {
'x-image-meta-checksum': 'asdf',
'x-image-meta-size': str(len("XXXX") + 1),
}
self._do_test_add_image_attribute_mismatch(attributes)

def test_add_image_bad_store(self):
"""Tests raises BadRequest for invalid store header"""
fixture_headers = {'x-image-meta-store': 'bad',
Expand Down

0 comments on commit 5e5e722

Please sign in to comment.