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 <pholzing@redhat.com>
This commit is contained in:
Paul Holzinger
2024-09-20 13:19:17 +02:00
parent f6bda786ed
commit 792796183f
2 changed files with 20 additions and 28 deletions

View File

@ -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()
nsPath, err := netns.NewNSFrom(nsProcess)
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)
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)

View File

@ -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
}