From dae525716f7b28cd4a30ac396e2444188ac868f8 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Tue, 2 Apr 2024 14:23:55 +0200 Subject: [PATCH] libnetwork/rootlessnetns: fix netns leak on errors When the netns program fails to configure the netns or we fail for any other reason during the setup we must make sure to remove the netns mount again. Without it the next command sees the existing mount and thinks the netns was setup correctly but than later fails during the custom resolv.conf mount because the resolv.conf source file was never created. For future we should consider adding checks due ensure pasta/slirp4netns is still running when we access the netns to make it more fault tolerant. The reason this is a common problem is that on boot pasta can likely fail if it was started before the networking was fully configured (i.e. no default route). Fixes containers/podman#22168 Signed-off-by: Paul Holzinger --- libnetwork/internal/rootlessnetns/netns_linux.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/libnetwork/internal/rootlessnetns/netns_linux.go b/libnetwork/internal/rootlessnetns/netns_linux.go index 98961935d..7bc0c91d1 100644 --- a/libnetwork/internal/rootlessnetns/netns_linux.go +++ b/libnetwork/internal/rootlessnetns/netns_linux.go @@ -100,7 +100,7 @@ func (n *Netns) getOrCreateNetns() (ns.NetNS, bool, error) { nsPath := n.getPath(rootlessNetnsDir) nsRef, err := ns.GetNS(nsPath) if err == nil { - // TODO check if slirp4netns is alive + // TODO check if pasta/slirp4netns is alive return nsRef, false, nil } logrus.Debugf("Creating rootless network namespace at %q", nsPath) @@ -109,7 +109,7 @@ func (n *Netns) getOrCreateNetns() (ns.NetNS, bool, error) { if err := os.MkdirAll(n.dir, 0o700); err != nil { return nil, false, wrapError("", err) } - netns, err := netns.NewNSAtPath(nsPath) + nsRef, err = netns.NewNSAtPath(nsPath) if err != nil { return nil, false, wrapError("create netns", err) } @@ -121,7 +121,17 @@ func (n *Netns) getOrCreateNetns() (ns.NetNS, bool, error) { default: err = fmt.Errorf("invalid rootless network command %q", n.config.Network.DefaultRootlessNetworkCmd) } - return netns, true, err + // If pasta or slirp4netns fail here we need to get rid of the netns again to not leak it, + // otherwise the next command thinks the netns was successfully setup. + if err != nil { + if nerr := netns.UnmountNS(nsPath); nerr != nil { + logrus.Error(nerr) + } + _ = nsRef.Close() + return nil, false, err + } + + return nsRef, true, nil } func (n *Netns) cleanup() error {