Merge pull request from GHSA-xmmx-7jpf-fx42
[20.10] vendor: update github.com/docker/distribution and github.com/containerd/containerd
This commit is contained in:
commit
10106a0f66
7 changed files with 217 additions and 13 deletions
|
@ -3,6 +3,7 @@ package distribution
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
|
@ -11,7 +12,9 @@ import (
|
|||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/manifest/manifestlist"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -166,8 +169,10 @@ func detectManifestMediaType(ra content.ReaderAt) (string, error) {
|
|||
func detectManifestBlobMediaType(dt []byte) (string, error) {
|
||||
var mfst struct {
|
||||
MediaType string `json:"mediaType"`
|
||||
Config json.RawMessage `json:"config"` // schema2 Manifest
|
||||
FSLayers json.RawMessage `json:"fsLayers"` // schema1 Manifest
|
||||
Manifests json.RawMessage `json:"manifests"` // oci index, manifest list
|
||||
Config json.RawMessage `json:"config"` // schema2 Manifest
|
||||
Layers json.RawMessage `json:"layers"` // schema2 Manifest
|
||||
FSLayers json.RawMessage `json:"fsLayers"` // schema1 Manifest
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(dt, &mfst); err != nil {
|
||||
|
@ -178,18 +183,40 @@ func detectManifestBlobMediaType(dt []byte) (string, error) {
|
|||
// Docker types should generally have a media type set.
|
||||
// OCI (golang) types do not have a `mediaType` defined, and it is optional in the spec.
|
||||
//
|
||||
// `distrubtion.UnmarshalManifest`, which is used to unmarshal this for real, checks these media type values.
|
||||
// `distribution.UnmarshalManifest`, which is used to unmarshal this for real, checks these media type values.
|
||||
// If the specified media type does not match it will error, and in some cases (docker media types) it is required.
|
||||
// So pretty much if we don't have a media type we can fall back to OCI.
|
||||
// This does have a special fallback for schema1 manifests just because it is easy to detect.
|
||||
switch {
|
||||
case mfst.MediaType != "":
|
||||
switch mfst.MediaType {
|
||||
case schema2.MediaTypeManifest, specs.MediaTypeImageManifest:
|
||||
if mfst.Manifests != nil || mfst.FSLayers != nil {
|
||||
return "", fmt.Errorf(`media-type: %q should not have "manifests" or "fsLayers"`, mfst.MediaType)
|
||||
}
|
||||
return mfst.MediaType, nil
|
||||
case manifestlist.MediaTypeManifestList, specs.MediaTypeImageIndex:
|
||||
if mfst.Config != nil || mfst.Layers != nil || mfst.FSLayers != nil {
|
||||
return "", fmt.Errorf(`media-type: %q should not have "config", "layers", or "fsLayers"`, mfst.MediaType)
|
||||
}
|
||||
return mfst.MediaType, nil
|
||||
case schema1.MediaTypeManifest:
|
||||
if mfst.Manifests != nil || mfst.Layers != nil {
|
||||
return "", fmt.Errorf(`media-type: %q should not have "manifests" or "layers"`, mfst.MediaType)
|
||||
}
|
||||
return mfst.MediaType, nil
|
||||
case mfst.FSLayers != nil:
|
||||
return schema1.MediaTypeManifest, nil
|
||||
case mfst.Config != nil:
|
||||
return specs.MediaTypeImageManifest, nil
|
||||
default:
|
||||
if mfst.MediaType != "" {
|
||||
return mfst.MediaType, nil
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case mfst.FSLayers != nil && mfst.Manifests == nil && mfst.Layers == nil && mfst.Config == nil:
|
||||
return schema1.MediaTypeManifest, nil
|
||||
case mfst.Config != nil && mfst.Manifests == nil && mfst.FSLayers == nil,
|
||||
mfst.Layers != nil && mfst.Manifests == nil && mfst.FSLayers == nil:
|
||||
return specs.MediaTypeImageManifest, nil
|
||||
case mfst.Config == nil && mfst.Layers == nil && mfst.FSLayers == nil:
|
||||
// fallback to index
|
||||
return specs.MediaTypeImageIndex, nil
|
||||
}
|
||||
return "", errors.New("media-type: cannot determine")
|
||||
}
|
||||
|
|
|
@ -14,8 +14,10 @@ import (
|
|||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/manifest/manifestlist"
|
||||
"github.com/docker/distribution/manifest/ocischema"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
@ -349,3 +351,73 @@ func TestDetectManifestBlobMediaType(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func TestDetectManifestBlobMediaTypeInvalid(t *testing.T) {
|
||||
type testCase struct {
|
||||
json []byte
|
||||
expected string
|
||||
}
|
||||
cases := map[string]testCase{
|
||||
"schema 1 mediaType with manifests": {
|
||||
[]byte(`{"mediaType": "` + schema1.MediaTypeManifest + `","manifests":[]}`),
|
||||
`media-type: "application/vnd.docker.distribution.manifest.v1+json" should not have "manifests" or "layers"`,
|
||||
},
|
||||
"schema 1 mediaType with layers": {
|
||||
[]byte(`{"mediaType": "` + schema1.MediaTypeManifest + `","layers":[]}`),
|
||||
`media-type: "application/vnd.docker.distribution.manifest.v1+json" should not have "manifests" or "layers"`,
|
||||
},
|
||||
"schema 2 mediaType with manifests": {
|
||||
[]byte(`{"mediaType": "` + schema2.MediaTypeManifest + `","manifests":[]}`),
|
||||
`media-type: "application/vnd.docker.distribution.manifest.v2+json" should not have "manifests" or "fsLayers"`,
|
||||
},
|
||||
"schema 2 mediaType with fsLayers": {
|
||||
[]byte(`{"mediaType": "` + schema2.MediaTypeManifest + `","fsLayers":[]}`),
|
||||
`media-type: "application/vnd.docker.distribution.manifest.v2+json" should not have "manifests" or "fsLayers"`,
|
||||
},
|
||||
"oci manifest mediaType with manifests": {
|
||||
[]byte(`{"mediaType": "` + specs.MediaTypeImageManifest + `","manifests":[]}`),
|
||||
`media-type: "application/vnd.oci.image.manifest.v1+json" should not have "manifests" or "fsLayers"`,
|
||||
},
|
||||
"manifest list mediaType with fsLayers": {
|
||||
[]byte(`{"mediaType": "` + manifestlist.MediaTypeManifestList + `","fsLayers":[]}`),
|
||||
`media-type: "application/vnd.docker.distribution.manifest.list.v2+json" should not have "config", "layers", or "fsLayers"`,
|
||||
},
|
||||
"index mediaType with layers": {
|
||||
[]byte(`{"mediaType": "` + specs.MediaTypeImageIndex + `","layers":[]}`),
|
||||
`media-type: "application/vnd.oci.image.index.v1+json" should not have "config", "layers", or "fsLayers"`,
|
||||
},
|
||||
"index mediaType with config": {
|
||||
[]byte(`{"mediaType": "` + specs.MediaTypeImageIndex + `","config":{}}`),
|
||||
`media-type: "application/vnd.oci.image.index.v1+json" should not have "config", "layers", or "fsLayers"`,
|
||||
},
|
||||
"config and manifests": {
|
||||
[]byte(`{"config":{}, "manifests":[]}`),
|
||||
`media-type: cannot determine`,
|
||||
},
|
||||
"layers and manifests": {
|
||||
[]byte(`{"layers":[], "manifests":[]}`),
|
||||
`media-type: cannot determine`,
|
||||
},
|
||||
"layers and fsLayers": {
|
||||
[]byte(`{"layers":[], "fsLayers":[]}`),
|
||||
`media-type: cannot determine`,
|
||||
},
|
||||
"fsLayers and manifests": {
|
||||
[]byte(`{"fsLayers":[], "manifests":[]}`),
|
||||
`media-type: cannot determine`,
|
||||
},
|
||||
"config and fsLayers": {
|
||||
[]byte(`{"config":{}, "fsLayers":[]}`),
|
||||
`media-type: cannot determine`,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
mt, err := detectManifestBlobMediaType(tc.json)
|
||||
assert.Error(t, err, tc.expected)
|
||||
assert.Equal(t, mt, "")
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ github.com/ishidawataru/sctp f2269e66cdee387bd321445d5d30
|
|||
go.etcd.io/bbolt 232d8fc87f50244f9c808f4745759e08a304c029 # v1.3.5
|
||||
|
||||
# get graph and distribution packages
|
||||
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
|
||||
github.com/docker/distribution 58f99e93b767ebacbf8e62a9074844712d31a177 github.com/samuelkarp/docker-distribution
|
||||
github.com/vbatts/tar-split 620714a4c508c880ac1bdda9c8370a2b19af1a55 # v0.11.1
|
||||
github.com/opencontainers/go-digest ea51bea511f75cfa3ef6098cc253c5c3609b037a # v1.0.0
|
||||
|
||||
|
@ -130,7 +130,7 @@ github.com/googleapis/gax-go bd5b16380fd03dc758d11cef74ba
|
|||
google.golang.org/genproto 3f1135a288c9a07e340ae8ba4cc6c7065a3160e8
|
||||
|
||||
# containerd
|
||||
github.com/containerd/containerd 0edc412565dcc6e3d6125ff9e4b009ad4b89c638 # master (v1.5.0-dev)
|
||||
github.com/containerd/containerd e048c115a3a89caf63941d363858e207c28bccd6 github.com/moby/containerd # master (v1.5.0-dev) + patch for CVE-2021-41190
|
||||
github.com/containerd/fifo 0724c46b320cf96bb172a0550c19a4b1fca4dacb
|
||||
github.com/containerd/continuity efbc4488d8fe1bdc16bde3b2d2990d9b3a899165
|
||||
github.com/containerd/cgroups 0b889c03f102012f1d93a97ddd3ef71cd6f4f510
|
||||
|
|
55
vendor/github.com/containerd/containerd/images/image.go
generated
vendored
55
vendor/github.com/containerd/containerd/images/image.go
generated
vendored
|
@ -19,6 +19,7 @@ package images
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
|
@ -154,6 +155,10 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := validateMediaType(p, desc.MediaType); err != nil {
|
||||
return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest)
|
||||
}
|
||||
|
||||
var manifest ocispec.Manifest
|
||||
if err := json.Unmarshal(p, &manifest); err != nil {
|
||||
return nil, err
|
||||
|
@ -194,6 +199,10 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := validateMediaType(p, desc.MediaType); err != nil {
|
||||
return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest)
|
||||
}
|
||||
|
||||
var idx ocispec.Index
|
||||
if err := json.Unmarshal(p, &idx); err != nil {
|
||||
return nil, err
|
||||
|
@ -336,6 +345,10 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := validateMediaType(p, desc.MediaType); err != nil {
|
||||
return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest)
|
||||
}
|
||||
|
||||
// TODO(stevvooe): We just assume oci manifest, for now. There may be
|
||||
// subtle differences from the docker version.
|
||||
var manifest ocispec.Manifest
|
||||
|
@ -351,6 +364,10 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := validateMediaType(p, desc.MediaType); err != nil {
|
||||
return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest)
|
||||
}
|
||||
|
||||
var index ocispec.Index
|
||||
if err := json.Unmarshal(p, &index); err != nil {
|
||||
return nil, err
|
||||
|
@ -368,6 +385,44 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
|
|||
return descs, nil
|
||||
}
|
||||
|
||||
// unknownDocument represents a manifest, manifest list, or index that has not
|
||||
// yet been validated.
|
||||
type unknownDocument struct {
|
||||
MediaType string `json:"mediaType,omitempty"`
|
||||
Config json.RawMessage `json:"config,omitempty"`
|
||||
Layers json.RawMessage `json:"layers,omitempty"`
|
||||
Manifests json.RawMessage `json:"manifests,omitempty"`
|
||||
FSLayers json.RawMessage `json:"fsLayers,omitempty"` // schema 1
|
||||
}
|
||||
|
||||
// validateMediaType returns an error if the byte slice is invalid JSON or if
|
||||
// the media type identifies the blob as one format but it contains elements of
|
||||
// another format.
|
||||
func validateMediaType(b []byte, mt string) error {
|
||||
var doc unknownDocument
|
||||
if err := json.Unmarshal(b, &doc); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(doc.FSLayers) != 0 {
|
||||
return fmt.Errorf("media-type: schema 1 not supported")
|
||||
}
|
||||
switch mt {
|
||||
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
|
||||
if len(doc.Manifests) != 0 ||
|
||||
doc.MediaType == MediaTypeDockerSchema2ManifestList ||
|
||||
doc.MediaType == ocispec.MediaTypeImageIndex {
|
||||
return fmt.Errorf("media-type: expected manifest but found index (%s)", mt)
|
||||
}
|
||||
case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
|
||||
if len(doc.Config) != 0 || len(doc.Layers) != 0 ||
|
||||
doc.MediaType == MediaTypeDockerSchema2Manifest ||
|
||||
doc.MediaType == ocispec.MediaTypeImageManifest {
|
||||
return fmt.Errorf("media-type: expected index but found manifest (%s)", mt)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RootFS returns the unpacked diffids that make up and images rootfs.
|
||||
//
|
||||
// These are used to verify that a set of layers unpacked to the expected
|
||||
|
|
9
vendor/github.com/containerd/containerd/remotes/docker/schema1/converter.go
generated
vendored
9
vendor/github.com/containerd/containerd/remotes/docker/schema1/converter.go
generated
vendored
|
@ -256,6 +256,9 @@ func (c *Converter) fetchManifest(ctx context.Context, desc ocispec.Descriptor)
|
|||
if err := json.Unmarshal(b, &m); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(m.Manifests) != 0 || len(m.Layers) != 0 {
|
||||
return errors.New("converter: expected schema1 document but found extra keys")
|
||||
}
|
||||
c.pulledManifest = &m
|
||||
|
||||
return nil
|
||||
|
@ -472,8 +475,10 @@ type history struct {
|
|||
}
|
||||
|
||||
type manifest struct {
|
||||
FSLayers []fsLayer `json:"fsLayers"`
|
||||
History []history `json:"history"`
|
||||
FSLayers []fsLayer `json:"fsLayers"`
|
||||
History []history `json:"history"`
|
||||
Layers json.RawMessage `json:"layers,omitempty"` // OCI manifest
|
||||
Manifests json.RawMessage `json:"manifests,omitempty"` // OCI index
|
||||
}
|
||||
|
||||
type v1History struct {
|
||||
|
|
23
vendor/github.com/docker/distribution/manifest/manifestlist/manifestlist.go
generated
vendored
23
vendor/github.com/docker/distribution/manifest/manifestlist/manifestlist.go
generated
vendored
|
@ -54,6 +54,9 @@ func init() {
|
|||
}
|
||||
|
||||
imageIndexFunc := func(b []byte) (distribution.Manifest, distribution.Descriptor, error) {
|
||||
if err := validateIndex(b); err != nil {
|
||||
return nil, distribution.Descriptor{}, err
|
||||
}
|
||||
m := new(DeserializedManifestList)
|
||||
err := m.UnmarshalJSON(b)
|
||||
if err != nil {
|
||||
|
@ -214,3 +217,23 @@ func (m DeserializedManifestList) Payload() (string, []byte, error) {
|
|||
|
||||
return mediaType, m.canonical, nil
|
||||
}
|
||||
|
||||
// unknownDocument represents a manifest, manifest list, or index that has not
|
||||
// yet been validated
|
||||
type unknownDocument struct {
|
||||
Config interface{} `json:"config,omitempty"`
|
||||
Layers interface{} `json:"layers,omitempty"`
|
||||
}
|
||||
|
||||
// validateIndex returns an error if the byte slice is invalid JSON or if it
|
||||
// contains fields that belong to a manifest
|
||||
func validateIndex(b []byte) error {
|
||||
var doc unknownDocument
|
||||
if err := json.Unmarshal(b, &doc); err != nil {
|
||||
return err
|
||||
}
|
||||
if doc.Config != nil || doc.Layers != nil {
|
||||
return errors.New("index: expected index but found manifest")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
22
vendor/github.com/docker/distribution/manifest/ocischema/manifest.go
generated
vendored
22
vendor/github.com/docker/distribution/manifest/ocischema/manifest.go
generated
vendored
|
@ -22,6 +22,9 @@ var (
|
|||
|
||||
func init() {
|
||||
ocischemaFunc := func(b []byte) (distribution.Manifest, distribution.Descriptor, error) {
|
||||
if err := validateManifest(b); err != nil {
|
||||
return nil, distribution.Descriptor{}, err
|
||||
}
|
||||
m := new(DeserializedManifest)
|
||||
err := m.UnmarshalJSON(b)
|
||||
if err != nil {
|
||||
|
@ -122,3 +125,22 @@ func (m *DeserializedManifest) MarshalJSON() ([]byte, error) {
|
|||
func (m DeserializedManifest) Payload() (string, []byte, error) {
|
||||
return v1.MediaTypeImageManifest, m.canonical, nil
|
||||
}
|
||||
|
||||
// unknownDocument represents a manifest, manifest list, or index that has not
|
||||
// yet been validated
|
||||
type unknownDocument struct {
|
||||
Manifests interface{} `json:"manifests,omitempty"`
|
||||
}
|
||||
|
||||
// validateManifest returns an error if the byte slice is invalid JSON or if it
|
||||
// contains fields that belong to a index
|
||||
func validateManifest(b []byte) error {
|
||||
var doc unknownDocument
|
||||
if err := json.Unmarshal(b, &doc); err != nil {
|
||||
return err
|
||||
}
|
||||
if doc.Manifests != nil {
|
||||
return errors.New("ocimanifest: expected manifest but found index")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue