Skip to content

Commit

Permalink
libpod: setupNetNS() correctly mount netns
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Luap99 committed Sep 20, 2024
1 parent f6bda78 commit 7927961
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 28 deletions.
29 changes: 1 addition & 28 deletions libpod/networking_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -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)

Expand Down
19 changes: 19 additions & 0 deletions test/system/550-pause-process.bats
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit 7927961

Please sign in to comment.