Skip to content

Commit 06a4c4c

Browse files
committed
network: distinguish nested root from rootless user
Signed-off-by: Yuxiang Zhu <vfreex@gmail.com>
1 parent 05e6930 commit 06a4c4c

2 files changed

Lines changed: 36 additions & 5 deletions

File tree

common/libnetwork/netavark/network.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strings"
1212
"time"
1313

14+
"github.com/moby/sys/capability"
1415
"github.com/sirupsen/logrus"
1516
"go.podman.io/common/libnetwork/internal/rootlessnetns"
1617
"go.podman.io/common/libnetwork/internal/util"
@@ -109,6 +110,11 @@ func NewNetworkInterface(conf *InitConfig) (types.ContainerNetwork, error) {
109110
// causes issues as this slower more complicated rootless-netns logic should not be used as root.
110111
val, ok := os.LookupEnv(unshare.UsernsEnvName)
111112
useRootlessNetns := ok && val == "done"
113+
// Preserve rootless netns mode unless UID 0 has the networking capability
114+
// needed to manage rootful netavark bridge state.
115+
if useRootlessNetns && unshare.GetRootlessUID() == 0 && hasCapNetAdmin() {
116+
useRootlessNetns = false
117+
}
112118
if useRootlessNetns {
113119
netns, err = rootlessnetns.New(conf.NetworkRunDir, conf.Config)
114120
if err != nil {
@@ -172,6 +178,17 @@ func NewNetworkInterface(conf *InitConfig) (types.ContainerNetwork, error) {
172178
return n, nil
173179
}
174180

181+
func hasCapNetAdmin() bool {
182+
currentCaps, err := capability.NewPid2(0)
183+
if err != nil {
184+
return false
185+
}
186+
if err = currentCaps.Load(); err != nil {
187+
return false
188+
}
189+
return currentCaps.Get(capability.EFFECTIVE, capability.CAP_NET_ADMIN)
190+
}
191+
175192
var builtinDrivers = []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver, types.IPVLANNetworkDriver}
176193

177194
// Drivers will return the list of supported network drivers

common/libnetwork/network/interface.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"path/filepath"
88

9+
"github.com/moby/sys/capability"
910
"go.podman.io/common/libnetwork/netavark"
1011
"go.podman.io/common/libnetwork/types"
1112
"go.podman.io/common/pkg/config"
@@ -55,10 +56,10 @@ func netavarkBackendFromConf(store storage.Store, conf *config.Config, syslog bo
5556

5657
// We cannot use the runroot for rootful since the network namespace is shared for all
5758
// libpod instances they also have to share the same ipam db.
58-
// For rootless we have our own network namespace per libpod instances,
59+
// For rootless users we have our own network namespace per libpod instances,
5960
// so this is not a problem there.
6061
runDir := netavarkRunDir
61-
if unshare.IsRootless() {
62+
if unshare.IsRootless() && (unshare.GetRootlessUID() != 0 || !hasCapNetAdmin()) {
6263
runDir = filepath.Join(store.RunRoot(), "networks")
6364
}
6465

@@ -78,8 +79,21 @@ func netavarkBackendFromConf(store storage.Store, conf *config.Config, syslog bo
7879
// use the graphroot for rootful since the network namespace is shared for all
7980
// libpod instances.
8081
func getDefaultNetavarkConfigDir(store storage.Store) string {
81-
if !unshare.IsRootless() {
82-
return netavarkConfigDir
82+
// Preserve the existing rootless path layout unless UID 0 has the
83+
// networking capability needed to manage rootful netavark bridge state.
84+
if unshare.IsRootless() && (unshare.GetRootlessUID() != 0 || !hasCapNetAdmin()) {
85+
return filepath.Join(store.GraphRoot(), "networks")
8386
}
84-
return filepath.Join(store.GraphRoot(), "networks")
87+
return netavarkConfigDir
88+
}
89+
90+
func hasCapNetAdmin() bool {
91+
currentCaps, err := capability.NewPid2(0)
92+
if err != nil {
93+
return false
94+
}
95+
if err = currentCaps.Load(); err != nil {
96+
return false
97+
}
98+
return currentCaps.Get(capability.EFFECTIVE, capability.CAP_NET_ADMIN)
8599
}

0 commit comments

Comments
 (0)