Skip to content

Commit

Permalink
WIP: Expect UncompressedDigest to be set for partial pulls, enforce D…
Browse files Browse the repository at this point in the history
…iffID match

Signed-off-by: Miloslav Trmač <[email protected]>
  • Loading branch information
mtrmac committed Nov 25, 2024
1 parent e54fba6 commit f6be37a
Showing 1 changed file with 27 additions and 13 deletions.
40 changes: 27 additions & 13 deletions storage/storage_dest.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,23 +370,22 @@ func (s *storageImageDestination) PutBlobPartial(ctx context.Context, chunkAcces
if out.UncompressedDigest != "" {
s.lockProtected.indexToDiffID[options.LayerIndex] = out.UncompressedDigest
if out.TOCDigest != "" {
s.lockProtected.indexToTOCDigest[options.LayerIndex] = out.TOCDigest
options.Cache.RecordTOCUncompressedPair(out.TOCDigest, out.UncompressedDigest)
}
// Don’t set indexToTOCDigest on this path:
// - Using UncompressedDigest allows image reuse with non-partially-pulled layers, so we want to set indexToDiffID.
// - If UncompressedDigest has been computed, that means the layer was read completely, and the TOC has been created from scratch.
// That TOC is quite unlikely to match any other TOC value.

// The computation of UncompressedDigest means the whole layer has been consumed; while doing that, chunked.GetDiffer is
// If the whole layer has been consumed, chunked.GetDiffer is
// responsible for ensuring blobDigest has been validated.
if out.CompressedDigest != blobDigest {
return private.UploadedBlob{}, fmt.Errorf("internal error: PrepareStagedLayer returned CompressedDigest %q not matching expected %q",
out.CompressedDigest, blobDigest)
}
// So, record also information about blobDigest, that might benefit reuse.
// We trust PrepareStagedLayer to validate or create both values correctly.
s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest
options.Cache.RecordDigestUncompressedPair(out.CompressedDigest, out.UncompressedDigest)
if out.CompressedDigest != "" {
if out.CompressedDigest != blobDigest {
return private.UploadedBlob{}, fmt.Errorf("internal error: PrepareStagedLayer returned CompressedDigest %q not matching expected %q",
out.CompressedDigest, blobDigest)
}
// So, record also information about blobDigest, that might benefit reuse.
// We trust PrepareStagedLayer to validate or create both values correctly.
s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest
options.Cache.RecordDigestUncompressedPair(out.CompressedDigest, out.UncompressedDigest)
}
} else {
// Use diffID for layer identity if it is known.
if uncompressedDigest := options.Cache.UncompressedDigestForTOC(out.TOCDigest); uncompressedDigest != "" {
Expand Down Expand Up @@ -936,12 +935,27 @@ func (s *storageImageDestination) createNewLayer(index int, layerDigest digest.D
return nil, nil
}

// FIXME: Should we insist on UncompressedDigest being always set, and hard fail otherwise??
untrustedUncompressedDigest = d
// While the contents of the digest are untrusted, make sure at least the _format_ is valid,
// because we are going to write it to durable storage in expectedLayerDiffIDFlag .
if err := untrustedUncompressedDigest.Validate(); err != nil {
return nil, err
}
} else {
// FIXME: Clean up. Maybe the generic code can provide us the config earlier?
// FIXME: Always enforce this for all layers??!
d, err := s.untrustedLayerDiffID(index)
if err != nil {
return nil, err
}
if d == "" {
logrus.Debugf("Skipping commit for layer %q, manifest not yet available", newLayerID)
return nil, nil
}
if diffOutput.UncompressedDigest != d {
return nil, fmt.Errorf("uncompressed digest inconsistency for layer %d: config %q vs. computed %q", index, d, diffOutput.UncompressedDigest)
}
}

flags := make(map[string]interface{})
Expand Down

0 comments on commit f6be37a

Please sign in to comment.