Re: [PATCH 0/8] userns: per-namespace capability bounding set and opt-in netns loopback

From
Hallgrimur H. Gunnarsson <hidden>
Date
2026-11-10 15:31:36
Also in
linux-api, linux-doc, linux-fsdevel, linux-kselftest, linux-security-module, lkml
Reply to
Andy Lutomirski, 2026-11-07
On Sat, Nov 07, 2026 at 10:47:41AM -0800, Andy Lutomirski wrote:
On Fri, Nov 6, 2026 at 5:13 AM Christian Brauner [off-list ref] wrote:
quoted
On Wed, Oct 28, 2026 at 03:56:11PM -0700, Andy Lutomirski wrote:
quoted
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
We've had this idea in the past and I think it is reasonable. I had
always thought that we should expose a system call to create empty
namespaces ot any type. Usually I'd be excited about that but I think
that point is a bit moot and I'd really like see whether we can turn
cells (or whatever other name) into a first class api.

The problem I have with the patchset as written is that adds a lot of
moving parts. And yes, I find the CLONE_* and UNSHARE_* flags plus
sysctl to be suboptimal as well.

So the TL;DR is that CAP_NET_ADMIN + userns =
CAP_NET_PRIVILEGE_ESCALATION 10+ years later. And this patchset wants to
put it back on a leash.

So why isn't an aggressively stupid solution to this problem to split a
new capability out of CAP_NET_ADMIN so it covers the absolute minimal
set of things that should be allowed instead of doing effectively the
same thing but split over multiple apis?
Because we don't actually have a clean way to make a list of
privileges that are, in theory, harmless but are hazardous from an
attack surface perspective and assign them only to tasks that ought to
have them.
Exactly. Furthermore, even if we split a minimal capability out of
CAP_NET_ADMIN, create_user_ns() still grants CAP_FULL_SET to new
unprivileged user namespaces by default. Without a mechanism to
withhold capabilities that are namespaced in scope but carry high
attack surface risk (like CAP_NET_ADMIN and CAP_NET_RAW) and only
selectively grant them to tasks that really need them, an unprivileged
userns would still receive the full set of capabilities.

Providing that mechanism is the core goal of the per-userns capability
bounding set in this series. Even on its own, without any loopback
changes, it can be configured to prevent unprivileged users from acquiring
CAP_NET_ADMIN and CAP_NET_RAW when creating a new userns + netns, while
still supporting sandboxes that use a completely disconnected netns or
containers whose networking is configured externally.

Finding a solution for loopback simply makes this bounding set more
practical, as it allows us to also support sandboxes that rely on
localhost networking without forcing them to retain full CAP_NET_ADMIN.

With a way to withhold CAP_NET_ADMIN from unprivileged userns, splitting
out a minimal capability (as Christian suggests) is a very appealing way
to handle the allowed subset for loopback, though the main challenge is
defining a scope that justifies a capability bit without re-introducing
LPE risk.

Looking at the CAP_NET_ADMIN LPEs from Google's kernelCTF, most are
concentrated in netfilter and tc, with a smaller number in virtual
interfaces and routing. Simply bringing up loopback at netns init
shouldn't carry any LPE risk, but something like CAP_NET_LOOPBACK_UP
is obviously too specific to warrant a capability bit. Conversely,
broadening it into something like CAP_NET_IFCONFIG (allowing link state,
L3 address and basic route configuration on existing interfaces) might
justify a bit, but even such a basic subset would still re-introduce
some LPE risk (see e.g. CVE-2026-53259 / commit f723ccaff2fb),
although it would drastically reduce the risk by excluding the most
high-risk components.

Furthermore, I think splitting out a smaller CAP_NET_ADMIN would also
run into some practical difficulties when it comes to clean enforcement
in rtnetlink. Currently, rtnetlink_rcv_msg() relies on a coarse
CAP_NET_ADMIN check at the beginning before any complex message parsing
occurs. To support more fine-grained capabilities, we would have to push
these checks much deeper into the stack, spreading security checks
across many locations, which could easily lead to mistakes.

Given this, I was hoping to have a minimal mechanism to just allow
bringing up loopback without going for a new capability bit. Ultimately,
it's a pragmatic judgment call. Maybe something like CAP_NET_IFCONFIG
offers enough value and risk reduction to be worth the trade-off.

Otherwise, if we want to avoid consuming a capability bit just for
loopback, we could also consider other alternatives, e.g. a small nsfs
ioctl on the netns fd (e.g. NS_NET_LOOPBACK_UP). This would align with
Andy's earlier suggestion of adding a "very simple new API" dedicated
to these safely scoped operations.

If we drop CLONE_NEWNET_LOOPBACK / UNSHARE_NEWNET_LOOPBACK from this
series and handle loopback separately, do you think the per-userns
bounding set is a reasonable approach for withholding capabilities
(e.g. CAP_NET_ADMIN and CAP_NET_RAW) from unprivileged userns, or
would you prefer a different mechanism?

I think the single-deep case we were discussing on the other thread
could also be cleanly built on top of this. The per-userns bounding
set provides the underlying enforcement mechanism. How we configure
and trigger that bounding, whether via sysctl and clone3() as proposed
in this series, or via a per-task securebit to handle single-deep
containers in init_user_ns as discussed on the other thread, is a
policy control interface decision that can feed directly into the
same mechanism.

To address the concern about the number of moving parts, I am also
happy to simplify the control interfaces. If we decide a per-task
securebit is the cleanest way to drive this configuration for both
single-deep and nested cases, we could focus on that and drop the
clone3() and sysctl from this series entirely, or only expose whatever
subset you prefer.

Thanks!
Thread (24 messages) 24 messages, 7 authors, last reply 14h ago
Keyboard shortcuts
hback out one level
jnext message in thread / next series-diff position
kprevious message in thread / previous series-diff position
ldrill in
Escclose help / fold thread tree
?toggle this help