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.
8081func 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