Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

oci: cas*: add blob verification #282

Merged
merged 4 commits into from
Dec 28, 2018

Conversation

cyphar
Copy link
Member

@cyphar cyphar commented Dec 27, 2018

Previously we didn't really check that blobs matched their hashes
directly -- most of the checks we did were based on layer DiffIDs and
similar checks.

Here we add a new casext.GetVerifiedBlob() API which wraps the
underlying reader with a VerifiedReadCloser that will verify that the
digest matches on EOF (or on Close). Users should be very careful to
ensure that they actually check all errors (such as when using
ioutil.Discard or when they do Close).

In addition, we add it to the underlying oci/cas/dir implementation
(just for safety). This adds effectively no overhead since
VerifiedReadCloser will not double-up on verification if the digest is
the same. We also add a basic verification of this as an integration and
some unit tests -- so that we can have some confidence it actually works
to protect against bad blobs.

This is an improvement to the hardened VerifiedReadCloser, such that it
now also acts as a verified LimitedReader. First of all, it actually
means we now check the length of blobs according to their descriptors.
It also allows us to avoid reading further than strictly necessary, if
we already know that the read will fail. Unfortunately, the standard
cas/dir cannot really handle this new verification properly.

Fixes #278
Signed-off-by: Aleksa Sarai asarai@suse.de

@cyphar cyphar added this to the 0.5.0 milestone Dec 27, 2018
@cyphar
Copy link
Member Author

cyphar commented Dec 27, 2018

/cc @tych0 -- You should probably be aware of this change (since it improves overall security).

@cyphar cyphar force-pushed the blob-verified-reader branch 5 times, most recently from b9712bd to 77faf93 Compare December 28, 2018 11:30
Signed-off-by: Aleksa Sarai <asarai@suse.de>
Previously we didn't really check that blobs matched their hashes
directly -- most of the checks we did were based on layer DiffIDs and
similar checks.

Here we add a new casext.GetVerifiedBlob() API which wraps the
underlying reader with a VerifiedReadCloser that will verify that the
digest matches on EOF (or on Close). Users should be very careful to
ensure that they actually check all errors (such as when using
ioutil.Discard or when they do Close).

In addition, we add it to the underlying oci/cas/dir implementation
(just for safety). This adds effectively no overhead since
VerifiedReadCloser will not double-up on verification if the digest is
the same. We also add a basic verification of this as an integration and
some unit tests -- so that we can have some confidence it actually works
to protect against bad blobs.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
This is an improvement to the hardened VerifiedReadCloser, such that it
now also acts as a verified LimitedReader. First of all, it actually
means we now check the length of blobs according to their descriptors.
It also allows us to avoid reading further than strictly necessary, if
we already know that the read will fail. Unfortunately, the standard
cas/dir cannot really handle this new verification properly.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
Signed-off-by: Aleksa Sarai <asarai@suse.de>
@cyphar
Copy link
Member Author

cyphar commented Dec 28, 2018

LGTM.

@cyphar cyphar merged commit 306cd09 into opencontainers:master Dec 28, 2018
cyphar added a commit that referenced this pull request Dec 28, 2018
  CHANGELOG: update
  pkg: hardening: expand to verify descriptor length
  oci: cas*: add blob verification
  ci: add gosec to docker image

LGTMs: @cyphar
Closes #282
@cyphar cyphar deleted the blob-verified-reader branch December 28, 2018 13:51
@tych0
Copy link
Member

tych0 commented Dec 28, 2018 via email

@cyphar
Copy link
Member Author

cyphar commented Dec 28, 2018

A few things:

  1. It checks the digests of everything (not just layer archives -- JSON blobs are included). DiffIDs are only for layer archives.

  2. In the case of archives, it protects against having a different compressed archive that has the same uncompressed form (DiffIDs are the hash of the uncompressed payload -- meaning you have to uncompresss it in order to check it and also opens you up to archive bombs but that's only partially protected against here). This is somewhat more of a sanity thing, but not a bad thing to have.

  3. It protects against endless-read (and thus DoS) attacks from blobs which are much longer than advertised. This is a bit of a half-point since they could in theory change the length of whatever descriptor you used too, but the point is that you won't read more bytes than the descriptor says. It also potentially protects against future collision attacks by requiring pre-images to have the same length.

@tych0
Copy link
Member

tych0 commented Dec 28, 2018 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants