Do not allow incorrect sized layers

This is a partial revert of I70a7bb5f73d1dddc540e96529784bb8c9bb0b9e3

The off-by-one error turned out to come from our range response
(I1fb1abf3c76ea8db7820caa90c97ddbf92997842).  There are no clients we
know of that send an incorrect size in the manifest; we should error
if we see that.

Revert the adding of layer sizes done with
Id5b1c5726fbe046b2f9f2994bf34f5fd7ecd90de and replace it with a hard
error.  I have tested both docker and podman pushes against this
change and both correctly set a size for each layer in the manifest
per [1].

Although I can not replicate it, the missing sizes might have already
been fixed upstream, or related to the aforementioned off-by-one
response we were giving.

[1] https://docs.docker.com/registry/spec/manifest-v2-2/#manifest-list-field-descriptions

Change-Id: Ibe061171bfd8ab6043b491bbab933bf277f8e12b
This commit is contained in:
Ian Wienand 2021-09-13 17:38:17 +10:00
parent ce2fb31a72
commit b88539964d
2 changed files with 7 additions and 27 deletions

View File

@ -21,8 +21,3 @@ registry:
storage: storage:
driver: filesystem driver: filesystem
root: /tmp/storage root: /tmp/storage
# Check the size of layers matches the size specified in the
# container manifest. Some versions of docker can push invalid
# manifests (and *also* don't care about a size mismatch when
# pulling); set this to false to ignore layer-size mismatches.
strict: true

View File

@ -323,34 +323,19 @@ class RegistryAPI:
data['config']['size'] = size data['config']['size'] = size
changed = True changed = True
# Validate layer sizes
for layer in data['layers']: for layer in data['layers']:
digest = layer['digest'] digest = layer['digest']
actual_size = self.storage.blob_size(namespace, digest) actual_size = self.storage.blob_size(namespace, digest)
# As above, we may or may not have a size for layers. If
# this layer doesn't have a size, add it.
if 'size' not in layer: if 'size' not in layer:
layer['size'] = actual_size msg = ('Client push error: layer %s missing size ' % digest)
changed = True raise cherrypy.HTTPError(400, msg)
continue
# However, if we got a size, we validate it
size = layer['size'] size = layer['size']
if size == actual_size: if size == actual_size:
continue continue
msg = ("Manifest has invalid size for layer %s " msg = ("Manifest has invalid size for layer %s "
"(size:%d actual:%d)" % (digest, size, actual_size)) "(size:%d actual:%d)" % (digest, size, actual_size))
self.log.error(msg) self.log.error(msg)
# Docker pushes a manifest with sizes one byte larger
# than it actaully sends. We choose to ignore this.
# https://github.com/docker/for-linux/issues/1296
if ('docker/' in request.headers.get('User-Agent', '')
and (actual_size + 1 == size)):
self.log.info("Fix docker layer size for %s" % digest)
layer['size'] = actual_size
changed = True
elif self.conf.get('strict', True):
# We don't delete layers here as they may be used by # We don't delete layers here as they may be used by
# different images with valid manifests. Return an error to # different images with valid manifests. Return an error to
# the client so it can try again. # the client so it can try again.