Skip to content

network: distinguish nested root from rootless user#932

Open
vfreex wants to merge 1 commit into
podman-container-tools:mainfrom
vfreex:podman-rootful-nested-prereqs
Open

network: distinguish nested root from rootless user#932
vfreex wants to merge 1 commit into
podman-container-tools:mainfrom
vfreex:podman-rootful-nested-prereqs

Conversation

@vfreex

@vfreex vfreex commented Jun 20, 2026

Copy link
Copy Markdown

Dependency support for the main Podman fix: podman-container-tools/podman#28995

Bug report: podman-container-tools/podman#18783

Summary

Network config/runtime path selection should distinguish a real rootless user from UID 0 running inside a nested user namespace. UID 0 in a delegated container environment should continue to use rootful network paths.

This also adds unshare.HasCapNetAdmin(), matching the existing cached HasCapSysAdmin() helper, so callers can check effective CAP_NET_ADMIN without duplicating capability-loading code.

Rationale

Podman's rootful bridge-networking preflight needs to check CAP_NET_ADMIN separately from CAP_SYS_ADMIN. Once this is merged and vendored, the Podman PR can replace its temporary local helper with unshare.HasCapNetAdmin().

For network path selection, the relevant question is whether the original caller was a non-root user. The network path decision now uses unshare.GetRootlessUID() > 0 directly so UID 0 keeps rootful paths, including UID 0 inside a nested user namespace.

Tests

  • GOOS=linux go test -c -o /private/tmp/container-libs-common-network.test ./libnetwork/network from common/
  • GOOS=linux go test -c -o /private/tmp/container-libs-storage-unshare.test ./pkg/unshare from storage/

@Luap99 Luap99 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also does not fix anything for podman-container-tools/podman#18783

Comment thread storage/pkg/unshare/unshare_linux.go Outdated
}

// HasCapNetAdmin returns whether the current process has CAP_NET_ADMIN.
func HasCapNetAdmin() (bool, error) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do not need this, if there is just a single user it should not be put here where we have to commit stable APIs more or less.

But as I said on the Podman PR I do not think it is worth it.

Comment thread common/libnetwork/network/interface.go Outdated
if unshare.IsRootless() {
// Use the original caller UID here: UID 0 in a nested user namespace
// should still use rootful network paths.
if unshare.GetRootlessUID() > 0 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I would agree with this change based on recent config file rework doing this now is to late as this is a breaking change for anyone who already uses podman in such a env, using the per user directories in a userns is not really a problem overall.

@vfreex vfreex force-pushed the podman-rootful-nested-prereqs branch from 297e73d to ffb737a Compare June 23, 2026 12:46
@vfreex

vfreex commented Jun 23, 2026

Copy link
Copy Markdown
Author

Thanks, I updated this to narrow the behavior change.

The PR no longer adds unshare.HasCapNetAdmin() to storage, so there is no new exported/stable storage API.

The network path selection also no longer treats UID 0 in a user namespace as rootful unconditionally. It preserves the existing rootless path layout unless all of these are true:

  • rootless/userns detection is true
  • the original caller UID is 0
  • the current process has CAP_NET_ADMIN

If CAP_NET_ADMIN cannot be read or is not present, the code keeps using the existing rootless graph/run-root network paths.

I also updated the netavark mode decision itself. _CONTAINERS_USERNS_CONFIGURED=done is still preserved as the global Podman/storage userns-reexec marker, but common/libnetwork/netavark no longer interprets it as useRootlessNetns=true for the UID 0 + CAP_NET_ADMIN case. That means common does not create the rootless netns wrapper for this case and passes --rootless=false to netavark, avoiding the rootless aardvark systemd-run --user path.

So the intended behavior is:

  • normal rootless user: unchanged
  • UID 0 in a user namespace without CAP_NET_ADMIN: unchanged
  • UID 0 in an Incus/LXC-style container with delegated CAP_NET_ADMIN: use the shared rootful netavark/aardvark paths and rootful netavark mode so bridge DNS state is not split into rootless per-user directories

I agree this should not be a broad rootless-directory migration. The updated version only switches networking behavior when the environment has the capability required to manage rootful netavark bridge state.

Could you please take another look?

Signed-off-by: Yuxiang Zhu <vfreex@gmail.com>
@vfreex vfreex force-pushed the podman-rootful-nested-prereqs branch from ffb737a to 06a4c4c Compare June 23, 2026 13:56

@Luap99 Luap99 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are re-execed in a user namesapce we have new caps which always have NET_ADMIN there, we cannot just say we have the cap and not use the rootless logic as we no longer own the parent namesapaces.
once we are in the userns we always have to use the rootless logic.

There is really no way to recover this AFAICT. If we are root with SYS_ADMIN but no NET_ADMIN then we cannot even use the rootlessnetns logic as we would need to trigger the rexec logic first but this is all way to far at this point and not possible.

So overall I do not see how this cap check gets us anywhere to fix the LXC issues, either a user has both caps already or they don't and we use rexec, just SYS_ADMIN without NET_ADMIN looks unsupportable so I rather not deal with these speical cases

The users in podman-container-tools/podman#18783 ponly talk about the aardvark-dns problem which is the systemd user session problem and unrelated to having caps so this will not bring us one thing closer to fixing this either. Hence I think we should just close this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

common Related to "common" package storage Related to "storage" package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants