mirror of
https://github.com/containers/skopeo.git
synced 2025-06-23 13:27:45 +00:00
Update to c/image v5.17.0
Includes a fix for CVE-2021-41190 / GHSA-77vh-xpmg-72qh . Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
parent
904c745bb0
commit
69728fdf93
2
go.mod
2
go.mod
@ -4,7 +4,7 @@ go 1.12
|
||||
|
||||
require (
|
||||
github.com/containers/common v0.46.1-0.20211026130826-7abfd453c86f
|
||||
github.com/containers/image/v5 v5.16.2-0.20211021181114-25411654075f
|
||||
github.com/containers/image/v5 v5.17.0
|
||||
github.com/containers/ocicrypt v1.1.2
|
||||
github.com/containers/storage v1.37.0
|
||||
github.com/docker/docker v20.10.11+incompatible
|
||||
|
6
go.sum
6
go.sum
@ -228,8 +228,8 @@ github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRD
|
||||
github.com/containers/common v0.46.1-0.20211026130826-7abfd453c86f h1:jFFIV8QvsPgwkJHh3tjfREFRwSeMq5M8lt8vklkZaOk=
|
||||
github.com/containers/common v0.46.1-0.20211026130826-7abfd453c86f/go.mod h1:pVvmLTLCOZE300e4rex/QDmpnRmEM/5aZ/YfCkkjgZo=
|
||||
github.com/containers/image/v5 v5.16.1/go.mod h1:mCvIFdzyyP1B0NBcZ80OIuaYqFn/OpFpaOMOMn1kU2M=
|
||||
github.com/containers/image/v5 v5.16.2-0.20211021181114-25411654075f h1:gqeQG8jumo9u6TmyUPrSCuflSjkQX+zFa5bRJAZYz2g=
|
||||
github.com/containers/image/v5 v5.16.2-0.20211021181114-25411654075f/go.mod h1:ERFkrXC5lLXov65ia/NiKBKfEeHgiItB9bQz6fReQ7g=
|
||||
github.com/containers/image/v5 v5.17.0 h1:KS5pro80CCsSp5qDBTMmSAWQo+xcBX19zUPExmYX2OQ=
|
||||
github.com/containers/image/v5 v5.17.0/go.mod h1:GnYVusVRFPMMTAAUkrcS8NNSpBp8oyrjOUe04AAmRr4=
|
||||
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
|
||||
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
||||
github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
|
||||
@ -279,7 +279,6 @@ github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v20.10.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v20.10.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v20.10.10+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v20.10.11+incompatible h1:OqzI/g/W54LczvhnccGqniFoQghHx3pklbLuhfXpqGo=
|
||||
github.com/docker/docker v20.10.11+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
@ -537,6 +536,7 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=
|
||||
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
|
||||
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
|
22
vendor/github.com/containers/image/v5/docker/docker_image_src.go
generated
vendored
22
vendor/github.com/containers/image/v5/docker/docker_image_src.go
generated
vendored
@ -236,6 +236,9 @@ func (s *dockerImageSource) ensureManifestIsLoaded(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// getExternalBlob returns the reader of the first available blob URL from urls, which must not be empty.
|
||||
// This function can return nil reader when no url is supported by this function. In this case, the caller
|
||||
// should fallback to fetch the non-external blob (i.e. pull from the registry).
|
||||
func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string) (io.ReadCloser, int64, error) {
|
||||
var (
|
||||
resp *http.Response
|
||||
@ -244,14 +247,17 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
|
||||
if len(urls) == 0 {
|
||||
return nil, 0, errors.New("internal error: getExternalBlob called with no URLs")
|
||||
}
|
||||
for _, url := range urls {
|
||||
for _, u := range urls {
|
||||
if u, err := url.Parse(u); err != nil || (u.Scheme != "http" && u.Scheme != "https") {
|
||||
continue // unsupported url. skip this url.
|
||||
}
|
||||
// NOTE: we must not authenticate on additional URLs as those
|
||||
// can be abused to leak credentials or tokens. Please
|
||||
// refer to CVE-2020-15157 for more information.
|
||||
resp, err = s.c.makeRequestToResolvedURL(ctx, http.MethodGet, url, nil, nil, -1, noAuth, nil)
|
||||
resp, err = s.c.makeRequestToResolvedURL(ctx, http.MethodGet, u, nil, nil, -1, noAuth, nil)
|
||||
if err == nil {
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = errors.Errorf("error fetching external blob from %q: %d (%s)", url, resp.StatusCode, http.StatusText(resp.StatusCode))
|
||||
err = errors.Errorf("error fetching external blob from %q: %d (%s)", u, resp.StatusCode, http.StatusText(resp.StatusCode))
|
||||
logrus.Debug(err)
|
||||
resp.Body.Close()
|
||||
continue
|
||||
@ -259,6 +265,9 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
|
||||
break
|
||||
}
|
||||
}
|
||||
if resp == nil && err == nil {
|
||||
return nil, 0, nil // fallback to non-external blob
|
||||
}
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
@ -408,7 +417,12 @@ func (s *dockerImageSource) GetBlobAt(ctx context.Context, info types.BlobInfo,
|
||||
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
|
||||
func (s *dockerImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
|
||||
if len(info.URLs) != 0 {
|
||||
return s.getExternalBlob(ctx, info.URLs)
|
||||
r, s, err := s.getExternalBlob(ctx, info.URLs)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
} else if r != nil {
|
||||
return r, s, nil
|
||||
}
|
||||
}
|
||||
|
||||
path := fmt.Sprintf(blobsPath, reference.Path(s.physicalRef.ref), info.Digest.String())
|
||||
|
67
vendor/github.com/containers/image/v5/manifest/common.go
generated
vendored
67
vendor/github.com/containers/image/v5/manifest/common.go
generated
vendored
@ -1,6 +1,7 @@
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
compressiontypes "github.com/containers/image/v5/pkg/compression/types"
|
||||
@ -32,6 +33,72 @@ func dupStringStringMap(m map[string]string) map[string]string {
|
||||
return result
|
||||
}
|
||||
|
||||
// allowedManifestFields is a bit mask of “essential” manifest fields that validateUnambiguousManifestFormat
|
||||
// can expect to be present.
|
||||
type allowedManifestFields int
|
||||
|
||||
const (
|
||||
allowedFieldConfig allowedManifestFields = 1 << iota
|
||||
allowedFieldFSLayers
|
||||
allowedFieldHistory
|
||||
allowedFieldLayers
|
||||
allowedFieldManifests
|
||||
allowedFieldFirstUnusedBit // Keep this at the end!
|
||||
)
|
||||
|
||||
// validateUnambiguousManifestFormat rejects manifests (incl. multi-arch) that look like more than
|
||||
// one kind we currently recognize, i.e. if they contain any of the known “essential” format fields
|
||||
// other than the ones the caller specifically allows.
|
||||
// expectedMIMEType is used only for diagnostics.
|
||||
// NOTE: The caller should do the non-heuristic validations (e.g. check for any specified format
|
||||
// identification/version, or other “magic numbers”) before calling this, to cleanly reject unambigous
|
||||
// data that just isn’t what was expected, as opposed to actually ambiguous data.
|
||||
func validateUnambiguousManifestFormat(manifest []byte, expectedMIMEType string,
|
||||
allowed allowedManifestFields) error {
|
||||
if allowed >= allowedFieldFirstUnusedBit {
|
||||
return fmt.Errorf("internal error: invalid allowedManifestFields value %#v", allowed)
|
||||
}
|
||||
// Use a private type to decode, not just a map[string]interface{}, because we want
|
||||
// to also reject case-insensitive matches (which would be used by Go when really decoding
|
||||
// the manifest).
|
||||
// (It is expected that as manifest formats are added or extended over time, more fields will be added
|
||||
// here.)
|
||||
detectedFields := struct {
|
||||
Config interface{} `json:"config"`
|
||||
FSLayers interface{} `json:"fsLayers"`
|
||||
History interface{} `json:"history"`
|
||||
Layers interface{} `json:"layers"`
|
||||
Manifests interface{} `json:"manifests"`
|
||||
}{}
|
||||
if err := json.Unmarshal(manifest, &detectedFields); err != nil {
|
||||
// The caller was supposed to already validate version numbers, so this shold not happen;
|
||||
// let’s not bother with making this error “nice”.
|
||||
return err
|
||||
}
|
||||
unexpected := []string{}
|
||||
// Sadly this isn’t easy to automate in Go, without reflection. So, copy&paste.
|
||||
if detectedFields.Config != nil && (allowed&allowedFieldConfig) == 0 {
|
||||
unexpected = append(unexpected, "config")
|
||||
}
|
||||
if detectedFields.FSLayers != nil && (allowed&allowedFieldFSLayers) == 0 {
|
||||
unexpected = append(unexpected, "fsLayers")
|
||||
}
|
||||
if detectedFields.History != nil && (allowed&allowedFieldHistory) == 0 {
|
||||
unexpected = append(unexpected, "history")
|
||||
}
|
||||
if detectedFields.Layers != nil && (allowed&allowedFieldLayers) == 0 {
|
||||
unexpected = append(unexpected, "layers")
|
||||
}
|
||||
if detectedFields.Manifests != nil && (allowed&allowedFieldManifests) == 0 {
|
||||
unexpected = append(unexpected, "manifests")
|
||||
}
|
||||
if len(unexpected) != 0 {
|
||||
return fmt.Errorf(`rejecting ambiguous manifest, unexpected fields %#v in supposedly %s`,
|
||||
unexpected, expectedMIMEType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// layerInfosToStrings converts a list of layer infos, presumably obtained from a Manifest.LayerInfos()
|
||||
// method call, into a format suitable for inclusion in a types.ImageInspectInfo structure.
|
||||
func layerInfosToStrings(infos []LayerInfo) []string {
|
||||
|
4
vendor/github.com/containers/image/v5/manifest/docker_schema1.go
generated
vendored
4
vendor/github.com/containers/image/v5/manifest/docker_schema1.go
generated
vendored
@ -60,6 +60,10 @@ func Schema1FromManifest(manifest []byte) (*Schema1, error) {
|
||||
if s1.SchemaVersion != 1 {
|
||||
return nil, errors.Errorf("unsupported schema version %d", s1.SchemaVersion)
|
||||
}
|
||||
if err := validateUnambiguousManifestFormat(manifest, DockerV2Schema1SignedMediaType,
|
||||
allowedFieldFSLayers|allowedFieldHistory); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s1.initialize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
4
vendor/github.com/containers/image/v5/manifest/docker_schema2.go
generated
vendored
4
vendor/github.com/containers/image/v5/manifest/docker_schema2.go
generated
vendored
@ -165,6 +165,10 @@ func Schema2FromManifest(manifest []byte) (*Schema2, error) {
|
||||
if err := json.Unmarshal(manifest, &s2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateUnambiguousManifestFormat(manifest, DockerV2Schema2MediaType,
|
||||
allowedFieldConfig|allowedFieldLayers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Check manifest's and layers' media types.
|
||||
if err := SupportedSchema2MediaType(s2.MediaType); err != nil {
|
||||
return nil, err
|
||||
|
4
vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go
generated
vendored
4
vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go
generated
vendored
@ -192,6 +192,10 @@ func Schema2ListFromManifest(manifest []byte) (*Schema2List, error) {
|
||||
if err := json.Unmarshal(manifest, &list); err != nil {
|
||||
return nil, errors.Wrapf(err, "unmarshaling Schema2List %q", string(manifest))
|
||||
}
|
||||
if err := validateUnambiguousManifestFormat(manifest, DockerV2ListMediaType,
|
||||
allowedFieldManifests); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &list, nil
|
||||
}
|
||||
|
||||
|
4
vendor/github.com/containers/image/v5/manifest/oci.go
generated
vendored
4
vendor/github.com/containers/image/v5/manifest/oci.go
generated
vendored
@ -54,6 +54,10 @@ func OCI1FromManifest(manifest []byte) (*OCI1, error) {
|
||||
if err := json.Unmarshal(manifest, &oci1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateUnambiguousManifestFormat(manifest, imgspecv1.MediaTypeImageIndex,
|
||||
allowedFieldConfig|allowedFieldLayers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &oci1, nil
|
||||
}
|
||||
|
||||
|
4
vendor/github.com/containers/image/v5/manifest/oci_index.go
generated
vendored
4
vendor/github.com/containers/image/v5/manifest/oci_index.go
generated
vendored
@ -202,6 +202,10 @@ func OCI1IndexFromManifest(manifest []byte) (*OCI1Index, error) {
|
||||
if err := json.Unmarshal(manifest, &index); err != nil {
|
||||
return nil, errors.Wrapf(err, "unmarshaling OCI1Index %q", string(manifest))
|
||||
}
|
||||
if err := validateUnambiguousManifestFormat(manifest, imgspecv1.MediaTypeImageIndex,
|
||||
allowedFieldManifests); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &index, nil
|
||||
}
|
||||
|
||||
|
30
vendor/github.com/containers/image/v5/oci/layout/oci_src.go
generated
vendored
30
vendor/github.com/containers/image/v5/oci/layout/oci_src.go
generated
vendored
@ -5,6 +5,7 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
@ -113,7 +114,12 @@ func (s *ociImageSource) HasThreadSafeGetBlob() bool {
|
||||
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
|
||||
func (s *ociImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
|
||||
if len(info.URLs) != 0 {
|
||||
return s.getExternalBlob(ctx, info.URLs)
|
||||
r, s, err := s.getExternalBlob(ctx, info.URLs)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
} else if r != nil {
|
||||
return r, s, nil
|
||||
}
|
||||
}
|
||||
|
||||
path, err := s.ref.blobPath(info.Digest, s.sharedBlobDir)
|
||||
@ -140,34 +146,44 @@ func (s *ociImageSource) GetSignatures(ctx context.Context, instanceDigest *dige
|
||||
return [][]byte{}, nil
|
||||
}
|
||||
|
||||
// getExternalBlob returns the reader of the first available blob URL from urls, which must not be empty.
|
||||
// This function can return nil reader when no url is supported by this function. In this case, the caller
|
||||
// should fallback to fetch the non-external blob (i.e. pull from the registry).
|
||||
func (s *ociImageSource) getExternalBlob(ctx context.Context, urls []string) (io.ReadCloser, int64, error) {
|
||||
if len(urls) == 0 {
|
||||
return nil, 0, errors.New("internal error: getExternalBlob called with no URLs")
|
||||
}
|
||||
|
||||
errWrap := errors.New("failed fetching external blob from all urls")
|
||||
for _, url := range urls {
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
hasSupportedURL := false
|
||||
for _, u := range urls {
|
||||
if u, err := url.Parse(u); err != nil || (u.Scheme != "http" && u.Scheme != "https") {
|
||||
continue // unsupported url. skip this url.
|
||||
}
|
||||
hasSupportedURL = true
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
|
||||
if err != nil {
|
||||
errWrap = errors.Wrapf(errWrap, "fetching %s failed %s", url, err.Error())
|
||||
errWrap = errors.Wrapf(errWrap, "fetching %s failed %s", u, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req)
|
||||
if err != nil {
|
||||
errWrap = errors.Wrapf(errWrap, "fetching %s failed %s", url, err.Error())
|
||||
errWrap = errors.Wrapf(errWrap, "fetching %s failed %s", u, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
resp.Body.Close()
|
||||
errWrap = errors.Wrapf(errWrap, "fetching %s failed, response code not 200", url)
|
||||
errWrap = errors.Wrapf(errWrap, "fetching %s failed, response code not 200", u)
|
||||
continue
|
||||
}
|
||||
|
||||
return resp.Body, getBlobSize(resp), nil
|
||||
}
|
||||
if !hasSupportedURL {
|
||||
return nil, 0, nil // fallback to non-external blob
|
||||
}
|
||||
|
||||
return nil, 0, errWrap
|
||||
}
|
||||
|
6
vendor/github.com/containers/image/v5/version/version.go
generated
vendored
6
vendor/github.com/containers/image/v5/version/version.go
generated
vendored
@ -6,12 +6,12 @@ const (
|
||||
// VersionMajor is for an API incompatible changes
|
||||
VersionMajor = 5
|
||||
// VersionMinor is for functionality in a backwards-compatible manner
|
||||
VersionMinor = 16
|
||||
VersionMinor = 17
|
||||
// VersionPatch is for backwards-compatible bug fixes
|
||||
VersionPatch = 2
|
||||
VersionPatch = 0
|
||||
|
||||
// VersionDev indicates development branch. Releases will be empty string.
|
||||
VersionDev = "-dev"
|
||||
VersionDev = ""
|
||||
)
|
||||
|
||||
// Version is the specification version that the package types support.
|
||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -53,7 +53,7 @@ github.com/containers/common/pkg/flag
|
||||
github.com/containers/common/pkg/report
|
||||
github.com/containers/common/pkg/report/camelcase
|
||||
github.com/containers/common/pkg/retry
|
||||
# github.com/containers/image/v5 v5.16.2-0.20211021181114-25411654075f
|
||||
# github.com/containers/image/v5 v5.17.0
|
||||
github.com/containers/image/v5/copy
|
||||
github.com/containers/image/v5/directory
|
||||
github.com/containers/image/v5/directory/explicitfilepath
|
||||
|
Loading…
Reference in New Issue
Block a user