|
@@ -3,9 +3,12 @@ package main
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
"fmt"
|
|
|
+ "os"
|
|
|
+ "path/filepath"
|
|
|
"regexp"
|
|
|
"strings"
|
|
|
|
|
|
+ "github.com/docker/distribution/manifest/schema1"
|
|
|
"github.com/docker/distribution/manifest/schema2"
|
|
|
"github.com/docker/docker/api/types"
|
|
|
"github.com/docker/docker/integration-cli/checker"
|
|
@@ -77,6 +80,10 @@ func (s *DockerRegistrySuite) TestPullByTagDisplaysDigest(c *check.C) {
|
|
|
testPullByTagDisplaysDigest(c)
|
|
|
}
|
|
|
|
|
|
+func (s *DockerSchema1RegistrySuite) TestPullByTagDisplaysDigest(c *check.C) {
|
|
|
+ testPullByTagDisplaysDigest(c)
|
|
|
+}
|
|
|
+
|
|
|
func testPullByDigest(c *check.C) {
|
|
|
testRequires(c, DaemonIsLinux)
|
|
|
pushDigest, err := setupImage(c)
|
|
@@ -99,6 +106,10 @@ func (s *DockerRegistrySuite) TestPullByDigest(c *check.C) {
|
|
|
testPullByDigest(c)
|
|
|
}
|
|
|
|
|
|
+func (s *DockerSchema1RegistrySuite) TestPullByDigest(c *check.C) {
|
|
|
+ testPullByDigest(c)
|
|
|
+}
|
|
|
+
|
|
|
func testPullByDigestNoFallback(c *check.C) {
|
|
|
testRequires(c, DaemonIsLinux)
|
|
|
// pull from the registry using the <name>@<digest> reference
|
|
@@ -112,6 +123,10 @@ func (s *DockerRegistrySuite) TestPullByDigestNoFallback(c *check.C) {
|
|
|
testPullByDigestNoFallback(c)
|
|
|
}
|
|
|
|
|
|
+func (s *DockerSchema1RegistrySuite) TestPullByDigestNoFallback(c *check.C) {
|
|
|
+ testPullByDigestNoFallback(c)
|
|
|
+}
|
|
|
+
|
|
|
func (s *DockerRegistrySuite) TestCreateByDigest(c *check.C) {
|
|
|
pushDigest, err := setupImage(c)
|
|
|
assert.NilError(c, err, "error setting up image")
|
|
@@ -546,3 +561,131 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) {
|
|
|
expectedErrorMsg := fmt.Sprintf("manifest verification failed for digest %s", manifestDigest)
|
|
|
assert.Assert(c, is.Contains(out, expectedErrorMsg))
|
|
|
}
|
|
|
+
|
|
|
+// TestPullFailsWithAlteredManifest tests that a `docker pull` fails when
|
|
|
+// we have modified a manifest blob and its digest cannot be verified.
|
|
|
+// This is the schema1 version of the test.
|
|
|
+func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) {
|
|
|
+ testRequires(c, DaemonIsLinux)
|
|
|
+ manifestDigest, err := setupImage(c)
|
|
|
+ c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
|
|
+
|
|
|
+ // Load the target manifest blob.
|
|
|
+ manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
|
|
|
+
|
|
|
+ var imgManifest schema1.Manifest
|
|
|
+ err = json.Unmarshal(manifestBlob, &imgManifest)
|
|
|
+ c.Assert(err, checker.IsNil, check.Commentf("unable to decode image manifest from blob"))
|
|
|
+
|
|
|
+ // Change a layer in the manifest.
|
|
|
+ imgManifest.FSLayers[0] = schema1.FSLayer{
|
|
|
+ BlobSum: digest.Digest("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"),
|
|
|
+ }
|
|
|
+
|
|
|
+ // Move the existing data file aside, so that we can replace it with a
|
|
|
+ // malicious blob of data. NOTE: we defer the returned undo func.
|
|
|
+ undo := s.reg.TempMoveBlobData(c, manifestDigest)
|
|
|
+ defer undo()
|
|
|
+
|
|
|
+ alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", " ")
|
|
|
+ c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON"))
|
|
|
+
|
|
|
+ s.reg.WriteBlobContents(c, manifestDigest, alteredManifestBlob)
|
|
|
+
|
|
|
+ // Now try pulling that image by digest. We should get an error about
|
|
|
+ // digest verification for the manifest digest.
|
|
|
+
|
|
|
+ // Pull from the registry using the <name>@<digest> reference.
|
|
|
+ imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest)
|
|
|
+ out, exitStatus, _ := dockerCmdWithError("pull", imageReference)
|
|
|
+ c.Assert(exitStatus, checker.Not(check.Equals), 0)
|
|
|
+
|
|
|
+ expectedErrorMsg := fmt.Sprintf("image verification failed for digest %s", manifestDigest)
|
|
|
+ c.Assert(out, checker.Contains, expectedErrorMsg)
|
|
|
+}
|
|
|
+
|
|
|
+// TestPullFailsWithAlteredLayer tests that a `docker pull` fails when
|
|
|
+// we have modified a layer blob and its digest cannot be verified.
|
|
|
+// This is the schema2 version of the test.
|
|
|
+func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
|
|
|
+ testRequires(c, DaemonIsLinux)
|
|
|
+ manifestDigest, err := setupImage(c)
|
|
|
+ c.Assert(err, checker.IsNil)
|
|
|
+
|
|
|
+ // Load the target manifest blob.
|
|
|
+ manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
|
|
|
+
|
|
|
+ var imgManifest schema2.Manifest
|
|
|
+ err = json.Unmarshal(manifestBlob, &imgManifest)
|
|
|
+ c.Assert(err, checker.IsNil)
|
|
|
+
|
|
|
+ // Next, get the digest of one of the layers from the manifest.
|
|
|
+ targetLayerDigest := imgManifest.Layers[0].Digest
|
|
|
+
|
|
|
+ // Move the existing data file aside, so that we can replace it with a
|
|
|
+ // malicious blob of data. NOTE: we defer the returned undo func.
|
|
|
+ undo := s.reg.TempMoveBlobData(c, targetLayerDigest)
|
|
|
+ defer undo()
|
|
|
+
|
|
|
+ // Now make a fake data blob in this directory.
|
|
|
+ s.reg.WriteBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for."))
|
|
|
+
|
|
|
+ // Now try pulling that image by digest. We should get an error about
|
|
|
+ // digest verification for the target layer digest.
|
|
|
+
|
|
|
+ // Remove distribution cache to force a re-pull of the blobs
|
|
|
+ if err := os.RemoveAll(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "image", s.d.StorageDriver(), "distribution")); err != nil {
|
|
|
+ c.Fatalf("error clearing distribution cache: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Pull from the registry using the <name>@<digest> reference.
|
|
|
+ imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest)
|
|
|
+ out, exitStatus, _ := dockerCmdWithError("pull", imageReference)
|
|
|
+ c.Assert(exitStatus, checker.Not(check.Equals), 0, check.Commentf("expected a non-zero exit status"))
|
|
|
+
|
|
|
+ expectedErrorMsg := fmt.Sprintf("filesystem layer verification failed for digest %s", targetLayerDigest)
|
|
|
+ c.Assert(out, checker.Contains, expectedErrorMsg, check.Commentf("expected error message in output: %s", out))
|
|
|
+}
|
|
|
+
|
|
|
+// TestPullFailsWithAlteredLayer tests that a `docker pull` fails when
|
|
|
+// we have modified a layer blob and its digest cannot be verified.
|
|
|
+// This is the schema1 version of the test.
|
|
|
+func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
|
|
|
+ testRequires(c, DaemonIsLinux)
|
|
|
+ manifestDigest, err := setupImage(c)
|
|
|
+ c.Assert(err, checker.IsNil)
|
|
|
+
|
|
|
+ // Load the target manifest blob.
|
|
|
+ manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
|
|
|
+
|
|
|
+ var imgManifest schema1.Manifest
|
|
|
+ err = json.Unmarshal(manifestBlob, &imgManifest)
|
|
|
+ c.Assert(err, checker.IsNil)
|
|
|
+
|
|
|
+ // Next, get the digest of one of the layers from the manifest.
|
|
|
+ targetLayerDigest := imgManifest.FSLayers[0].BlobSum
|
|
|
+
|
|
|
+ // Move the existing data file aside, so that we can replace it with a
|
|
|
+ // malicious blob of data. NOTE: we defer the returned undo func.
|
|
|
+ undo := s.reg.TempMoveBlobData(c, targetLayerDigest)
|
|
|
+ defer undo()
|
|
|
+
|
|
|
+ // Now make a fake data blob in this directory.
|
|
|
+ s.reg.WriteBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for."))
|
|
|
+
|
|
|
+ // Now try pulling that image by digest. We should get an error about
|
|
|
+ // digest verification for the target layer digest.
|
|
|
+
|
|
|
+ // Remove distribution cache to force a re-pull of the blobs
|
|
|
+ if err := os.RemoveAll(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "image", s.d.StorageDriver(), "distribution")); err != nil {
|
|
|
+ c.Fatalf("error clearing distribution cache: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Pull from the registry using the <name>@<digest> reference.
|
|
|
+ imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest)
|
|
|
+ out, exitStatus, _ := dockerCmdWithError("pull", imageReference)
|
|
|
+ c.Assert(exitStatus, checker.Not(check.Equals), 0, check.Commentf("expected a non-zero exit status"))
|
|
|
+
|
|
|
+ expectedErrorMsg := fmt.Sprintf("filesystem layer verification failed for digest %s", targetLayerDigest)
|
|
|
+ c.Assert(out, checker.Contains, expectedErrorMsg, check.Commentf("expected error message in output: %s", out))
|
|
|
+}
|