[AUTO-CHERRYPICK] Backport CVE-2024-3727 fix for libcontainers-common - branch main (#10450)
Co-authored-by: Sudipta Pandit <sudpandit@microsoft.com> Co-authored-by: Pawel Winogrodzki <pawelwi@microsoft.com> Co-authored-by: jslobodzian <joslobo@microsoft.com>
This commit is contained in:
Родитель
ef135f4b46
Коммит
2f66e799c2
|
@ -0,0 +1,536 @@
|
||||||
|
From f20a95cee488de958f42db02bb5121ba52981a1d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudipta Pandit <sudpandit@microsoft.com>
|
||||||
|
Date: Thu, 12 Sep 2024 17:08:02 +0530
|
||||||
|
Subject: [PATCH] Backport upstream patch for containers/image
|
||||||
|
|
||||||
|
---
|
||||||
|
.../image/v5/directory/directory_dest.go | 23 ++++++++--
|
||||||
|
.../image/v5/directory/directory_src.go | 18 ++++++--
|
||||||
|
.../image/v5/directory/directory_transport.go | 25 ++++++----
|
||||||
|
.../image/v5/docker/docker_client.go | 4 ++
|
||||||
|
.../image/v5/docker/docker_image.go | 7 ++-
|
||||||
|
.../image/v5/docker/docker_image_dest.go | 4 ++
|
||||||
|
.../image/v5/docker/docker_image_src.go | 6 +++
|
||||||
|
.../image/v5/docker/internal/tarfile/dest.go | 12 ++++-
|
||||||
|
.../v5/docker/internal/tarfile/writer.go | 34 +++++++++++---
|
||||||
|
.../containers/image/v5/ostree/ostree_dest.go | 10 ++++
|
||||||
|
.../containers/image/v5/ostree/ostree_src.go | 4 +-
|
||||||
|
.../image/v5/storage/storage_image.go | 46 +++++++++++++++----
|
||||||
|
.../image/v5/storage/storage_reference.go | 10 +++-
|
||||||
|
13 files changed, 165 insertions(+), 38 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/directory/directory_dest.go b/vendor/github.com/containers/image/v5/directory/directory_dest.go
|
||||||
|
index ea20e7c5..72ec5a70 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/directory/directory_dest.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/directory/directory_dest.go
|
||||||
|
@@ -188,7 +188,11 @@ func (d *dirImageDestination) PutBlob(ctx context.Context, stream io.Reader, inp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- blobPath := d.ref.layerPath(blobDigest)
|
||||||
|
+ // Custom backport for CVE-2024-3727
|
||||||
|
+ blobPath, err := d.ref.layerPath(blobDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return types.BlobInfo{}, err
|
||||||
|
+ }
|
||||||
|
// need to explicitly close the file, since a rename won't otherwise not work on Windows
|
||||||
|
blobFile.Close()
|
||||||
|
explicitClosed = true
|
||||||
|
@@ -212,7 +216,10 @@ func (d *dirImageDestination) TryReusingBlob(ctx context.Context, info types.Blo
|
||||||
|
if info.Digest == "" {
|
||||||
|
return false, types.BlobInfo{}, errors.Errorf(`"Can not check for a blob with unknown digest`)
|
||||||
|
}
|
||||||
|
- blobPath := d.ref.layerPath(info.Digest)
|
||||||
|
+ blobPath, err := d.ref.layerPath(info.Digest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return false, types.BlobInfo{}, err
|
||||||
|
+ }
|
||||||
|
finfo, err := os.Stat(blobPath)
|
||||||
|
if err != nil && os.IsNotExist(err) {
|
||||||
|
return false, types.BlobInfo{}, nil
|
||||||
|
@@ -232,7 +239,11 @@ func (d *dirImageDestination) TryReusingBlob(ctx context.Context, info types.Blo
|
||||||
|
// If the destination is in principle available, refuses this manifest type (e.g. it does not recognize the schema),
|
||||||
|
// but may accept a different manifest type, the returned error must be an ManifestTypeRejectedError.
|
||||||
|
func (d *dirImageDestination) PutManifest(ctx context.Context, manifest []byte, instanceDigest *digest.Digest) error {
|
||||||
|
- return ioutil.WriteFile(d.ref.manifestPath(instanceDigest), manifest, 0644)
|
||||||
|
+ manifestPath, err := d.ref.manifestPath(instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
+ return ioutil.WriteFile(manifestPath, manifest, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutSignatures writes a set of signatures to the destination.
|
||||||
|
@@ -240,7 +251,11 @@ func (d *dirImageDestination) PutManifest(ctx context.Context, manifest []byte,
|
||||||
|
// (when the primary manifest is a manifest list); this should always be nil if the primary manifest is not a manifest list.
|
||||||
|
func (d *dirImageDestination) PutSignatures(ctx context.Context, signatures [][]byte, instanceDigest *digest.Digest) error {
|
||||||
|
for i, sig := range signatures {
|
||||||
|
- if err := ioutil.WriteFile(d.ref.signaturePath(i, instanceDigest), sig, 0644); err != nil {
|
||||||
|
+ signaturePath, err := d.ref.signaturePath(i, instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
+ if err := ioutil.WriteFile(signaturePath, sig, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/directory/directory_src.go b/vendor/github.com/containers/image/v5/directory/directory_src.go
|
||||||
|
index ad9129d4..420cee2f 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/directory/directory_src.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/directory/directory_src.go
|
||||||
|
@@ -37,7 +37,11 @@ func (s *dirImageSource) Close() error {
|
||||||
|
// If instanceDigest is not nil, it contains a digest of the specific manifest instance to retrieve (when the primary manifest is a manifest list);
|
||||||
|
// this never happens if the primary manifest is not a manifest list (e.g. if the source never returns manifest lists).
|
||||||
|
func (s *dirImageSource) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
|
||||||
|
- m, err := ioutil.ReadFile(s.ref.manifestPath(instanceDigest))
|
||||||
|
+ path, err := s.ref.manifestPath(instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, "", err
|
||||||
|
+ }
|
||||||
|
+ m, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
@@ -53,7 +57,11 @@ func (s *dirImageSource) HasThreadSafeGetBlob() bool {
|
||||||
|
// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
|
||||||
|
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
|
||||||
|
func (s *dirImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
|
||||||
|
- r, err := os.Open(s.ref.layerPath(info.Digest))
|
||||||
|
+ path, err := s.ref.layerPath(info.Digest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, -1, err
|
||||||
|
+ }
|
||||||
|
+ r, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, -1, err
|
||||||
|
}
|
||||||
|
@@ -71,7 +79,11 @@ func (s *dirImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache
|
||||||
|
func (s *dirImageSource) GetSignatures(ctx context.Context, instanceDigest *digest.Digest) ([][]byte, error) {
|
||||||
|
signatures := [][]byte{}
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
- signature, err := ioutil.ReadFile(s.ref.signaturePath(i, instanceDigest))
|
||||||
|
+ path, err := s.ref.signaturePath(i, instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, err
|
||||||
|
+ }
|
||||||
|
+ signature, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
break
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/directory/directory_transport.go b/vendor/github.com/containers/image/v5/directory/directory_transport.go
|
||||||
|
index e542d888..ea280707 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/directory/directory_transport.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/directory/directory_transport.go
|
||||||
|
@@ -162,25 +162,34 @@ func (ref dirReference) DeleteImage(ctx context.Context, sys *types.SystemContex
|
||||||
|
}
|
||||||
|
|
||||||
|
// manifestPath returns a path for the manifest within a directory using our conventions.
|
||||||
|
-func (ref dirReference) manifestPath(instanceDigest *digest.Digest) string {
|
||||||
|
+func (ref dirReference) manifestPath(instanceDigest *digest.Digest) (string, error) {
|
||||||
|
if instanceDigest != nil {
|
||||||
|
- return filepath.Join(ref.path, instanceDigest.Encoded()+".manifest.json")
|
||||||
|
+ if err := instanceDigest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
+ return filepath.Join(ref.path, instanceDigest.Encoded()+".manifest.json"), nil
|
||||||
|
}
|
||||||
|
- return filepath.Join(ref.path, "manifest.json")
|
||||||
|
+ return filepath.Join(ref.path, "manifest.json"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// layerPath returns a path for a layer tarball within a directory using our conventions.
|
||||||
|
-func (ref dirReference) layerPath(digest digest.Digest) string {
|
||||||
|
+func (ref dirReference) layerPath(digest digest.Digest) (string, error) {
|
||||||
|
+ if err := digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
// FIXME: Should we keep the digest identification?
|
||||||
|
- return filepath.Join(ref.path, digest.Encoded())
|
||||||
|
+ return filepath.Join(ref.path, digest.Encoded()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// signaturePath returns a path for a signature within a directory using our conventions.
|
||||||
|
-func (ref dirReference) signaturePath(index int, instanceDigest *digest.Digest) string {
|
||||||
|
+func (ref dirReference) signaturePath(index int, instanceDigest *digest.Digest) (string, error) {
|
||||||
|
if instanceDigest != nil {
|
||||||
|
- return filepath.Join(ref.path, fmt.Sprintf(instanceDigest.Encoded()+".signature-%d", index+1))
|
||||||
|
+ if err := instanceDigest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
+ return filepath.Join(ref.path, fmt.Sprintf(instanceDigest.Encoded()+".signature-%d", index+1)), nil
|
||||||
|
}
|
||||||
|
- return filepath.Join(ref.path, fmt.Sprintf("signature-%d", index+1))
|
||||||
|
+ return filepath.Join(ref.path, fmt.Sprintf("signature-%d", index+1)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// versionPath returns a path for the version file within a directory using our conventions.
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/docker_client.go b/vendor/github.com/containers/image/v5/docker/docker_client.go
|
||||||
|
index 3fe9a11d..08f5d66e 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/docker_client.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/docker_client.go
|
||||||
|
@@ -796,6 +796,10 @@ func (c *dockerClient) detectProperties(ctx context.Context) error {
|
||||||
|
// getExtensionsSignatures returns signatures from the X-Registry-Supports-Signatures API extension,
|
||||||
|
// using the original data structures.
|
||||||
|
func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerReference, manifestDigest digest.Digest) (*extensionSignatureList, error) {
|
||||||
|
+ // Custom patch for CVE-2024-3727
|
||||||
|
+ if err := manifestDigest.Validate(); err != nil { // Make sure manifestDigest.String() does not contain any unexpected characters
|
||||||
|
+ return nil, err
|
||||||
|
+ }
|
||||||
|
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(ref.ref), manifestDigest)
|
||||||
|
res, err := c.makeRequest(ctx, http.MethodGet, path, nil, nil, v2Auth, nil)
|
||||||
|
if err != nil {
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image.go b/vendor/github.com/containers/image/v5/docker/docker_image.go
|
||||||
|
index c84bb37d..284b39f5 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/docker_image.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/docker_image.go
|
||||||
|
@@ -83,7 +83,12 @@ func GetRepositoryTags(ctx context.Context, sys *types.SystemContext, ref types.
|
||||||
|
if err = json.NewDecoder(res.Body).Decode(&tagsHolder); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
- tags = append(tags, tagsHolder.Tags...)
|
||||||
|
+ for _, tag := range tagsHolder.Tags {
|
||||||
|
+ if _, err := reference.WithTag(dr.ref, tag); err != nil { // Ensure the tag does not contain unexpected values
|
||||||
|
+ return nil, fmt.Errorf("registry returned invalid tag %q: %w", tag, err)
|
||||||
|
+ }
|
||||||
|
+ tags = append(tags, tag)
|
||||||
|
+ }
|
||||||
|
|
||||||
|
link := res.Header.Get("Link")
|
||||||
|
if link == "" {
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image_dest.go b/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
|
||||||
|
index 80701a76..ce08333c 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
|
||||||
|
@@ -215,6 +215,9 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
|
||||||
|
// If the destination does not contain the blob, or it is unknown, blobExists ordinarily returns (false, -1, nil);
|
||||||
|
// it returns a non-nil error only on an unexpected failure.
|
||||||
|
func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.Named, digest digest.Digest, extraScope *authScope) (bool, int64, error) {
|
||||||
|
+ if err := digest.Validate(); err != nil { // Make sure digest.String() does not contain any unexpected characters
|
||||||
|
+ return false, -1, err
|
||||||
|
+ }
|
||||||
|
checkPath := fmt.Sprintf(blobsPath, reference.Path(repo), digest.String())
|
||||||
|
logrus.Debugf("Checking %s", checkPath)
|
||||||
|
res, err := d.c.makeRequest(ctx, http.MethodHead, checkPath, nil, nil, v2Auth, extraScope)
|
||||||
|
@@ -641,6 +644,7 @@ sigExists:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // manifestDigest is known to be valid because it was not rejected by getExtensionsSignatures above.
|
||||||
|
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(d.ref.ref), manifestDigest.String())
|
||||||
|
res, err := d.c.makeRequest(ctx, http.MethodPut, path, nil, bytes.NewReader(body), v2Auth, nil)
|
||||||
|
if err != nil {
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image_src.go b/vendor/github.com/containers/image/v5/docker/docker_image_src.go
|
||||||
|
index 1333cf9e..1c3cf448 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/docker_image_src.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/docker_image_src.go
|
||||||
|
@@ -178,6 +178,9 @@ func simplifyContentType(contentType string) string {
|
||||||
|
// this never happens if the primary manifest is not a manifest list (e.g. if the source never returns manifest lists).
|
||||||
|
func (s *dockerImageSource) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
|
||||||
|
if instanceDigest != nil {
|
||||||
|
+ if err := instanceDigest.Validate(); err != nil { // Make sure instanceDigest.String() does not contain any unexpected characters
|
||||||
|
+ return nil, "", err
|
||||||
|
+ }
|
||||||
|
return s.fetchManifest(ctx, instanceDigest.String())
|
||||||
|
}
|
||||||
|
err := s.ensureManifestIsLoaded(ctx)
|
||||||
|
@@ -364,6 +367,9 @@ func (s *dockerImageSource) GetBlobAt(ctx context.Context, info types.BlobInfo,
|
||||||
|
return nil, nil, fmt.Errorf("external URLs not supported with GetBlobAt")
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if err := info.Digest.Validate(); err != nil { // Make sure info.Digest.String() does not contain any unexpected characters
|
||||||
|
+ return nil, nil, err
|
||||||
|
+ }
|
||||||
|
path := fmt.Sprintf(blobsPath, reference.Path(s.physicalRef.ref), info.Digest.String())
|
||||||
|
logrus.Debugf("Downloading %s", path)
|
||||||
|
res, err := s.c.makeRequest(ctx, http.MethodGet, path, headers, nil, v2Auth, nil)
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
|
||||||
|
index 44b0af11..e9162668 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
|
||||||
|
@@ -141,11 +141,19 @@ func (d *Destination) PutBlob(ctx context.Context, stream io.Reader, inputInfo t
|
||||||
|
return types.BlobInfo{}, errors.Wrap(err, "reading Config file stream")
|
||||||
|
}
|
||||||
|
d.config = buf
|
||||||
|
- if err := d.archive.sendFileLocked(d.archive.configPath(inputInfo.Digest), inputInfo.Size, bytes.NewReader(buf)); err != nil {
|
||||||
|
+ configPath, err := d.archive.configPath(inputInfo.Digest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return types.BlobInfo{}, errors.Wrap(err, "getting config path")
|
||||||
|
+ }
|
||||||
|
+ if err := d.archive.sendFileLocked(configPath, inputInfo.Size, bytes.NewReader(buf)); err != nil {
|
||||||
|
return types.BlobInfo{}, errors.Wrap(err, "writing Config file")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
- if err := d.archive.sendFileLocked(d.archive.physicalLayerPath(inputInfo.Digest), inputInfo.Size, stream); err != nil {
|
||||||
|
+ layerPath, err := d.archive.physicalLayerPath(inputInfo.Digest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return types.BlobInfo{}, err
|
||||||
|
+ }
|
||||||
|
+ if err := d.archive.sendFileLocked(layerPath, inputInfo.Size, stream); err != nil {
|
||||||
|
return types.BlobInfo{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
|
||||||
|
index 255f0d35..742f977c 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
|
||||||
|
@@ -92,7 +92,10 @@ func (w *Writer) ensureSingleLegacyLayerLocked(layerID string, layerDigest diges
|
||||||
|
if _, ok := w.legacyLayers[layerID]; !ok {
|
||||||
|
// Create a symlink for the legacy format, where there is one subdirectory per layer ("image").
|
||||||
|
// See also the comment in physicalLayerPath.
|
||||||
|
- physicalLayerPath := w.physicalLayerPath(layerDigest)
|
||||||
|
+ physicalLayerPath, err := w.physicalLayerPath(layerDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
if err := w.sendSymlinkLocked(filepath.Join(layerID, legacyLayerFileName), filepath.Join("..", physicalLayerPath)); err != nil {
|
||||||
|
return errors.Wrap(err, "creating layer symbolic link")
|
||||||
|
}
|
||||||
|
@@ -136,6 +139,9 @@ func (w *Writer) writeLegacyMetadataLocked(layerDescriptors []manifest.Schema2De
|
||||||
|
}
|
||||||
|
|
||||||
|
// This chainID value matches the computation in docker/docker/layer.CreateChainID …
|
||||||
|
+ if err := l.Digest.Validate(); err != nil { // This should never fail on this code path, still: make sure the chainID computation is unambiguous.
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
if chainID == "" {
|
||||||
|
chainID = l.Digest
|
||||||
|
} else {
|
||||||
|
@@ -206,12 +212,20 @@ func checkManifestItemsMatch(a, b *ManifestItem) error {
|
||||||
|
func (w *Writer) ensureManifestItemLocked(layerDescriptors []manifest.Schema2Descriptor, configDigest digest.Digest, repoTags []reference.NamedTagged) error {
|
||||||
|
layerPaths := []string{}
|
||||||
|
for _, l := range layerDescriptors {
|
||||||
|
- layerPaths = append(layerPaths, w.physicalLayerPath(l.Digest))
|
||||||
|
+ p, err := w.physicalLayerPath(l.Digest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
+ layerPaths = append(layerPaths, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
var item *ManifestItem
|
||||||
|
+ configPath, err := w.configPath(configDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
newItem := ManifestItem{
|
||||||
|
- Config: w.configPath(configDigest),
|
||||||
|
+ Config: configPath,
|
||||||
|
RepoTags: []string{},
|
||||||
|
Layers: layerPaths,
|
||||||
|
Parent: "", // We don’t have this information
|
||||||
|
@@ -296,21 +310,27 @@ func (w *Writer) Close() error {
|
||||||
|
// configPath returns a path we choose for storing a config with the specified digest.
|
||||||
|
// NOTE: This is an internal implementation detail, not a format property, and can change
|
||||||
|
// any time.
|
||||||
|
-func (w *Writer) configPath(configDigest digest.Digest) string {
|
||||||
|
- return configDigest.Hex() + ".json"
|
||||||
|
+func (w *Writer) configPath(configDigest digest.Digest) (string, error) {
|
||||||
|
+ if err := configDigest.Validate(); err != nil { // digest.Digest.Hex() panics on failure, and could possibly result in unexpected paths, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
+ return configDigest.Hex() + ".json", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// physicalLayerPath returns a path we choose for storing a layer with the specified digest
|
||||||
|
// (the actual path, i.e. a regular file, not a symlink that may be used in the legacy format).
|
||||||
|
// NOTE: This is an internal implementation detail, not a format property, and can change
|
||||||
|
// any time.
|
||||||
|
-func (w *Writer) physicalLayerPath(layerDigest digest.Digest) string {
|
||||||
|
+func (w *Writer) physicalLayerPath(layerDigest digest.Digest) (string, error) {
|
||||||
|
+ if err := layerDigest.Validate(); err != nil { // digest.Digest.Hex() panics on failure, and could possibly result in unexpected paths, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
// Note that this can't be e.g. filepath.Join(l.Digest.Hex(), legacyLayerFileName); due to the way
|
||||||
|
// writeLegacyMetadata constructs layer IDs differently from inputinfo.Digest values (as described
|
||||||
|
// inside it), most of the layers would end up in subdirectories alone without any metadata; (docker load)
|
||||||
|
// tries to load every subdirectory as an image and fails if the config is missing. So, keep the layers
|
||||||
|
// in the root of the tarball.
|
||||||
|
- return layerDigest.Hex() + ".tar"
|
||||||
|
+ return layerDigest.Hex() + ".tar", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type tarFI struct {
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/ostree/ostree_dest.go b/vendor/github.com/containers/image/v5/ostree/ostree_dest.go
|
||||||
|
index 3eb2a2cb..02115a26 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/ostree/ostree_dest.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/ostree/ostree_dest.go
|
||||||
|
@@ -352,6 +352,10 @@ func (d *ostreeImageDestination) TryReusingBlob(ctx context.Context, info types.
|
||||||
|
}
|
||||||
|
d.repo = repo
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ if err := info.Digest.Validate(); err != nil { // digest.Digest.Hex() panics on failure, so validate explicitly.
|
||||||
|
+ return false, types.BlobInfo{}, err
|
||||||
|
+ }
|
||||||
|
branch := fmt.Sprintf("ociimage/%s", info.Digest.Hex())
|
||||||
|
|
||||||
|
found, data, err := readMetadata(d.repo, branch, "docker.uncompressed_digest")
|
||||||
|
@@ -472,12 +476,18 @@ func (d *ostreeImageDestination) Commit(context.Context, types.UnparsedImage) er
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, layer := range d.schema.LayersDescriptors {
|
||||||
|
+ if err := layer.Digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
hash := layer.Digest.Hex()
|
||||||
|
if err = checkLayer(hash); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, layer := range d.schema.FSLayers {
|
||||||
|
+ if err := layer.BlobSum.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
hash := layer.BlobSum.Hex()
|
||||||
|
if err = checkLayer(hash); err != nil {
|
||||||
|
return err
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/ostree/ostree_src.go b/vendor/github.com/containers/image/v5/ostree/ostree_src.go
|
||||||
|
index d30c764a..f60cbcf7 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/ostree/ostree_src.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/ostree/ostree_src.go
|
||||||
|
@@ -273,7 +273,9 @@ func (s *ostreeImageSource) HasThreadSafeGetBlob() bool {
|
||||||
|
// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
|
||||||
|
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
|
||||||
|
func (s *ostreeImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
|
||||||
|
-
|
||||||
|
+ if err := info.Digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
|
||||||
|
+ return nil, -1, err
|
||||||
|
+ }
|
||||||
|
blob := info.Digest.Hex()
|
||||||
|
|
||||||
|
// Ensure s.compressed is initialized. It is build by LayerInfosForCopy.
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/storage/storage_image.go b/vendor/github.com/containers/image/v5/storage/storage_image.go
|
||||||
|
index 7329ef6e..a40d7f1a 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/storage/storage_image.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/storage/storage_image.go
|
||||||
|
@@ -100,14 +100,21 @@ type storageImageCloser struct {
|
||||||
|
// manifestBigDataKey returns a key suitable for recording a manifest with the specified digest using storage.Store.ImageBigData and related functions.
|
||||||
|
// If a specific manifest digest is explicitly requested by the user, the key returned by this function should be used preferably;
|
||||||
|
// for compatibility, if a manifest is not available under this key, check also storage.ImageDigestBigDataKey
|
||||||
|
-func manifestBigDataKey(digest digest.Digest) string {
|
||||||
|
- return storage.ImageDigestManifestBigDataNamePrefix + "-" + digest.String()
|
||||||
|
+func manifestBigDataKey(digest digest.Digest) (string, error) {
|
||||||
|
+ // return storage.ImageDigestManifestBigDataNamePrefix + "-" + digest.String()
|
||||||
|
+ if err := digest.Validate(); err != nil { // Make sure info.Digest.String() uses the expected format and does not collide with other BigData keys.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
+ return storage.ImageDigestManifestBigDataNamePrefix + "-" + digest.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// signatureBigDataKey returns a key suitable for recording the signatures associated with the manifest with the specified digest using storage.Store.ImageBigData and related functions.
|
||||||
|
// If a specific manifest digest is explicitly requested by the user, the key returned by this function should be used preferably;
|
||||||
|
-func signatureBigDataKey(digest digest.Digest) string {
|
||||||
|
- return "signature-" + digest.Encoded()
|
||||||
|
+func signatureBigDataKey(digest digest.Digest) (string, error) {
|
||||||
|
+ if err := digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
+ return "signature-" + digest.Encoded(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newImageSource sets up an image for reading.
|
||||||
|
@@ -243,8 +250,12 @@ func (s *storageImageSource) getBlobAndLayerID(info types.BlobInfo) (rc io.ReadC
|
||||||
|
|
||||||
|
// GetManifest() reads the image's manifest.
|
||||||
|
func (s *storageImageSource) GetManifest(ctx context.Context, instanceDigest *digest.Digest) (manifestBlob []byte, MIMEType string, err error) {
|
||||||
|
+ // Custom patch for CVE-2024-3727
|
||||||
|
if instanceDigest != nil {
|
||||||
|
- key := manifestBigDataKey(*instanceDigest)
|
||||||
|
+ key, err := manifestBigDataKey(*instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, "", errors.Wrapf(err, "generating manifest big data key for image instance %q", *instanceDigest)
|
||||||
|
+ }
|
||||||
|
blob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", errors.Wrapf(err, "reading manifest for image instance %q", *instanceDigest)
|
||||||
|
@@ -256,7 +267,10 @@ func (s *storageImageSource) GetManifest(ctx context.Context, instanceDigest *di
|
||||||
|
// Prefer the manifest corresponding to the user-specified digest, if available.
|
||||||
|
if s.imageRef.named != nil {
|
||||||
|
if digested, ok := s.imageRef.named.(reference.Digested); ok {
|
||||||
|
- key := manifestBigDataKey(digested.Digest())
|
||||||
|
+ key, err := manifestBigDataKey(digested.Digest())
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, "", err
|
||||||
|
+ }
|
||||||
|
blob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, key)
|
||||||
|
if err != nil && !os.IsNotExist(err) { // os.IsNotExist is true if the image exists but there is no data corresponding to key
|
||||||
|
return nil, "", err
|
||||||
|
@@ -369,7 +383,10 @@ func (s *storageImageSource) GetSignatures(ctx context.Context, instanceDigest *
|
||||||
|
instance := "default instance"
|
||||||
|
if instanceDigest != nil {
|
||||||
|
signatureSizes = s.SignaturesSizes[*instanceDigest]
|
||||||
|
- key = signatureBigDataKey(*instanceDigest)
|
||||||
|
+ key, err = signatureBigDataKey(*instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, errors.Wrapf(err, "generating signature big data key for image instance %q", *instanceDigest)
|
||||||
|
+ }
|
||||||
|
instance = instanceDigest.Encoded()
|
||||||
|
}
|
||||||
|
if len(signatureSizes) > 0 {
|
||||||
|
@@ -1146,7 +1163,10 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "digesting top-level manifest")
|
||||||
|
}
|
||||||
|
- key := manifestBigDataKey(manifestDigest)
|
||||||
|
+ key, err := manifestBigDataKey(manifestDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return errors.Wrapf(err, "getting manifest big data key for image %q", img.ID)
|
||||||
|
+ }
|
||||||
|
if err := s.imageRef.transport.store.SetImageBigData(img.ID, key, toplevelManifest, manifest.Digest); err != nil {
|
||||||
|
logrus.Debugf("error saving top-level manifest for image %q: %v", img.ID, err)
|
||||||
|
return errors.Wrapf(err, "saving top-level manifest for image %q", img.ID)
|
||||||
|
@@ -1155,7 +1175,10 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
|
||||||
|
// Save the image's manifest. Allow looking it up by digest by using the key convention defined by the Store.
|
||||||
|
// Record the manifest twice: using a digest-specific key to allow references to that specific digest instance,
|
||||||
|
// and using storage.ImageDigestBigDataKey for future users that don’t specify any digest and for compatibility with older readers.
|
||||||
|
- key := manifestBigDataKey(s.manifestDigest)
|
||||||
|
+ key, err := manifestBigDataKey(s.manifestDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return errors.Wrapf(err, "getting manifest big data key for image %q", img.ID)
|
||||||
|
+ }
|
||||||
|
if err := s.imageRef.transport.store.SetImageBigData(img.ID, key, s.manifest, manifest.Digest); err != nil {
|
||||||
|
logrus.Debugf("error saving manifest for image %q: %v", img.ID, err)
|
||||||
|
return errors.Wrapf(err, "saving manifest for image %q", img.ID)
|
||||||
|
@@ -1173,7 +1196,10 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for instanceDigest, signatures := range s.signatureses {
|
||||||
|
- key := signatureBigDataKey(instanceDigest)
|
||||||
|
+ key, err := signatureBigDataKey(instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
if err := s.imageRef.transport.store.SetImageBigData(img.ID, key, signatures, manifest.Digest); err != nil {
|
||||||
|
logrus.Debugf("error saving signatures for image %q: %v", img.ID, err)
|
||||||
|
return errors.Wrapf(err, "saving signatures for image %q", img.ID)
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/storage/storage_reference.go b/vendor/github.com/containers/image/v5/storage/storage_reference.go
|
||||||
|
index 7c6da112..ac1d1e42 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/storage/storage_reference.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/storage/storage_reference.go
|
||||||
|
@@ -73,7 +73,10 @@ func multiArchImageMatchesSystemContext(store storage.Store, img *storage.Image,
|
||||||
|
// We don't need to care about storage.ImageDigestBigDataKey because
|
||||||
|
// manifests lists are only stored into storage by c/image versions
|
||||||
|
// that know about manifestBigDataKey, and only using that key.
|
||||||
|
- key := manifestBigDataKey(manifestDigest)
|
||||||
|
+ key, err := manifestBigDataKey(manifestDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return false // This should never happen, manifestDigest comes from a reference.Digested, and that validates the format.
|
||||||
|
+ }
|
||||||
|
manifestBytes, err := store.ImageBigData(img.ID, key)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
@@ -95,7 +98,10 @@ func multiArchImageMatchesSystemContext(store storage.Store, img *storage.Image,
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
- key = manifestBigDataKey(chosenInstance)
|
||||||
|
+ key, err = manifestBigDataKey(chosenInstance)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return false
|
||||||
|
+ }
|
||||||
|
_, err = store.ImageBigData(img.ID, key)
|
||||||
|
return err == nil // true if img.ID is based on chosenInstance.
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.34.1
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
Summary: Configuration files common to github.com/containers
|
Summary: Configuration files common to github.com/containers
|
||||||
Name: libcontainers-common
|
Name: libcontainers-common
|
||||||
Version: 20210626
|
Version: 20210626
|
||||||
Release: 6%{?dist}
|
Release: 7%{?dist}
|
||||||
License: ASL 2.0 AND GPLv3
|
License: ASL 2.0 AND GPLv3
|
||||||
Vendor: Microsoft Corporation
|
Vendor: Microsoft Corporation
|
||||||
Distribution: Mariner
|
Distribution: Mariner
|
||||||
|
@ -52,6 +52,8 @@ Patch0: CVE-2021-44716.patch
|
||||||
Patch1: CVE-2024-37298.patch
|
Patch1: CVE-2024-37298.patch
|
||||||
Patch2: CVE-2021-43565.patch
|
Patch2: CVE-2021-43565.patch
|
||||||
Patch3: CVE-2022-32149.patch
|
Patch3: CVE-2022-32149.patch
|
||||||
|
Patch4: CVE-2024-3727.patch
|
||||||
|
Patch5: podman-CVE-2024-3727.patch
|
||||||
BuildRequires: go-go-md2man
|
BuildRequires: go-go-md2man
|
||||||
Requires(post): grep
|
Requires(post): grep
|
||||||
Requires(post): util-linux
|
Requires(post): util-linux
|
||||||
|
@ -65,15 +67,19 @@ github.com/containers libraries, such as Buildah, CRI-O, Podman and Skopeo.
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q -T -D -b 0 -n image-%{imagever}
|
%setup -q -T -D -b 0 -n image-%{imagever}
|
||||||
|
%patch 4 -p6
|
||||||
|
|
||||||
%setup -q -T -D -b 1 -n storage-%{storagever}
|
%setup -q -T -D -b 1 -n storage-%{storagever}
|
||||||
|
|
||||||
%setup -q -T -D -b 7 -n podman-%{podmanver}
|
%setup -q -T -D -b 7 -n podman-%{podmanver}
|
||||||
|
%patch 5 -p1
|
||||||
%patch 1 -p1
|
%patch 1 -p1
|
||||||
%patch 3 -p1
|
%patch 3 -p1
|
||||||
|
|
||||||
%setup -q -T -D -b 9 -n common-%{commonver}
|
%setup -q -T -D -b 9 -n common-%{commonver}
|
||||||
%patch 0 -p1
|
%patch 0 -p1
|
||||||
%patch 3 -p1
|
%patch 3 -p1
|
||||||
|
%patch 4 -p1
|
||||||
|
|
||||||
# copy the LICENSE file in the build root
|
# copy the LICENSE file in the build root
|
||||||
%patch 2 -p1 -d ../podman-%{podmanver}
|
%patch 2 -p1 -d ../podman-%{podmanver}
|
||||||
|
@ -171,6 +177,9 @@ fi
|
||||||
%license LICENSE
|
%license LICENSE
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Sep 12 2024 Sudipta Pandit <sudpandit@microsoft.com> - 20210626-7
|
||||||
|
- Backport CVE-2024-3727 for all sources from upstream
|
||||||
|
|
||||||
* Tue Aug 27 2024 Sindhu Karri <lakarri@microsoft.com> - 20210626-6
|
* Tue Aug 27 2024 Sindhu Karri <lakarri@microsoft.com> - 20210626-6
|
||||||
- Patch CVE-2022-32149
|
- Patch CVE-2022-32149
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,524 @@
|
||||||
|
From 5a593b2736e49ab2b449a9ab6100a9d44c9fc967 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudipta Pandit <sudpandit@microsoft.com>
|
||||||
|
Date: Thu, 12 Sep 2024 19:37:38 +0530
|
||||||
|
Subject: [PATCH] Backport upstream patch of vendored containers/image of
|
||||||
|
podman
|
||||||
|
|
||||||
|
---
|
||||||
|
.../image/v5/directory/directory_dest.go | 17 +++++--
|
||||||
|
.../image/v5/directory/directory_src.go | 18 ++++++--
|
||||||
|
.../image/v5/directory/directory_transport.go | 25 ++++++----
|
||||||
|
.../image/v5/docker/docker_client.go | 4 ++
|
||||||
|
.../image/v5/docker/docker_image.go | 7 ++-
|
||||||
|
.../image/v5/docker/docker_image_dest.go | 4 ++
|
||||||
|
.../image/v5/docker/docker_image_src.go | 6 +++
|
||||||
|
.../image/v5/docker/internal/tarfile/dest.go | 12 ++++-
|
||||||
|
.../v5/docker/internal/tarfile/writer.go | 34 +++++++++++---
|
||||||
|
.../containers/image/v5/ostree/ostree_dest.go | 10 ++++
|
||||||
|
.../containers/image/v5/ostree/ostree_src.go | 4 +-
|
||||||
|
.../image/v5/storage/storage_image.go | 46 +++++++++++++++----
|
||||||
|
.../image/v5/storage/storage_reference.go | 10 +++-
|
||||||
|
13 files changed, 160 insertions(+), 37 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/directory/directory_dest.go b/vendor/github.com/containers/image/v5/directory/directory_dest.go
|
||||||
|
index e3280aa2b..9cf88175d 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/directory/directory_dest.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/directory/directory_dest.go
|
||||||
|
@@ -213,7 +213,10 @@ func (d *dirImageDestination) TryReusingBlob(ctx context.Context, info types.Blo
|
||||||
|
if info.Digest == "" {
|
||||||
|
return false, types.BlobInfo{}, errors.Errorf(`"Can not check for a blob with unknown digest`)
|
||||||
|
}
|
||||||
|
- blobPath := d.ref.layerPath(info.Digest)
|
||||||
|
+ blobPath, err := d.ref.layerPath(info.Digest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return false, types.BlobInfo{}, err
|
||||||
|
+ }
|
||||||
|
finfo, err := os.Stat(blobPath)
|
||||||
|
if err != nil && os.IsNotExist(err) {
|
||||||
|
return false, types.BlobInfo{}, nil
|
||||||
|
@@ -233,7 +236,11 @@ func (d *dirImageDestination) TryReusingBlob(ctx context.Context, info types.Blo
|
||||||
|
// If the destination is in principle available, refuses this manifest type (e.g. it does not recognize the schema),
|
||||||
|
// but may accept a different manifest type, the returned error must be an ManifestTypeRejectedError.
|
||||||
|
func (d *dirImageDestination) PutManifest(ctx context.Context, manifest []byte, instanceDigest *digest.Digest) error {
|
||||||
|
- return ioutil.WriteFile(d.ref.manifestPath(instanceDigest), manifest, 0644)
|
||||||
|
+ manifestPath, err := d.ref.manifestPath(instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
+ return ioutil.WriteFile(manifestPath, manifest, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutSignatures writes a set of signatures to the destination.
|
||||||
|
@@ -241,7 +248,11 @@ func (d *dirImageDestination) PutManifest(ctx context.Context, manifest []byte,
|
||||||
|
// (when the primary manifest is a manifest list); this should always be nil if the primary manifest is not a manifest list.
|
||||||
|
func (d *dirImageDestination) PutSignatures(ctx context.Context, signatures [][]byte, instanceDigest *digest.Digest) error {
|
||||||
|
for i, sig := range signatures {
|
||||||
|
- if err := ioutil.WriteFile(d.ref.signaturePath(i, instanceDigest), sig, 0644); err != nil {
|
||||||
|
+ signaturePath, err := d.ref.signaturePath(i, instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
+ if err := ioutil.WriteFile(signaturePath, sig, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/directory/directory_src.go b/vendor/github.com/containers/image/v5/directory/directory_src.go
|
||||||
|
index ad9129d40..420cee2fd 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/directory/directory_src.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/directory/directory_src.go
|
||||||
|
@@ -37,7 +37,11 @@ func (s *dirImageSource) Close() error {
|
||||||
|
// If instanceDigest is not nil, it contains a digest of the specific manifest instance to retrieve (when the primary manifest is a manifest list);
|
||||||
|
// this never happens if the primary manifest is not a manifest list (e.g. if the source never returns manifest lists).
|
||||||
|
func (s *dirImageSource) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
|
||||||
|
- m, err := ioutil.ReadFile(s.ref.manifestPath(instanceDigest))
|
||||||
|
+ path, err := s.ref.manifestPath(instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, "", err
|
||||||
|
+ }
|
||||||
|
+ m, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
@@ -53,7 +57,11 @@ func (s *dirImageSource) HasThreadSafeGetBlob() bool {
|
||||||
|
// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
|
||||||
|
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
|
||||||
|
func (s *dirImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
|
||||||
|
- r, err := os.Open(s.ref.layerPath(info.Digest))
|
||||||
|
+ path, err := s.ref.layerPath(info.Digest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, -1, err
|
||||||
|
+ }
|
||||||
|
+ r, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, -1, err
|
||||||
|
}
|
||||||
|
@@ -71,7 +79,11 @@ func (s *dirImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache
|
||||||
|
func (s *dirImageSource) GetSignatures(ctx context.Context, instanceDigest *digest.Digest) ([][]byte, error) {
|
||||||
|
signatures := [][]byte{}
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
- signature, err := ioutil.ReadFile(s.ref.signaturePath(i, instanceDigest))
|
||||||
|
+ path, err := s.ref.signaturePath(i, instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, err
|
||||||
|
+ }
|
||||||
|
+ signature, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
break
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/directory/directory_transport.go b/vendor/github.com/containers/image/v5/directory/directory_transport.go
|
||||||
|
index e542d888c..ea2807070 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/directory/directory_transport.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/directory/directory_transport.go
|
||||||
|
@@ -162,25 +162,34 @@ func (ref dirReference) DeleteImage(ctx context.Context, sys *types.SystemContex
|
||||||
|
}
|
||||||
|
|
||||||
|
// manifestPath returns a path for the manifest within a directory using our conventions.
|
||||||
|
-func (ref dirReference) manifestPath(instanceDigest *digest.Digest) string {
|
||||||
|
+func (ref dirReference) manifestPath(instanceDigest *digest.Digest) (string, error) {
|
||||||
|
if instanceDigest != nil {
|
||||||
|
- return filepath.Join(ref.path, instanceDigest.Encoded()+".manifest.json")
|
||||||
|
+ if err := instanceDigest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
+ return filepath.Join(ref.path, instanceDigest.Encoded()+".manifest.json"), nil
|
||||||
|
}
|
||||||
|
- return filepath.Join(ref.path, "manifest.json")
|
||||||
|
+ return filepath.Join(ref.path, "manifest.json"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// layerPath returns a path for a layer tarball within a directory using our conventions.
|
||||||
|
-func (ref dirReference) layerPath(digest digest.Digest) string {
|
||||||
|
+func (ref dirReference) layerPath(digest digest.Digest) (string, error) {
|
||||||
|
+ if err := digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
// FIXME: Should we keep the digest identification?
|
||||||
|
- return filepath.Join(ref.path, digest.Encoded())
|
||||||
|
+ return filepath.Join(ref.path, digest.Encoded()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// signaturePath returns a path for a signature within a directory using our conventions.
|
||||||
|
-func (ref dirReference) signaturePath(index int, instanceDigest *digest.Digest) string {
|
||||||
|
+func (ref dirReference) signaturePath(index int, instanceDigest *digest.Digest) (string, error) {
|
||||||
|
if instanceDigest != nil {
|
||||||
|
- return filepath.Join(ref.path, fmt.Sprintf(instanceDigest.Encoded()+".signature-%d", index+1))
|
||||||
|
+ if err := instanceDigest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
+ return filepath.Join(ref.path, fmt.Sprintf(instanceDigest.Encoded()+".signature-%d", index+1)), nil
|
||||||
|
}
|
||||||
|
- return filepath.Join(ref.path, fmt.Sprintf("signature-%d", index+1))
|
||||||
|
+ return filepath.Join(ref.path, fmt.Sprintf("signature-%d", index+1)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// versionPath returns a path for the version file within a directory using our conventions.
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/docker_client.go b/vendor/github.com/containers/image/v5/docker/docker_client.go
|
||||||
|
index 3fe9a11d0..08f5d66e4 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/docker_client.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/docker_client.go
|
||||||
|
@@ -796,6 +796,10 @@ func (c *dockerClient) detectProperties(ctx context.Context) error {
|
||||||
|
// getExtensionsSignatures returns signatures from the X-Registry-Supports-Signatures API extension,
|
||||||
|
// using the original data structures.
|
||||||
|
func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerReference, manifestDigest digest.Digest) (*extensionSignatureList, error) {
|
||||||
|
+ // Custom patch for CVE-2024-3727
|
||||||
|
+ if err := manifestDigest.Validate(); err != nil { // Make sure manifestDigest.String() does not contain any unexpected characters
|
||||||
|
+ return nil, err
|
||||||
|
+ }
|
||||||
|
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(ref.ref), manifestDigest)
|
||||||
|
res, err := c.makeRequest(ctx, http.MethodGet, path, nil, nil, v2Auth, nil)
|
||||||
|
if err != nil {
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image.go b/vendor/github.com/containers/image/v5/docker/docker_image.go
|
||||||
|
index c84bb37d2..284b39f50 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/docker_image.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/docker_image.go
|
||||||
|
@@ -83,7 +83,12 @@ func GetRepositoryTags(ctx context.Context, sys *types.SystemContext, ref types.
|
||||||
|
if err = json.NewDecoder(res.Body).Decode(&tagsHolder); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
- tags = append(tags, tagsHolder.Tags...)
|
||||||
|
+ for _, tag := range tagsHolder.Tags {
|
||||||
|
+ if _, err := reference.WithTag(dr.ref, tag); err != nil { // Ensure the tag does not contain unexpected values
|
||||||
|
+ return nil, fmt.Errorf("registry returned invalid tag %q: %w", tag, err)
|
||||||
|
+ }
|
||||||
|
+ tags = append(tags, tag)
|
||||||
|
+ }
|
||||||
|
|
||||||
|
link := res.Header.Get("Link")
|
||||||
|
if link == "" {
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image_dest.go b/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
|
||||||
|
index 360a7122e..323a42a86 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
|
||||||
|
@@ -213,6 +213,9 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
|
||||||
|
// If the destination does not contain the blob, or it is unknown, blobExists ordinarily returns (false, -1, nil);
|
||||||
|
// it returns a non-nil error only on an unexpected failure.
|
||||||
|
func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.Named, digest digest.Digest, extraScope *authScope) (bool, int64, error) {
|
||||||
|
+ if err := digest.Validate(); err != nil { // Make sure digest.String() does not contain any unexpected characters
|
||||||
|
+ return false, -1, err
|
||||||
|
+ }
|
||||||
|
checkPath := fmt.Sprintf(blobsPath, reference.Path(repo), digest.String())
|
||||||
|
logrus.Debugf("Checking %s", checkPath)
|
||||||
|
res, err := d.c.makeRequest(ctx, http.MethodHead, checkPath, nil, nil, v2Auth, extraScope)
|
||||||
|
@@ -639,6 +642,7 @@ sigExists:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // manifestDigest is known to be valid because it was not rejected by getExtensionsSignatures above.
|
||||||
|
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(d.ref.ref), manifestDigest.String())
|
||||||
|
res, err := d.c.makeRequest(ctx, http.MethodPut, path, nil, bytes.NewReader(body), v2Auth, nil)
|
||||||
|
if err != nil {
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image_src.go b/vendor/github.com/containers/image/v5/docker/docker_image_src.go
|
||||||
|
index 5dc8e7b1f..1d79c56bd 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/docker_image_src.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/docker_image_src.go
|
||||||
|
@@ -178,6 +178,9 @@ func simplifyContentType(contentType string) string {
|
||||||
|
// this never happens if the primary manifest is not a manifest list (e.g. if the source never returns manifest lists).
|
||||||
|
func (s *dockerImageSource) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
|
||||||
|
if instanceDigest != nil {
|
||||||
|
+ if err := instanceDigest.Validate(); err != nil { // Make sure instanceDigest.String() does not contain any unexpected characters
|
||||||
|
+ return nil, "", err
|
||||||
|
+ }
|
||||||
|
return s.fetchManifest(ctx, instanceDigest.String())
|
||||||
|
}
|
||||||
|
err := s.ensureManifestIsLoaded(ctx)
|
||||||
|
@@ -362,6 +365,9 @@ func (s *dockerImageSource) GetBlob(ctx context.Context, info types.BlobInfo, ca
|
||||||
|
return s.getExternalBlob(ctx, info.URLs)
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if err := info.Digest.Validate(); err != nil { // Make sure info.Digest.String() does not contain any unexpected characters
|
||||||
|
+ return nil, 0, err
|
||||||
|
+ }
|
||||||
|
path := fmt.Sprintf(blobsPath, reference.Path(s.physicalRef.ref), info.Digest.String())
|
||||||
|
logrus.Debugf("Downloading %s", path)
|
||||||
|
res, err := s.c.makeRequest(ctx, http.MethodGet, path, nil, nil, v2Auth, nil)
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
|
||||||
|
index a558657b6..bb093032a 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
|
||||||
|
@@ -143,11 +143,19 @@ func (d *Destination) PutBlob(ctx context.Context, stream io.Reader, inputInfo t
|
||||||
|
return types.BlobInfo{}, errors.Wrap(err, "reading Config file stream")
|
||||||
|
}
|
||||||
|
d.config = buf
|
||||||
|
- if err := d.archive.sendFileLocked(d.archive.configPath(inputInfo.Digest), inputInfo.Size, bytes.NewReader(buf)); err != nil {
|
||||||
|
+ configPath, err := d.archive.configPath(inputInfo.Digest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return types.BlobInfo{}, errors.Wrap(err, "getting config path")
|
||||||
|
+ }
|
||||||
|
+ if err := d.archive.sendFileLocked(configPath, inputInfo.Size, bytes.NewReader(buf)); err != nil {
|
||||||
|
return types.BlobInfo{}, errors.Wrap(err, "writing Config file")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
- if err := d.archive.sendFileLocked(d.archive.physicalLayerPath(inputInfo.Digest), inputInfo.Size, stream); err != nil {
|
||||||
|
+ layerPath, err := d.archive.physicalLayerPath(inputInfo.Digest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return types.BlobInfo{}, err
|
||||||
|
+ }
|
||||||
|
+ if err := d.archive.sendFileLocked(layerPath, inputInfo.Size, stream); err != nil {
|
||||||
|
return types.BlobInfo{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
|
||||||
|
index 255f0d354..742f977c0 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
|
||||||
|
@@ -92,7 +92,10 @@ func (w *Writer) ensureSingleLegacyLayerLocked(layerID string, layerDigest diges
|
||||||
|
if _, ok := w.legacyLayers[layerID]; !ok {
|
||||||
|
// Create a symlink for the legacy format, where there is one subdirectory per layer ("image").
|
||||||
|
// See also the comment in physicalLayerPath.
|
||||||
|
- physicalLayerPath := w.physicalLayerPath(layerDigest)
|
||||||
|
+ physicalLayerPath, err := w.physicalLayerPath(layerDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
if err := w.sendSymlinkLocked(filepath.Join(layerID, legacyLayerFileName), filepath.Join("..", physicalLayerPath)); err != nil {
|
||||||
|
return errors.Wrap(err, "creating layer symbolic link")
|
||||||
|
}
|
||||||
|
@@ -136,6 +139,9 @@ func (w *Writer) writeLegacyMetadataLocked(layerDescriptors []manifest.Schema2De
|
||||||
|
}
|
||||||
|
|
||||||
|
// This chainID value matches the computation in docker/docker/layer.CreateChainID …
|
||||||
|
+ if err := l.Digest.Validate(); err != nil { // This should never fail on this code path, still: make sure the chainID computation is unambiguous.
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
if chainID == "" {
|
||||||
|
chainID = l.Digest
|
||||||
|
} else {
|
||||||
|
@@ -206,12 +212,20 @@ func checkManifestItemsMatch(a, b *ManifestItem) error {
|
||||||
|
func (w *Writer) ensureManifestItemLocked(layerDescriptors []manifest.Schema2Descriptor, configDigest digest.Digest, repoTags []reference.NamedTagged) error {
|
||||||
|
layerPaths := []string{}
|
||||||
|
for _, l := range layerDescriptors {
|
||||||
|
- layerPaths = append(layerPaths, w.physicalLayerPath(l.Digest))
|
||||||
|
+ p, err := w.physicalLayerPath(l.Digest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
+ layerPaths = append(layerPaths, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
var item *ManifestItem
|
||||||
|
+ configPath, err := w.configPath(configDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
newItem := ManifestItem{
|
||||||
|
- Config: w.configPath(configDigest),
|
||||||
|
+ Config: configPath,
|
||||||
|
RepoTags: []string{},
|
||||||
|
Layers: layerPaths,
|
||||||
|
Parent: "", // We don’t have this information
|
||||||
|
@@ -296,21 +310,27 @@ func (w *Writer) Close() error {
|
||||||
|
// configPath returns a path we choose for storing a config with the specified digest.
|
||||||
|
// NOTE: This is an internal implementation detail, not a format property, and can change
|
||||||
|
// any time.
|
||||||
|
-func (w *Writer) configPath(configDigest digest.Digest) string {
|
||||||
|
- return configDigest.Hex() + ".json"
|
||||||
|
+func (w *Writer) configPath(configDigest digest.Digest) (string, error) {
|
||||||
|
+ if err := configDigest.Validate(); err != nil { // digest.Digest.Hex() panics on failure, and could possibly result in unexpected paths, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
+ return configDigest.Hex() + ".json", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// physicalLayerPath returns a path we choose for storing a layer with the specified digest
|
||||||
|
// (the actual path, i.e. a regular file, not a symlink that may be used in the legacy format).
|
||||||
|
// NOTE: This is an internal implementation detail, not a format property, and can change
|
||||||
|
// any time.
|
||||||
|
-func (w *Writer) physicalLayerPath(layerDigest digest.Digest) string {
|
||||||
|
+func (w *Writer) physicalLayerPath(layerDigest digest.Digest) (string, error) {
|
||||||
|
+ if err := layerDigest.Validate(); err != nil { // digest.Digest.Hex() panics on failure, and could possibly result in unexpected paths, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
// Note that this can't be e.g. filepath.Join(l.Digest.Hex(), legacyLayerFileName); due to the way
|
||||||
|
// writeLegacyMetadata constructs layer IDs differently from inputinfo.Digest values (as described
|
||||||
|
// inside it), most of the layers would end up in subdirectories alone without any metadata; (docker load)
|
||||||
|
// tries to load every subdirectory as an image and fails if the config is missing. So, keep the layers
|
||||||
|
// in the root of the tarball.
|
||||||
|
- return layerDigest.Hex() + ".tar"
|
||||||
|
+ return layerDigest.Hex() + ".tar", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type tarFI struct {
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/ostree/ostree_dest.go b/vendor/github.com/containers/image/v5/ostree/ostree_dest.go
|
||||||
|
index c91a49c57..fc5d58d45 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/ostree/ostree_dest.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/ostree/ostree_dest.go
|
||||||
|
@@ -352,6 +352,10 @@ func (d *ostreeImageDestination) TryReusingBlob(ctx context.Context, info types.
|
||||||
|
}
|
||||||
|
d.repo = repo
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ if err := info.Digest.Validate(); err != nil { // digest.Digest.Hex() panics on failure, so validate explicitly.
|
||||||
|
+ return false, types.BlobInfo{}, err
|
||||||
|
+ }
|
||||||
|
branch := fmt.Sprintf("ociimage/%s", info.Digest.Hex())
|
||||||
|
|
||||||
|
found, data, err := readMetadata(d.repo, branch, "docker.uncompressed_digest")
|
||||||
|
@@ -472,12 +476,18 @@ func (d *ostreeImageDestination) Commit(context.Context, types.UnparsedImage) er
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, layer := range d.schema.LayersDescriptors {
|
||||||
|
+ if err := layer.Digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
hash := layer.Digest.Hex()
|
||||||
|
if err = checkLayer(hash); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, layer := range d.schema.FSLayers {
|
||||||
|
+ if err := layer.BlobSum.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
hash := layer.BlobSum.Hex()
|
||||||
|
if err = checkLayer(hash); err != nil {
|
||||||
|
return err
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/ostree/ostree_src.go b/vendor/github.com/containers/image/v5/ostree/ostree_src.go
|
||||||
|
index 4948ec664..9c4b53968 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/ostree/ostree_src.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/ostree/ostree_src.go
|
||||||
|
@@ -272,7 +272,9 @@ func (s *ostreeImageSource) HasThreadSafeGetBlob() bool {
|
||||||
|
// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
|
||||||
|
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
|
||||||
|
func (s *ostreeImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
|
||||||
|
-
|
||||||
|
+ if err := info.Digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
|
||||||
|
+ return nil, -1, err
|
||||||
|
+ }
|
||||||
|
blob := info.Digest.Hex()
|
||||||
|
|
||||||
|
// Ensure s.compressed is initialized. It is build by LayerInfosForCopy.
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/storage/storage_image.go b/vendor/github.com/containers/image/v5/storage/storage_image.go
|
||||||
|
index 6b0fea61a..433bf383d 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/storage/storage_image.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/storage/storage_image.go
|
||||||
|
@@ -96,14 +96,21 @@ type storageImageCloser struct {
|
||||||
|
// manifestBigDataKey returns a key suitable for recording a manifest with the specified digest using storage.Store.ImageBigData and related functions.
|
||||||
|
// If a specific manifest digest is explicitly requested by the user, the key returned by this function should be used preferably;
|
||||||
|
// for compatibility, if a manifest is not available under this key, check also storage.ImageDigestBigDataKey
|
||||||
|
-func manifestBigDataKey(digest digest.Digest) string {
|
||||||
|
- return storage.ImageDigestManifestBigDataNamePrefix + "-" + digest.String()
|
||||||
|
+func manifestBigDataKey(digest digest.Digest) (string, error) {
|
||||||
|
+ // return storage.ImageDigestManifestBigDataNamePrefix + "-" + digest.String()
|
||||||
|
+ if err := digest.Validate(); err != nil { // Make sure info.Digest.String() uses the expected format and does not collide with other BigData keys.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
+ return storage.ImageDigestManifestBigDataNamePrefix + "-" + digest.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// signatureBigDataKey returns a key suitable for recording the signatures associated with the manifest with the specified digest using storage.Store.ImageBigData and related functions.
|
||||||
|
// If a specific manifest digest is explicitly requested by the user, the key returned by this function should be used preferably;
|
||||||
|
-func signatureBigDataKey(digest digest.Digest) string {
|
||||||
|
- return "signature-" + digest.Encoded()
|
||||||
|
+func signatureBigDataKey(digest digest.Digest) (string, error) {
|
||||||
|
+ if err := digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
|
||||||
|
+ return "", err
|
||||||
|
+ }
|
||||||
|
+ return "signature-" + digest.Encoded(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newImageSource sets up an image for reading.
|
||||||
|
@@ -239,8 +246,12 @@ func (s *storageImageSource) getBlobAndLayerID(info types.BlobInfo) (rc io.ReadC
|
||||||
|
|
||||||
|
// GetManifest() reads the image's manifest.
|
||||||
|
func (s *storageImageSource) GetManifest(ctx context.Context, instanceDigest *digest.Digest) (manifestBlob []byte, MIMEType string, err error) {
|
||||||
|
+ // Custom patch for CVE-2024-3727
|
||||||
|
if instanceDigest != nil {
|
||||||
|
- key := manifestBigDataKey(*instanceDigest)
|
||||||
|
+ key, err := manifestBigDataKey(*instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, "", errors.Wrapf(err, "generating manifest big data key for image instance %q", *instanceDigest)
|
||||||
|
+ }
|
||||||
|
blob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", errors.Wrapf(err, "reading manifest for image instance %q", *instanceDigest)
|
||||||
|
@@ -252,7 +263,10 @@ func (s *storageImageSource) GetManifest(ctx context.Context, instanceDigest *di
|
||||||
|
// Prefer the manifest corresponding to the user-specified digest, if available.
|
||||||
|
if s.imageRef.named != nil {
|
||||||
|
if digested, ok := s.imageRef.named.(reference.Digested); ok {
|
||||||
|
- key := manifestBigDataKey(digested.Digest())
|
||||||
|
+ key, err := manifestBigDataKey(digested.Digest())
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, "", err
|
||||||
|
+ }
|
||||||
|
blob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, key)
|
||||||
|
if err != nil && !os.IsNotExist(err) { // os.IsNotExist is true if the image exists but there is no data corresponding to key
|
||||||
|
return nil, "", err
|
||||||
|
@@ -365,7 +379,10 @@ func (s *storageImageSource) GetSignatures(ctx context.Context, instanceDigest *
|
||||||
|
instance := "default instance"
|
||||||
|
if instanceDigest != nil {
|
||||||
|
signatureSizes = s.SignaturesSizes[*instanceDigest]
|
||||||
|
- key = signatureBigDataKey(*instanceDigest)
|
||||||
|
+ key, err = signatureBigDataKey(*instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return nil, errors.Wrapf(err, "generating signature big data key for image instance %q", *instanceDigest)
|
||||||
|
+ }
|
||||||
|
instance = instanceDigest.Encoded()
|
||||||
|
}
|
||||||
|
if len(signatureSizes) > 0 {
|
||||||
|
@@ -1140,7 +1157,10 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "digesting top-level manifest")
|
||||||
|
}
|
||||||
|
- key := manifestBigDataKey(manifestDigest)
|
||||||
|
+ key, err := manifestBigDataKey(manifestDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return errors.Wrapf(err, "getting manifest big data key for image %q", img.ID)
|
||||||
|
+ }
|
||||||
|
if err := s.imageRef.transport.store.SetImageBigData(img.ID, key, toplevelManifest, manifest.Digest); err != nil {
|
||||||
|
logrus.Debugf("error saving top-level manifest for image %q: %v", img.ID, err)
|
||||||
|
return errors.Wrapf(err, "saving top-level manifest for image %q", img.ID)
|
||||||
|
@@ -1149,7 +1169,10 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
|
||||||
|
// Save the image's manifest. Allow looking it up by digest by using the key convention defined by the Store.
|
||||||
|
// Record the manifest twice: using a digest-specific key to allow references to that specific digest instance,
|
||||||
|
// and using storage.ImageDigestBigDataKey for future users that don’t specify any digest and for compatibility with older readers.
|
||||||
|
- key := manifestBigDataKey(s.manifestDigest)
|
||||||
|
+ key, err := manifestBigDataKey(s.manifestDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return errors.Wrapf(err, "getting manifest big data key for image %q", img.ID)
|
||||||
|
+ }
|
||||||
|
if err := s.imageRef.transport.store.SetImageBigData(img.ID, key, s.manifest, manifest.Digest); err != nil {
|
||||||
|
logrus.Debugf("error saving manifest for image %q: %v", img.ID, err)
|
||||||
|
return errors.Wrapf(err, "saving manifest for image %q", img.ID)
|
||||||
|
@@ -1167,7 +1190,10 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for instanceDigest, signatures := range s.signatureses {
|
||||||
|
- key := signatureBigDataKey(instanceDigest)
|
||||||
|
+ key, err := signatureBigDataKey(instanceDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
if err := s.imageRef.transport.store.SetImageBigData(img.ID, key, signatures, manifest.Digest); err != nil {
|
||||||
|
logrus.Debugf("error saving signatures for image %q: %v", img.ID, err)
|
||||||
|
return errors.Wrapf(err, "saving signatures for image %q", img.ID)
|
||||||
|
diff --git a/vendor/github.com/containers/image/v5/storage/storage_reference.go b/vendor/github.com/containers/image/v5/storage/storage_reference.go
|
||||||
|
index 1aafe9068..ea4846346 100644
|
||||||
|
--- a/vendor/github.com/containers/image/v5/storage/storage_reference.go
|
||||||
|
+++ b/vendor/github.com/containers/image/v5/storage/storage_reference.go
|
||||||
|
@@ -72,7 +72,10 @@ func multiArchImageMatchesSystemContext(store storage.Store, img *storage.Image,
|
||||||
|
// We don't need to care about storage.ImageDigestBigDataKey because
|
||||||
|
// manifests lists are only stored into storage by c/image versions
|
||||||
|
// that know about manifestBigDataKey, and only using that key.
|
||||||
|
- key := manifestBigDataKey(manifestDigest)
|
||||||
|
+ key, err := manifestBigDataKey(manifestDigest)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return false // This should never happen, manifestDigest comes from a reference.Digested, and that validates the format.
|
||||||
|
+ }
|
||||||
|
manifestBytes, err := store.ImageBigData(img.ID, key)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
@@ -94,7 +97,10 @@ func multiArchImageMatchesSystemContext(store storage.Store, img *storage.Image,
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
- key = manifestBigDataKey(chosenInstance)
|
||||||
|
+ key, err = manifestBigDataKey(chosenInstance)
|
||||||
|
+ if err != nil {
|
||||||
|
+ return false
|
||||||
|
+ }
|
||||||
|
_, err = store.ImageBigData(img.ID, key)
|
||||||
|
return err == nil // true if img.ID is based on chosenInstance.
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.34.1
|
||||||
|
|
Загрузка…
Ссылка в новой задаче