|
|
4c4c1b |
From c140ecdc9b416ab4efd4d21d14acd63b6adbdd42 Mon Sep 17 00:00:00 2001
|
|
|
4c4c1b |
From: Matthew Heon <matthew.heon@pm.me>
|
|
|
4c4c1b |
Date: Mon, 10 Feb 2020 13:37:38 -0500
|
|
|
4c4c1b |
Subject: [PATCH] Do not copy up when volume is not empty
|
|
|
4c4c1b |
|
|
|
4c4c1b |
When Docker performs a copy up, it first verifies that the volume
|
|
|
4c4c1b |
being copied into is empty; thus, for volumes that have been
|
|
|
4c4c1b |
modified elsewhere (e.g. manually copying into then), the copy up
|
|
|
4c4c1b |
will not be performed at all. Duplicate this behavior in Podman
|
|
|
4c4c1b |
by checking if the volume is empty before copying.
|
|
|
4c4c1b |
|
|
|
4c4c1b |
Furthermore, move setting copyup to false further up. This will
|
|
|
4c4c1b |
prevent a potential race where copy up could happen more than
|
|
|
4c4c1b |
once if Podman was killed after some files had been copied but
|
|
|
4c4c1b |
before the DB was updated.
|
|
|
4c4c1b |
|
|
|
4c4c1b |
This resolves CVE-2020-1726.
|
|
|
4c4c1b |
|
|
|
4c4c1b |
Signed-off-by: Matthew Heon <matthew.heon@pm.me>
|
|
|
4c4c1b |
---
|
|
|
4c4c1b |
libpod/container_internal.go | 28 ++++++++++++++++++++++------
|
|
|
4c4c1b |
test/e2e/run_volume_test.go | 24 ++++++++++++++++++++++++
|
|
|
4c4c1b |
2 files changed, 46 insertions(+), 6 deletions(-)
|
|
|
4c4c1b |
|
|
|
4c4c1b |
diff -up ./libpod-5cc92849f7fc9dd734ca2fd8f3ae8830b9a7eb26/libpod/container_internal.go.CVE-2020-1726 ./libpod-5cc92849f7fc9dd734ca2fd8f3ae8830b9a7eb26/libpod/container_internal.go
|
|
|
4c4c1b |
--- libpod-5cc92849f7fc9dd734ca2fd8f3ae8830b9a7eb26/libpod/container_internal.go.CVE-2020-1726 2020-02-13 22:37:15.002058706 +0100
|
|
|
4c4c1b |
+++ libpod-5cc92849f7fc9dd734ca2fd8f3ae8830b9a7eb26/libpod/container_internal.go 2020-02-13 22:37:15.005058742 +0100
|
|
|
4c4c1b |
@@ -1358,18 +1358,34 @@ func (c *Container) mountNamedVolume(v *
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
if vol.state.NeedsCopyUp {
|
|
|
4c4c1b |
logrus.Debugf("Copying up contents from container %s to volume %s", c.ID(), vol.Name())
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ // Set NeedsCopyUp to false immediately, so we don't try this
|
|
|
4c4c1b |
+ // again when there are already files copied.
|
|
|
4c4c1b |
+ vol.state.NeedsCopyUp = false
|
|
|
4c4c1b |
+ if err := vol.save(); err != nil {
|
|
|
4c4c1b |
+ return nil, err
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ // If the volume is not empty, we should not copy up.
|
|
|
4c4c1b |
+ volMount := vol.MountPoint()
|
|
|
4c4c1b |
+ contents, err := ioutil.ReadDir(volMount)
|
|
|
4c4c1b |
+ if err != nil {
|
|
|
4c4c1b |
+ return nil, errors.Wrapf(err, "error listing contents of volume %s mountpoint when copying up from container %s", vol.Name(), c.ID())
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+ if len(contents) > 0 {
|
|
|
4c4c1b |
+ // The volume is not empty. It was likely modified
|
|
|
4c4c1b |
+ // outside of Podman. For safety, let's not copy up into
|
|
|
4c4c1b |
+ // it. Fixes CVE-2020-1726.
|
|
|
4c4c1b |
+ return vol, nil
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
srcDir, err := securejoin.SecureJoin(mountpoint, v.Dest)
|
|
|
4c4c1b |
if err != nil {
|
|
|
4c4c1b |
return nil, errors.Wrapf(err, "error calculating destination path to copy up container %s volume %s", c.ID(), vol.Name())
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
- if err := c.copyWithTarFromImage(srcDir, vol.MountPoint()); err != nil && !os.IsNotExist(err) {
|
|
|
4c4c1b |
+ if err := c.copyWithTarFromImage(srcDir, volMount); err != nil && !os.IsNotExist(err) {
|
|
|
4c4c1b |
return nil, errors.Wrapf(err, "error copying content from container %s into volume %s", c.ID(), vol.Name())
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- vol.state.NeedsCopyUp = false
|
|
|
4c4c1b |
- if err := vol.save(); err != nil {
|
|
|
4c4c1b |
- return nil, err
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
return vol, nil
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
diff -up ./libpod-5cc92849f7fc9dd734ca2fd8f3ae8830b9a7eb26/test/e2e/run_volume_test.go.CVE-2020-1726 ./libpod-5cc92849f7fc9dd734ca2fd8f3ae8830b9a7eb26/test/e2e/run_volume_test.go
|
|
|
4c4c1b |
--- libpod-5cc92849f7fc9dd734ca2fd8f3ae8830b9a7eb26/test/e2e/run_volume_test.go.CVE-2020-1726 2020-02-13 22:37:15.030059039 +0100
|
|
|
4c4c1b |
+++ libpod-5cc92849f7fc9dd734ca2fd8f3ae8830b9a7eb26/test/e2e/run_volume_test.go 2020-02-13 22:37:15.033059075 +0100
|
|
|
4c4c1b |
@@ -375,4 +375,28 @@ var _ = Describe("Podman run with volume
|
|
|
4c4c1b |
volMount.WaitWithDefaultTimeout()
|
|
|
4c4c1b |
Expect(volMount.ExitCode()).To(Not(Equal(0)))
|
|
|
4c4c1b |
})
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ It("Podman fix for CVE-2020-1726", func() {
|
|
|
4c4c1b |
+ volName := "testVol"
|
|
|
4c4c1b |
+ volCreate := podmanTest.Podman([]string{"volume", "create", volName})
|
|
|
4c4c1b |
+ volCreate.WaitWithDefaultTimeout()
|
|
|
4c4c1b |
+ Expect(volCreate.ExitCode()).To(Equal(0))
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ volPath := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{.Mountpoint}}", volName})
|
|
|
4c4c1b |
+ volPath.WaitWithDefaultTimeout()
|
|
|
4c4c1b |
+ Expect(volPath.ExitCode()).To(Equal(0))
|
|
|
4c4c1b |
+ path := volPath.OutputToString()
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ fileName := "thisIsATestFile"
|
|
|
4c4c1b |
+ file, err := os.Create(filepath.Join(path, fileName))
|
|
|
4c4c1b |
+ Expect(err).To(BeNil())
|
|
|
4c4c1b |
+ defer file.Close()
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ runLs := podmanTest.Podman([]string{"run", "-t", "-i", "--rm", "-v", fmt.Sprintf("%v:/etc/ssl", volName), ALPINE, "ls", "-1", "/etc/ssl"})
|
|
|
4c4c1b |
+ runLs.WaitWithDefaultTimeout()
|
|
|
4c4c1b |
+ Expect(runLs.ExitCode()).To(Equal(0))
|
|
|
4c4c1b |
+ outputArr := runLs.OutputToStringArray()
|
|
|
4c4c1b |
+ Expect(len(outputArr)).To(Equal(1))
|
|
|
4c4c1b |
+ Expect(strings.Contains(outputArr[0], fileName)).To(BeTrue())
|
|
|
4c4c1b |
+ })
|
|
|
4c4c1b |
})
|