From e3e70b398ff362182797e2d73372f8f654ba9383 Mon Sep 17 00:00:00 2001
From: Vanient <xiadanni1@huawei.com>
Date: Thu, 9 Jun 2022 10:45:47 +0800
Subject: [PATCH 1/2] images: validate document type before unmarshal

Conflict:NA
Reference:https://github.com/containerd/containerd/commit/eb9ba7ed8d46d48fb22362f9d91fff6fb837e37e

Signed-off-by: Vanient <xiadanni1@huawei.com>
---
 images/image.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/images/image.go b/images/image.go
index f72684d82..ad12fe971 100644
--- a/images/image.go
+++ b/images/image.go
@@ -19,6 +19,7 @@ package images
 import (
 	"context"
 	"encoding/json"
+	"fmt"
 	"sort"
 	"strings"
 	"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
@@ -335,6 +344,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
@@ -350,6 +363,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
@@ -371,6 +388,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
-- 
2.27.0

