Skip to content

Commit

Permalink
Do not reset storage when running inside of a container
Browse files Browse the repository at this point in the history
Currently if the host shares container storage with a container
running podman, the podman inside of the container resets the
storage on the host. This can cause issues on the host, as
well as causes the podman command running the container, to
fail to unmount /dev/shm.

podman run -ti --rm --privileged -v /var/lib/containers:/var/lib/containers quay.io/podman/stable podman run alpine echo hello
	* unlinkat /var/lib/containers/storage/overlay-containers/a7f3c9deb0656f8de1d107e7ddff2d3c3c279c11c1635f233a0bffb16051fb2c/userdata/shm: device or resource busy
	* unlinkat /var/lib/containers/storage/overlay-containers/a7f3c9deb0656f8de1d107e7ddff2d3c3c279c11c1635f233a0bffb16051fb2c/userdata/shm: device or resource busy

Since podman is volume mounting in the graphroot, it will add a flag to
/run/.containerenv to tell podman inside of container whether to reset storage or not.

Since the inner podman is running inside of the container, no reason to assume this is a fresh reboot, so if "container" environment variable is set then skip
reset of storage.

Also added tests to make sure /run/.containerenv is runnig correctly.

Fixes: #9191

Signed-off-by: Daniel J Walsh <[email protected]>
  • Loading branch information
rhatdan committed Feb 16, 2021
1 parent 7fb347a commit 5d1ec29
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 5 deletions.
4 changes: 2 additions & 2 deletions libpod/container_internal_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -1627,7 +1627,7 @@ func (c *Container) makeBindMounts() error {

// Make .containerenv if it does not exist
if _, ok := c.state.BindMounts["/run/.containerenv"]; !ok {
var containerenv string
containerenv := c.runtime.graphRootMountedFlag(c.config.Spec.Mounts)
isRootless := 0
if rootless.IsRootless() {
isRootless = 1
Expand All @@ -1642,7 +1642,7 @@ id=%q
image=%q
imageid=%q
rootless=%d
`, version.Version.String(), c.Name(), c.ID(), imageName, imageID, isRootless)
%s`, version.Version.String(), c.Name(), c.ID(), imageName, imageID, isRootless, containerenv)
}
containerenvPath, err := c.writeStringToRundir(".containerenv", containerenv)
if err != nil {
Expand Down
37 changes: 34 additions & 3 deletions libpod/runtime.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package libpod

import (
"bufio"
"context"
"fmt"
"os"
Expand All @@ -26,6 +27,7 @@ import (
"github.com/containers/storage"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/docker/pkg/namesgenerator"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -622,9 +624,12 @@ func (r *Runtime) Shutdown(force bool) error {
func (r *Runtime) refresh(alivePath string) error {
logrus.Debugf("Podman detected system restart - performing state refresh")

// First clear the state in the database
if err := r.state.Refresh(); err != nil {
return err
// Clear state of database if not running in container
if !graphRootMounted() {
// First clear the state in the database
if err := r.state.Refresh(); err != nil {
return err
}
}

// Next refresh the state of all containers to recreate dirs and
Expand Down Expand Up @@ -904,3 +909,29 @@ func (r *Runtime) getVolumePlugin(name string) (*plugin.VolumePlugin, error) {
func (r *Runtime) GetSecretsStorageDir() string {
return filepath.Join(r.store.GraphRoot(), "secrets")
}

func graphRootMounted() bool {
f, err := os.OpenFile("/run/.containerenv", os.O_RDONLY, os.ModePerm)
if err != nil {
return false
}
defer f.Close()

scanner := bufio.NewScanner(f)
for scanner.Scan() {
if scanner.Text() == "graphRootMounted=1" {
return true
}
}
return false
}

func (r *Runtime) graphRootMountedFlag(mounts []spec.Mount) string {
root := r.store.GraphRoot()
for _, val := range mounts {
if strings.HasPrefix(root, val.Source) {
return "graphRootMounted=1"
}
}
return ""
}
23 changes: 23 additions & 0 deletions test/e2e/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,29 @@ var _ = Describe("Podman run", func() {
Expect(session.ExitCode()).To(Equal(0))
})

It("podman run check /run/.containerenv", func() {
session := podmanTest.Podman([]string{"run", ALPINE, "cat", "/run/.containerenv"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal(""))

session = podmanTest.Podman([]string{"run", "--privileged", "--name=test1", ALPINE, "cat", "/run/.containerenv"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("name=\"test1\""))
Expect(session.OutputToString()).To(ContainSubstring("image=\"" + ALPINE + "\""))

session = podmanTest.Podman([]string{"run", "-v", "/:/host", ALPINE, "cat", "/run/.containerenv"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("graphRootMounted=1"))

session = podmanTest.Podman([]string{"run", "-v", "/:/host", "--privileged", ALPINE, "cat", "/run/.containerenv"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("graphRootMounted=1"))
})

It("podman run a container based on a complex local image name", func() {
imageName := strings.TrimPrefix(nginx, "quay.io/")
session := podmanTest.Podman([]string{"run", imageName, "ls"})
Expand Down

0 comments on commit 5d1ec29

Please sign in to comment.