Skip to content

Commit c140ecd

Browse files
committed
Do not copy up when volume is not empty
When Docker performs a copy up, it first verifies that the volume being copied into is empty; thus, for volumes that have been modified elsewhere (e.g. manually copying into then), the copy up will not be performed at all. Duplicate this behavior in Podman by checking if the volume is empty before copying. Furthermore, move setting copyup to false further up. This will prevent a potential race where copy up could happen more than once if Podman was killed after some files had been copied but before the DB was updated. This resolves CVE-2020-1726. Signed-off-by: Matthew Heon <[email protected]>
1 parent e57253d commit c140ecd

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

libpod/container_internal.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,18 +1383,34 @@ func (c *Container) mountNamedVolume(v *ContainerNamedVolume, mountpoint string)
13831383
}
13841384
if vol.state.NeedsCopyUp {
13851385
logrus.Debugf("Copying up contents from container %s to volume %s", c.ID(), vol.Name())
1386+
1387+
// Set NeedsCopyUp to false immediately, so we don't try this
1388+
// again when there are already files copied.
1389+
vol.state.NeedsCopyUp = false
1390+
if err := vol.save(); err != nil {
1391+
return nil, err
1392+
}
1393+
1394+
// If the volume is not empty, we should not copy up.
1395+
volMount := vol.MountPoint()
1396+
contents, err := ioutil.ReadDir(volMount)
1397+
if err != nil {
1398+
return nil, errors.Wrapf(err, "error listing contents of volume %s mountpoint when copying up from container %s", vol.Name(), c.ID())
1399+
}
1400+
if len(contents) > 0 {
1401+
// The volume is not empty. It was likely modified
1402+
// outside of Podman. For safety, let's not copy up into
1403+
// it. Fixes CVE-2020-1726.
1404+
return vol, nil
1405+
}
1406+
13861407
srcDir, err := securejoin.SecureJoin(mountpoint, v.Dest)
13871408
if err != nil {
13881409
return nil, errors.Wrapf(err, "error calculating destination path to copy up container %s volume %s", c.ID(), vol.Name())
13891410
}
1390-
if err := c.copyWithTarFromImage(srcDir, vol.MountPoint()); err != nil && !os.IsNotExist(err) {
1411+
if err := c.copyWithTarFromImage(srcDir, volMount); err != nil && !os.IsNotExist(err) {
13911412
return nil, errors.Wrapf(err, "error copying content from container %s into volume %s", c.ID(), vol.Name())
13921413
}
1393-
1394-
vol.state.NeedsCopyUp = false
1395-
if err := vol.save(); err != nil {
1396-
return nil, err
1397-
}
13981414
}
13991415
return vol, nil
14001416
}

test/e2e/run_volume_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,4 +397,28 @@ var _ = Describe("Podman run with volumes", func() {
397397
volMount.WaitWithDefaultTimeout()
398398
Expect(volMount.ExitCode()).To(Not(Equal(0)))
399399
})
400+
401+
It("Podman fix for CVE-2020-1726", func() {
402+
volName := "testVol"
403+
volCreate := podmanTest.Podman([]string{"volume", "create", volName})
404+
volCreate.WaitWithDefaultTimeout()
405+
Expect(volCreate.ExitCode()).To(Equal(0))
406+
407+
volPath := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{.Mountpoint}}", volName})
408+
volPath.WaitWithDefaultTimeout()
409+
Expect(volPath.ExitCode()).To(Equal(0))
410+
path := volPath.OutputToString()
411+
412+
fileName := "thisIsATestFile"
413+
file, err := os.Create(filepath.Join(path, fileName))
414+
Expect(err).To(BeNil())
415+
defer file.Close()
416+
417+
runLs := podmanTest.Podman([]string{"run", "-t", "-i", "--rm", "-v", fmt.Sprintf("%v:/etc/ssl", volName), ALPINE, "ls", "-1", "/etc/ssl"})
418+
runLs.WaitWithDefaultTimeout()
419+
Expect(runLs.ExitCode()).To(Equal(0))
420+
outputArr := runLs.OutputToStringArray()
421+
Expect(len(outputArr)).To(Equal(1))
422+
Expect(strings.Contains(outputArr[0], fileName)).To(BeTrue())
423+
})
400424
})

0 commit comments

Comments
 (0)