Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions libcontainer/state_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"github.com/opencontainers/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)

Expand Down Expand Up @@ -61,11 +62,36 @@
return fmt.Errorf("unable to remove container state dir: %w", err)
}
c.initProcess = nil

if !c.config.Namespaces.IsPrivate(configs.NEWNS) {
unmountMounts(c)
}

err := runPoststopHooks(c)
c.state = &stoppedState{c: c}
return err
}

func unmountMounts(c *Container) {
// Unmount recursive
if err := unix.Unmount(c.config.Rootfs, unix.MNT_DETACH); err == nil {
return
}

// If recursive unmount fails, try best-effort unmount
// We iterate in reverse to unmount children before parents

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, should this be sorted by length instead? Or do we actually rely on the order of mounts? (we may)

for i := len(c.config.Mounts) - 1; i >= 0; i-- {

Check failure on line 83 in libcontainer/state_linux.go

View workflow job for this annotation

GitHub Actions / lint

slicesbackward: backward loop over slice can be modernized using slices.Backward (modernize)
m := c.config.Mounts[i]
mountpoint := filepath.Join(c.config.Rootfs, m.Destination)
if err := unmount(mountpoint, unix.MNT_DETACH); err != nil {
logrus.Warn(err)
Comment thread
kolyshkin marked this conversation as resolved.
}
}
if err := unmount(c.config.Rootfs, unix.MNT_DETACH); err != nil {
logrus.Warn(err)
}
}

func runPoststopHooks(c *Container) error {
hooks := c.config.Hooks
if hooks == nil {
Expand Down
30 changes: 30 additions & 0 deletions tests/integration/mounts.bats
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,33 @@ test_mount_target() {
rm -rf rootfs/tmp/hosts
test_mount_target . /etc/hosts /tmp/hosts
}

# https://github.com/opencontainers/runc/pull/3118
@test "runc delete [cleanup host mount namespace]" {
requires root

# Remove 'mount' namespace and clear masked/readonly paths
update_config ' .linux.namespaces |= map(select(.type != "mount"))
| .linux.maskedPaths = []
| .linux.readonlyPaths = [] '

runc run -d --console-socket "$CONSOLE_SOCKET" test_host_mnt
[ "$status" -eq 0 ]

runc state test_host_mnt
[ "$status" -eq 0 ]
[[ "$output" == *"running"* ]]

# Verify the rootfs is a mount point on the host.
ROOTFS_DIR="$PWD/rootfs"
mountpoint -q "$ROOTFS_DIR"
[ "$status" -eq 0 ]

runc kill test_host_mnt KILL
runc delete test_host_mnt
[ "$status" -eq 0 ]

# Verify the mount is gone.
run mountpoint -q "$ROOTFS_DIR"
[ "$status" -ne 0 ]
}
Loading