From 792796183f92946a6722c084b1ba9e7c602eefd0 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Fri, 20 Sep 2024 13:19:17 +0200 Subject: [PATCH] libpod: setupNetNS() correctly mount netns The netns dir has a special logic to bind mout itself and make itslef shared. This code here didn't which lead to catastrophic bug during netns unmounting as we were unable to unmount the netns as the mount got duplicated and had the wrong parent mount. This caused us to loop forever trying to remove the file. Fixes https://issues.redhat.com/browse/RHEL-59620 Fixes #23685 Signed-off-by: Paul Holzinger --- libpod/networking_linux.go | 29 +---------------------------- test/system/550-pause-process.bats | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index bf9f635987..688985b5ec 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -3,11 +3,8 @@ package libpod import ( - "crypto/rand" "fmt" "net" - "os" - "path/filepath" "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/common/libnetwork/types" @@ -17,7 +14,6 @@ import ( "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" - "golang.org/x/sys/unix" ) // Create and configure a new network namespace for a container @@ -104,33 +100,10 @@ func (r *Runtime) createNetNS(ctr *Container) (n string, q map[string]types.Stat // Configure the network namespace using the container process func (r *Runtime) setupNetNS(ctr *Container) error { nsProcess := fmt.Sprintf("/proc/%d/ns/net", ctr.state.PID) - - b := make([]byte, 16) - - if _, err := rand.Reader.Read(b); err != nil { - return fmt.Errorf("failed to generate random netns name: %w", err) - } - nsPath, err := netns.GetNSRunDir() - if err != nil { - return err - } - nsPath = filepath.Join(nsPath, fmt.Sprintf("netns-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])) - - if err := os.MkdirAll(filepath.Dir(nsPath), 0711); err != nil { - return err - } - - mountPointFd, err := os.Create(nsPath) + nsPath, err := netns.NewNSFrom(nsProcess) if err != nil { return err } - if err := mountPointFd.Close(); err != nil { - return err - } - - if err := unix.Mount(nsProcess, nsPath, "none", unix.MS_BIND, ""); err != nil { - return fmt.Errorf("cannot mount %s: %w", nsPath, err) - } networkStatus, err := r.configureNetNS(ctr, nsPath) diff --git a/test/system/550-pause-process.bats b/test/system/550-pause-process.bats index cd38609306..69da5a1d8b 100644 --- a/test/system/550-pause-process.bats +++ b/test/system/550-pause-process.bats @@ -149,3 +149,22 @@ function _check_pause_process() { run_podman rm -f -t0 $cname1 } + +# regression test for https://issues.redhat.com/browse/RHEL-59620 +@test "rootless userns can unmount netns properly" { + skip_if_not_rootless "pause process is only used as rootless" + skip_if_remote "system migrate not supported via remote" + + # Use podman system migrate to stop the currently running pause process + run_podman system migrate + + # First run a container with a custom userns as this uses different netns setup logic. + local cname=c-$(safename) + run_podman run --userns keep-id --name $cname -d $IMAGE sleep 100 + + # Now run a "normal" container without userns + run_podman run --rm $IMAGE true + + # This used to hang trying to unmount the netns. + run_podman rm -f -t0 $cname +}