131 lines
4.8 KiB
Diff
131 lines
4.8 KiB
Diff
|
|
From 373d9fb100649b74811acc73e6b7d67f539b561c Mon Sep 17 00:00:00 2001
|
||
|
|
From: daisicheng <daisicheng@huawei.com>
|
||
|
|
Date: Wed, 1 Feb 2023 15:12:33 +0800
|
||
|
|
Subject: [PATCH] add manifest.json verification before loading a tar
|
||
|
|
|
||
|
|
---
|
||
|
|
daemon/load.go | 45 +++++++++++++++++++++++++++++++++++++--------
|
||
|
|
daemon/load_test.go | 13 +++----------
|
||
|
|
2 files changed, 40 insertions(+), 18 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/daemon/load.go b/daemon/load.go
|
||
|
|
index c071374..69175d7 100644
|
||
|
|
--- a/daemon/load.go
|
||
|
|
+++ b/daemon/load.go
|
||
|
|
@@ -16,6 +16,7 @@ package daemon
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"os"
|
||
|
|
+ "strconv"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
"github.com/containers/image/v5/docker/tarfile"
|
||
|
|
@@ -175,25 +176,26 @@ func tryToParseImageFormatFromTarball(dataRoot string, opts *LoadOptions) ([]sin
|
||
|
|
systemContext.BigFilesTemporaryDir = tmpDir
|
||
|
|
|
||
|
|
// try docker format loading
|
||
|
|
- imagesInTar, err := getDockerRepoTagFromImageTar(systemContext, opts.path)
|
||
|
|
- if err == nil {
|
||
|
|
+ imagesInTar, errDockerFormat := getDockerRepoTagFromImageTar(systemContext, opts.path)
|
||
|
|
+ if errDockerFormat == nil {
|
||
|
|
logrus.Infof("Parse image successful with %q format", constant.DockerTransport)
|
||
|
|
opts.format = constant.DockerArchiveTransport
|
||
|
|
return imagesInTar, nil
|
||
|
|
}
|
||
|
|
- logrus.Warnf("Try to Parse image of docker format failed with error: %v", err)
|
||
|
|
+ logrus.Warnf("Try to Parse image of docker format failed with error: %v", errDockerFormat)
|
||
|
|
|
||
|
|
// try oci format loading
|
||
|
|
- imagesInTar, err = getOCIRepoTagFromImageTar(systemContext, opts.path)
|
||
|
|
- if err == nil {
|
||
|
|
+ imagesInTar, errOciFormat := getOCIRepoTagFromImageTar(systemContext, opts.path)
|
||
|
|
+ if errOciFormat == nil {
|
||
|
|
logrus.Infof("Parse image successful with %q format", constant.OCITransport)
|
||
|
|
opts.format = constant.OCIArchiveTransport
|
||
|
|
return imagesInTar, nil
|
||
|
|
}
|
||
|
|
- logrus.Warnf("Try to parse image of oci format failed with error: %v", err)
|
||
|
|
+ logrus.Warnf("Try to parse image of oci format failed with error: %v", errOciFormat)
|
||
|
|
|
||
|
|
- // record the last error
|
||
|
|
- return nil, errors.Wrap(err, "wrong image format detected from local tarball")
|
||
|
|
+ // record the error
|
||
|
|
+ return nil, errors.Errorf("wrong image format detected from local tarball: try docker format: %v,try oci format: %v",
|
||
|
|
+ errDockerFormat, errOciFormat)
|
||
|
|
}
|
||
|
|
|
||
|
|
func getDockerRepoTagFromImageTar(systemContext *types.SystemContext, path string) ([]singleImage, error) {
|
||
|
|
@@ -215,6 +217,9 @@ func getDockerRepoTagFromImageTar(systemContext *types.SystemContext, path strin
|
||
|
|
|
||
|
|
imagesInTar := make([]singleImage, 0, len(topLevelImageManifest))
|
||
|
|
for i, manifestItem := range topLevelImageManifest {
|
||
|
|
+ if err := checkManifestIsValid(systemContext, path, i); err != nil {
|
||
|
|
+ return nil, err
|
||
|
|
+ }
|
||
|
|
imageID, err := parseConfigID(manifestItem.Config)
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
@@ -282,3 +287,27 @@ func getLoadedImageID(imageRef types.ImageReference, systemContext *types.System
|
||
|
|
|
||
|
|
return "@" + imageDigest.Encoded(), nil
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+func checkManifestIsValid(systemContext *types.SystemContext, path string, manifestIndex int) error {
|
||
|
|
+ imageName := exporter.FormatTransport(constant.DockerArchiveTransport, path)
|
||
|
|
+ srcRef, err := alltransports.ParseImageName(imageName + ":@" + strconv.Itoa(manifestIndex))
|
||
|
|
+ if err != nil {
|
||
|
|
+ return errors.Wrap(err, "failed to parse image name of docker image format")
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if srcRef == nil || systemContext == nil {
|
||
|
|
+ return errors.New("nil image reference or system context when loading image")
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ newImage, err := srcRef.NewImage(context.TODO(), systemContext)
|
||
|
|
+ if err != nil {
|
||
|
|
+ return err
|
||
|
|
+ }
|
||
|
|
+ defer func() {
|
||
|
|
+ if err = newImage.Close(); err != nil {
|
||
|
|
+ logrus.Errorf("failed to close image: %v", err)
|
||
|
|
+ }
|
||
|
|
+ }()
|
||
|
|
+
|
||
|
|
+ return nil
|
||
|
|
+}
|
||
|
|
diff --git a/daemon/load_test.go b/daemon/load_test.go
|
||
|
|
index 5e1a42b..cecda36 100644
|
||
|
|
--- a/daemon/load_test.go
|
||
|
|
+++ b/daemon/load_test.go
|
||
|
|
@@ -271,7 +271,7 @@ func TestLoadSingleImage(t *testing.T) {
|
||
|
|
assert.ErrorContains(t, err, tc.errString)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
- assert.ErrorContains(t, err, "failed to get the image")
|
||
|
|
+ assert.ErrorContains(t, err, "wrong image format detected from local tarball")
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -314,16 +314,9 @@ func TestLoadMultipleImages(t *testing.T) {
|
||
|
|
defer clean(dir)
|
||
|
|
|
||
|
|
path := dir.Join(loadedTarFile)
|
||
|
|
- repoTags, err := tryToParseImageFormatFromTarball(daemon.opts.DataRoot, &LoadOptions{path: path})
|
||
|
|
- assert.NilError(t, err)
|
||
|
|
- assert.Equal(t, repoTags[0].nameTag[0], "registry.example.com/sayhello:first")
|
||
|
|
- assert.Equal(t, repoTags[1].nameTag[0], "registry.example.com/sayhello:second")
|
||
|
|
- assert.Equal(t, repoTags[1].nameTag[1], "registry.example.com/sayhello:third")
|
||
|
|
- assert.Equal(t, len(repoTags[2].nameTag), 0)
|
||
|
|
-
|
||
|
|
req := &pb.LoadRequest{Path: path}
|
||
|
|
stream := &controlLoadServer{}
|
||
|
|
|
||
|
|
- err = daemon.backend.Load(req, stream)
|
||
|
|
- assert.ErrorContains(t, err, "failed to get the image")
|
||
|
|
+ err := daemon.backend.Load(req, stream)
|
||
|
|
+ assert.ErrorContains(t, err, "wrong image format detected from local tarball")
|
||
|
|
}
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|