Re: [PATCH 0/8] userns: per-namespace capability bounding set and opt-in netns loopback
flat view
From: Alexey Gladkov <legion@kernel.org>
Date: 2026-10-29 10:45:02
Also in:
linux-api, linux-doc, linux-fsdevel, linux-kselftest, linux-security-module, lkml
On Wed, Oct 28, 2026 at 03:56:11PM -0700, Andy Lutomirski wrote:
On Wed, Oct 28, 2026 at 3:18 PM Hallgrimur H. Gunnarsson [off-list ref] wrote:quoted
When an unprivileged process creates a new user namespace, it is granted a full set of capabilities (CAP_FULL_SET) scoped to that namespace. While these capabilities are isolated to the namespace, they allow unprivileged local users to reach deep kernel subsystems (most notably networking configuration and raw sockets via CAP_NET_ADMIN and CAP_NET_RAW) that historically assumed a trusted caller and have accounted for a large share of local privilege escalation vulnerabilities. Many workloads and sandboxes use unprivileged user namespaces strictly for basic UID/GID, mount, PID, or network isolation and never need high-risk capabilities like CAP_NET_ADMIN or CAP_NET_RAW. Likewise, system administrators often want a host-wide policy ceiling restricting which capabilities unprivileged user namespaces may acquire, without disabling unprivileged user namespaces altogether. Prior work by Jonathan Calmels [1] proposed addressing this via a sixth per-thread capability set (cap_userns) alongside a global sysctl mask. During that discussion [1, 2], feedback (e.g. from Casey Schaufler) suggested that rather than adding another per-thread capability set and prctl() interface, capability restrictions could be integrated directly into struct user_namespace and configured via clone3(). At the same time, as noted in [1], a clone3() flag alone is not sufficient for administrators who need to enforce a host-wide ceiling on unprivileged user namespaces without modifying every userspace callsite. This series combines both pieces of feedback: it embeds a capability bounding set (cap_bset) directly into struct user_namespace, reusing the existing task cap_bset, cap_permitted, and cap_effective sets on namespace entry, and provides both a system-wide sysctl ceiling for unprivileged user namespaces and a CLONE_NEWUSER_BSET flag for voluntary per-namespace restriction via clone3().Why should the task's cap masks affect this? *Maybe* cap_bset makes sense, but I'm struggling a bit to see why cap_permitted and cap_effective should matter. Also, I think that Docker in non-userns mode restricts cap_bset, and the purpose of that restriction is rather at odds with interpreting it as a restriction on newly created user namespaces for purposes of vulnerability mitigation.quoted
In addition, because restricting CAP_NET_ADMIN at user namespace creation time prevents userspace from bringing up the loopback interface in new network namespaces, the series first introduces an opt-in flag to automatically enable loopback on network namespace creation: 1. Opt-in loopback activation on netns creation (Patch 1) New network namespaces start with the loopback interface (lo) DOWN by default, requiring CAP_NET_ADMIN over the owning user namespace to bring it up. To block external network access while preserving localhost networking, sandboxes commonly create an isolated network namespace with only the loopback interface enabled.The whole unshare/clone flag situation is getting out of hand, IMO. And this new thing makes logical sense but is really about reducing exposure. Perhaps we should instead have a small list associated with a userns (extensible in the future) of things that the ns's admin (i.e. whoever has CAP_SYS_ADMIN relative to the ns) may do. That list could include: - Create loopback with sensible defaults for ipv4 and/or ipv6 (i see no obvious reason to separate them) - Create tun/tap interfaces in that ns (and attach them, etc) And add a very simple new API to do these things. Actually, the tun/tap could just use the normal mechanism. Thoughts?
I think that's an interesting idea. I also think the whole flag issue is moving in the wrong direction. Are you thinking of something like `struct open_how` in openat2, or something else? -- Rgrds, legion