Thread (12 messages) 12 messages, 3 authors, 2d ago

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

flat view

From: Hallgrimur H. Gunnarsson <hidden>
Date: 2026-10-29 12:11:08
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.
Sorry, the phrasing here may have been misleading. Just to clarify:
none of the creating task's capability sets (cap_bset, cap_permitted
or cap_effective) are used to restrict the new user namespace.

When I wrote "reusing the existing task cap_bset, cap_permitted and
cap_effective sets on namespace entry", I was contrasting this with
the prior series from 2024 [1], which proposed adding a 6th per-thread
capability set to struct cred.

In this series, when a task creates or enters a user namespace, we
simply initialize its new cred->cap_{bset,permitted,effective} in
that namespace to user_ns->cap_bset instead of CAP_FULL_SET.
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.
When computing the new user namespace's user_ns->cap_bset in
create_user_ns():

1. The creating task's cred->cap_bset and cred->cap_permitted are not
   consulted at all. The base ceiling is inherited from
   parent_ns->cap_bset (which is CAP_FULL_SET in init_user_ns), not from
   the task's cred->cap_bset. So a non-userns Docker container that
   drops bits from its task cap_bset does not restrict newly created
   user namespaces.

2. The creating task's cred->cap_effective never restricts the new
   user namespace, but it is used as an additive exception to the
   unprivileged sysctl ceiling.

   The rationale is that if an admin restricts e.g. CAP_NET_ADMIN in the
   unprivileged sysctl, an unprivileged daemon that already holds
   effective CAP_NET_ADMIN in the parent namespace is allowed to keep
   it when creating a new user namespace. There is no added attack
   surface if the user already had the capability in the parent ns.
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'm not particularly attached to CLONE_NEWNET_LOOPBACK. I'd be happy
with whatever mechanism allows bringing up loopback in a new netns
without granting all of CAP_NET_ADMIN.

The main reason I went for a creation-time flag is that it avoids
needing a separate userspace API call after namespace creation and makes
it simple to get working loopback for sandboxes that want to drop all
capabilities in the new userns from the start, e.g. CLONE_NEWUSER_BSET
with cap_bset = 0.

That said, if maintainers prefer not to spend clone/unshare flags on
this, I'm completely open to an alternative mechanism.

Also worth noting that Patch 1 is orthogonal to the rest of the series.
The capability bounding set changes in Patches 2-4 stand on their own
and Patch 1 just makes restricting CAP_NET_ADMIN more practical for
common sandboxing use cases that rely on localhost networking.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help