diff --git a/daemon/load.go b/daemon/load.go index c0713741cf0ccfc9627487e30b180ce11e782e12..69175d795a4bef0a42f24be4f54f707d4de1d7f9 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 5e1a42bc99dbdcea5640ed280e4f90a3a60760af..cecda36034102d9091ee6170d3f6d3616a4983d1 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") }