From ac501d4b7c323120ff11b6754789d6bef43302fe Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Wed, 1 Jul 2026 18:40:53 +0200 Subject: [PATCH 1/3] rpm: update broken rootless storage.conf mount option A rootless user cannot use metacopy=on, doing so will work but the kernel then throws a error in demsg and we use the wrong options. This was reported on arch but the same problem is in the rpm spec: https://gitlab.archlinux.org/archlinux/packaging/packages/containers-common/-/work_items/12 Signed-off-by: Paul Holzinger (cherry picked from commit 8dcedbee5bd9752cd5fe6881bd1909141e905f78) Signed-off-by: Paul Holzinger --- common/rpm/00-storage-additional-store.conf | 2 -- common/rpm/00-storage-rootful.conf | 6 ++++++ common/rpm/00-storage-rootless.conf | 4 ++++ common/rpm/00-storage.conf | 4 ---- common/rpm/containers-common.spec | 7 +++++-- 5 files changed, 15 insertions(+), 8 deletions(-) delete mode 100644 common/rpm/00-storage-additional-store.conf create mode 100644 common/rpm/00-storage-rootful.conf create mode 100644 common/rpm/00-storage-rootless.conf diff --git a/common/rpm/00-storage-additional-store.conf b/common/rpm/00-storage-additional-store.conf deleted file mode 100644 index 8bb671127b..0000000000 --- a/common/rpm/00-storage-additional-store.conf +++ /dev/null @@ -1,2 +0,0 @@ -[storage.options] -additionalimagestores = ["/usr/lib/containers/storage"] diff --git a/common/rpm/00-storage-rootful.conf b/common/rpm/00-storage-rootful.conf new file mode 100644 index 0000000000..f49f57b8ae --- /dev/null +++ b/common/rpm/00-storage-rootful.conf @@ -0,0 +1,6 @@ +[storage.options] +additionalimagestores = ["/usr/lib/containers/storage"] + +[storage.options.overlay] +# mountopt specifies comma separated list of extra mount options +mountopt = "nodev,metacopy=on" diff --git a/common/rpm/00-storage-rootless.conf b/common/rpm/00-storage-rootless.conf new file mode 100644 index 0000000000..d9ffb01dbd --- /dev/null +++ b/common/rpm/00-storage-rootless.conf @@ -0,0 +1,4 @@ +[storage.options.overlay] +# mountopt specifies comma separated list of extra mount options +# Note unlike the rootful config we cannot use metacopy=on as rootless user +mountopt = "nodev" diff --git a/common/rpm/00-storage.conf b/common/rpm/00-storage.conf index 2574bcd794..2f4bc14857 100644 --- a/common/rpm/00-storage.conf +++ b/common/rpm/00-storage.conf @@ -1,6 +1,2 @@ [storage] driver = "overlay" - -[storage.options.overlay] -# mountopt specifies comma separated list of extra mount options -mountopt = "nodev,metacopy=on" diff --git a/common/rpm/containers-common.spec b/common/rpm/containers-common.spec index 277999447f..32890f9d8e 100644 --- a/common/rpm/containers-common.spec +++ b/common/rpm/containers-common.spec @@ -114,7 +114,8 @@ install -Dp -m0644 storage/storage.conf %{buildroot}%{_datadir}/containers/stora # install custom vendor overwrites install -Dp -m0644 common/rpm/00-containers.conf %{buildroot}%{_datadir}/containers/containers.conf.d/00-vendor.conf install -Dp -m0644 common/rpm/00-storage.conf %{buildroot}%{_datadir}/containers/storage.conf.d/00-vendor.conf -install -Dp -m0644 common/rpm/00-storage-additional-store.conf %{buildroot}%{_datadir}/containers/storage.rootful.conf.d/00-vendor-additional-store.conf +install -Dp -m0644 common/rpm/00-storage-rootful.conf %{buildroot}%{_datadir}/containers/storage.rootful.conf.d/00-vendor-rootful.conf +install -Dp -m0644 common/rpm/00-storage-rootless.conf %{buildroot}%{_datadir}/containers/storage.rootless.conf.d/00-vendor-rootless.conf %if %{defined fedora} install -Dp -m0644 common/rpm/00-fedora-registries.conf %{buildroot}%{_datadir}/containers/registries.conf.d/00-vendor.conf @@ -216,7 +217,9 @@ ln -s ../../../..%{_sysconfdir}/yum.repos.d/redhat.repo %{buildroot}%{_datadir}/ %dir %{_datadir}/containers/storage.conf.d %{_datadir}/containers/storage.conf.d/00-vendor.conf %dir %{_datadir}/containers/storage.rootful.conf.d -%{_datadir}/containers/storage.rootful.conf.d/00-vendor-additional-store.conf +%{_datadir}/containers/storage.rootful.conf.d/00-vendor-rootful.conf +%dir %{_datadir}/containers/storage.rootless.conf.d +%{_datadir}/containers/storage.rootless.conf.d/00-vendor-rootless.conf %dir %{_datadir}/rhel %dir %{_datadir}/rhel/secrets %{_datadir}/rhel/secrets/* From d98f0953707177010c7bd363e7e856be23f77ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Rod=C3=A1k?= Date: Mon, 29 Jun 2026 17:49:34 +0200 Subject: [PATCH 2/3] Move PestoSocketPath to ContainerNetwork interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compute the path directly from the netns directory instead of serializing it in RootlessNetnsInfo. Fixes pesto --delete being skipped when the info cache was not yet loaded. Signed-off-by: Jan Rodák (cherry picked from commit 90e83403372ba5257f0e9779001d5e7f425792a3) Signed-off-by: Paul Holzinger --- .../internal/rootlessnetns/netns_freebsd.go | 4 ++++ .../internal/rootlessnetns/netns_linux.go | 16 +++++++++------- common/libnetwork/netavark/run.go | 8 ++++++++ common/libnetwork/types/network.go | 7 ++++--- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/common/libnetwork/internal/rootlessnetns/netns_freebsd.go b/common/libnetwork/internal/rootlessnetns/netns_freebsd.go index f1ae4bb00c..49332f453b 100644 --- a/common/libnetwork/internal/rootlessnetns/netns_freebsd.go +++ b/common/libnetwork/internal/rootlessnetns/netns_freebsd.go @@ -31,3 +31,7 @@ func (n *Netns) Run(lock *lockfile.LockFile, toRun func() error) error { func (n *Netns) Info() *types.RootlessNetnsInfo { return &types.RootlessNetnsInfo{} } + +func (n *Netns) PestoSocketPath() string { + return "" +} diff --git a/common/libnetwork/internal/rootlessnetns/netns_linux.go b/common/libnetwork/internal/rootlessnetns/netns_linux.go index c11dc07d7c..750cb3810f 100644 --- a/common/libnetwork/internal/rootlessnetns/netns_linux.go +++ b/common/libnetwork/internal/rootlessnetns/netns_linux.go @@ -205,10 +205,8 @@ func (n *Netns) setupPasta(nsPath string) error { extraOpts := []string{"--pid", pidPath} - var socketPath string if n.config.Network.RootlessPortForwarder == config.RootlessPortForwarderPasta { - socketPath = n.getPath(pestoSocketFile) - extraOpts = append(extraOpts, "-c", socketPath) + extraOpts = append(extraOpts, "-c", n.getPath(pestoSocketFile)) } pastaOpts := pasta.SetupOptions{ @@ -248,10 +246,9 @@ func (n *Netns) setupPasta(nsPath string) error { } n.info = &types.RootlessNetnsInfo{ - IPAddresses: res.IPAddresses, - DnsForwardIps: res.DNSForwardIPs, - MapGuestIps: res.MapGuestAddrIPs, - PestoSocketPath: socketPath, + IPAddresses: res.IPAddresses, + DnsForwardIps: res.DNSForwardIPs, + MapGuestIps: res.MapGuestAddrIPs, } if err := n.serializeInfo(); err != nil { return wrapError("serialize info", err) @@ -632,6 +629,11 @@ func (n *Netns) Info() *types.RootlessNetnsInfo { return n.info } +// PestoSocketPath returns the path to the pesto control socket. +func (n *Netns) PestoSocketPath() string { + return n.getPath(pestoSocketFile) +} + func refCount(dir string, inc int) (int, error) { file := filepath.Join(dir, refCountFile) content, err := os.ReadFile(file) diff --git a/common/libnetwork/netavark/run.go b/common/libnetwork/netavark/run.go index 0a385edc5d..dc1e8ed37a 100644 --- a/common/libnetwork/netavark/run.go +++ b/common/libnetwork/netavark/run.go @@ -215,3 +215,11 @@ func (n *netavarkNetwork) RootlessNetnsInfo() (*types.RootlessNetnsInfo, error) } return n.rootlessNetns.Info(), nil } + +func (n *netavarkNetwork) PestoSocketPath() string { + if n.rootlessNetns == nil { + logrus.Debug("PestoSocketPath: rootlessNetns is nil") + return "" + } + return n.rootlessNetns.PestoSocketPath() +} diff --git a/common/libnetwork/types/network.go b/common/libnetwork/types/network.go index 85159bad2b..21260f1059 100644 --- a/common/libnetwork/types/network.go +++ b/common/libnetwork/types/network.go @@ -36,6 +36,10 @@ type ContainerNetwork interface { // Only used as rootless and should return an error as root. RootlessNetnsInfo() (*RootlessNetnsInfo, error) + // PestoSocketPath returns the path to the pesto control socket + // for dynamic port forwarding. Empty when not available. + PestoSocketPath() string + // Drivers will return the list of supported network drivers // for this interface. Drivers() []string @@ -377,9 +381,6 @@ type RootlessNetnsInfo struct { DnsForwardIps []string // MapGuestIps should be used for the host.containers.internal entry when set MapGuestIps []string - // PestoSocketPath is the path to the pasta control socket for dynamic - // port forwarding via pesto. Empty when pasta was started without -c. - PestoSocketPath string } // FilterFunc can be passed to NetworkList to filter the networks. From b03aaf0c8ff00557cd270bc7cedb9c9324c8ed2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Rod=C3=A1k?= Date: Tue, 30 Jun 2026 16:34:51 +0200 Subject: [PATCH 3/3] Document that rootless_port_forwarder requires no running containers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Rodák (cherry picked from commit d41da3a7ebef92966b9006b2f58dfdb05f1e3d03) Signed-off-by: Paul Holzinger --- common/docs/containers.conf.5.md | 4 ++++ common/pkg/config/config.go | 4 ++++ common/pkg/config/containers.conf | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/common/docs/containers.conf.5.md b/common/docs/containers.conf.5.md index 52308be2b0..2041c12bb5 100644 --- a/common/docs/containers.conf.5.md +++ b/common/docs/containers.conf.5.md @@ -496,6 +496,10 @@ Valid options are `rootlessport` (default) and `pasta`. which preserves the original source IP address inside the container. The `pasta` option is **experimental** and subject to change. +**Important:** This option must only be changed when no containers are running. +Switching while containers are active leads to port-forwarding rules being leaked +or cleanup failures because the running netns was created with the previous setting. + **network_config_dir**="/etc/containers/networks" Path to the directory where network configuration files are located. diff --git a/common/pkg/config/config.go b/common/pkg/config/config.go index e53dcce63b..22d161e27f 100644 --- a/common/pkg/config/config.go +++ b/common/pkg/config/config.go @@ -635,6 +635,10 @@ type NetworkConfig struct { // bridge networks. Valid values are RootlessPortForwarderRootlessport // (default, userspace TCP/UDP proxy) and RootlessPortForwarderPasta // (experimental, pasta's kernel splice preserving the original source IP). + // + // Must only be changed when no containers are running. Switching while + // containers are active leads to leaked port-forwarding rules or cleanup + // failures. RootlessPortForwarder string `toml:"rootless_port_forwarder,omitempty"` } diff --git a/common/pkg/config/containers.conf b/common/pkg/config/containers.conf index 1725909fc7..7f52238178 100644 --- a/common/pkg/config/containers.conf +++ b/common/pkg/config/containers.conf @@ -416,6 +416,11 @@ default_sysctls = [ # via kernel splice, which preserves the original source IP address inside the # container. This option is experimental and subject to change. # +# Important: This option must only be changed when no containers are running. +# Switching while containers are active leads to port-forwarding rules being +# leaked or cleanup failures because the running netns was created with the +# previous setting. +# #rootless_port_forwarder = "rootlessport" # Path to the directory where network configuration files are located.