From: "Serge E. Hallyn" <serge@hallyn.com>
To: Josef Bacik <josef@toxicpanda.com>
Cc: Paul Moore <paul@paul-moore.com>,
Christian Brauner <brauner@kernel.org>,
James Morris <jmorris@namei.org>,
David Howells <dhowells@redhat.com>,
Jarkko Sakkinen <jarkko@kernel.org>,
"Andrew G. Morgan" <morgan@kernel.org>,
Serge Hallyn <sergeh@kernel.org>,
linux-security-module@vger.kernel.org,
Bradley Morgan <brads@mainlining.org>
Subject: Re: [PATCH v4 0/5] capabilities: close the ways around the CAP_SETFCAP rule for uid 0
Date: Thu, 22 Oct 2026 17:42:05 -0500 [thread overview]
Message-ID: <atqRPZfUUUKzebNU@hallyn.com> (raw)
In-Reply-To: <20261022-b4-setfcap-userns-v4-0-88aa0ffaa08f@toxicpanda.com>
On Thu, Oct 22, 2026 at 06:36:18PM +0000, Josef Bacik wrote:
> v1: https://lore.kernel.org/all/20261006-b4-setfcap-userns-v1-0-f47e7ed66072@toxicpanda.com/
> v2: https://lore.kernel.org/all/20261014-b4-setfcap-userns-v2-0-fac4d19281d7@toxicpanda.com/
> v3: https://lore.kernel.org/all/20261021-b4-setfcap-userns-v3-0-97c7ed4e43e1@toxicpanda.com/
Apologies, but I will likely not be able to look at this closely until the
week after next. When I return, I'll take a close look at the newest
version.
> v3->v4:
> - 4/5: a v2 security.capability xattr skipped the new checks, it was
> written as is whenever the writer had CAP_SETFCAP over the
> filesystem's namespace. It now only does that when the filesystem's
> root user is within reach, and goes through the v3 conversion and its
> checks otherwise (Sashiko).
>
> v2->v3:
> - The setns() check in 2/5 and the ptrace check in 5/5 only apply to
> namespaces that map the root user of an ancestor within the creator's
> CAP_SETFCAP, or that have no uid_map yet. Root users stored through
> an idmapped mount are left to whoever sets up the mount, so a root
> task without CAP_SETFCAP can join an ordinary "0 100000" container
> again (Serge, Christian).
> - 2/5 adds cred_may_setfcap_userns() for those two checks and
> cred_setfcap_reaches() for the uid_map check; nothing outside
> create_user_ns() calls cap_setfcap_level() directly (Serge).
> - Fixed the cap_setfcap_level() kernel-doc, @ns doesn't have to be the
> cred's namespace or below; cap_capable() is compared with != 0
> (Serge).
> - Picked up Bradley's Reviewed-by on 1/5 and 3/5, not on 2/5, which
> changed.
> - Rebased onto current vfs.all.
>
> v1->v2:
> - The state lives on the user namespace now: ns->setfcap_level replaces
> ns->parent_could_setfcap, and cred->setfcap_level is gone (Serge,
> Christian).
> - New 2/5: setns() refuses a task whose CAP_SETFCAP doesn't reach as far
> up as the namespace's setfcap_level. It applies to every user
> namespace, not only to those that map the parent's uid 0, because of
> idmapped mounts (Serge, Christian).
> - 5/5 asks a tracer for what setns() asks for, also when the namespace
> doesn't map an ancestor's root user, again because of idmapped mounts.
> - Dropped "userns: don't let setns() lend the right to map uid 0", the
> setns() check covers it. Its nested case moved into 3/5, which checks
> the opener and the writer.
> - set_cred_user_ns() isn't touched anymore, so the put-before-use in
> userns_install() is gone (Sashiko).
> - Rebased onto current vfs.all.
>
> What it does now:
>
> Every user namespace gets a setfcap_level when it's created, which is
> how far up the creator's CAP_SETFCAP counted. If its tasks can write
> file capabilities for the root user of an ancestor, because the
> namespace maps that root user or can still map it, setns() only lets in
> tasks whose own CAP_SETFCAP reaches that far, and PTRACE_ATTACH asks the
> tracer for the same. The checks on the way to file capabilities then go
> by the namespace instead of the cred: a uid_map write that maps the
> parent's uid 0 (opener and writer), and setting security.capability.
>
> The visible difference from v1 is the setns() restriction. A task
> without CAP_SETFCAP can't join, or attach to tasks in, a namespace that
> maps the root user of an ancestor, such as host uid 0, and was created
> by a task that had it. A task that joins takes on the namespace's
> reach. Containers that don't map host uid 0, unprivileged users and
> anything with CAP_SETFCAP aren't affected.
>
> Testing: the v1 flows plus the setns() and ptrace cases, 41 in all, on
> vfs.all with and without the series. For v4 also the v2 xattr route: a
> task that unshared without CAP_SETFCAP mounts a tmpfs, writes a v2 xattr
> on it, and an overlay mounted from the initial namespace makes a uid
> 1000 user run the file with CAP_SYS_ADMIN. That works without the
> series and with v3, and gets -EPERM with v4. Every flow gives what's
> expected, and the only ones that changed from v2 are the five idmapped
> mount and "0 100000" container cases, which are allowed again. The
> pidfd, namespaces, mount_setattr and ptrace selftests give identical
> results with and without. The TLA+ model, which has no idmapped mounts,
> finds no violation with the narrower checks, and still finds the setns()
> bypass when the check is taken out.
>
> --- Original email (v1) ---
>
> Hello,
>
> Commit db2e718a4798 ("capabilities: require CAP_SETFCAP to map uid 0")
> stops a root task that has given up CAP_SETFCAP from creating a user
> namespace that maps uid 0 and then writing file capabilities in it that
> the initial namespace honours. The check only looks at the task that
> creates the namespace, so if somebody who did have CAP_SETFCAP created
> one, there are still several ways around it:
>
> - setns() into their namespace and write uid_map from inside (patch 2)
> - write "0 0 1" through a uid_map fd that they opened (patch 3)
> - setns() into a namespace of theirs that already maps uid 0 and set
> security.capability there, no map write needed (patch 4)
> - ptrace one of their tasks and have it do any of the above (patch 5)
>
> On an unmodified kernel we took a uid 0 task with CAP_SETFCAP dropped
> from its permitted, effective and bounding sets and, through each of
> these, ended up with a file that a uid 1000 user execs with
> CAP_SYS_ADMIN in its effective set.
>
> Patch 1 adds cred->setfcap_level, which records how far up the
> namespace tree a task's CAP_SETFCAP reached when it entered its
> namespace, and patches 2-5 check it. Patch 4 is the check that closes
> the class, the map patches make the uid 0 map rule mean what
> db2e718a4798 meant it to, and patch 5 keeps ptrace from borrowing what
> the target is entitled to.
>
> This does change behaviour. Everything new is -EPERM:
>
> - a task that entered a namespace without CAP_SETFCAP outside can't map
> uid 0 of the outside or write fscaps for that root user anymore
> - a uid_map fd opened by a task with CAP_SETFCAP can't be used by a
> task without it to map uid 0
> - if a privileged task maps "0 0 1" from the parent for a namespace
> created by a task without CAP_SETFCAP, that namespace can no longer
> write fscaps honoured outside
> - PTRACE_ATTACH and PTRACE_TRACEME fail when the tracer gave up
> CAP_SETFCAP and CAP_SYS_PTRACE, the target didn't, and they share a
> root user
>
> Rootless containers, privileged runtimes writing the map from the
> parent, nested unprivileged namespaces and containers that don't map
> host uid 0 aren't affected. The ptrace check is one compare for
> targets in the initial namespace and in namespaces entered without
> the capability.
>
> Testing: a set of flows run on the base and patched kernels, every
> bypass route above gets -EPERM with the series and the 16 legitimate
> flows behave the same. The capabilities, namespaces, ptrace, pidfd and
> proc selftests give the same results before and after. Thanks,
>
> Josef
>
> ---
> Changes in v4:
> - Link to v3: https://patch.msgid.link/20261021-b4-setfcap-userns-v3-0-97c7ed4e43e1@toxicpanda.com
>
> Changes in v3:
> - Link to v2: https://patch.msgid.link/20261014-b4-setfcap-userns-v2-0-fac4d19281d7@toxicpanda.com
>
> Changes in v2:
> - Link to v1: https://patch.msgid.link/20261006-b4-setfcap-userns-v1-0-f47e7ed66072@toxicpanda.com
>
> ---
> Josef Bacik (5):
> userns: record how far up CAP_SETFCAP reaches
> userns: don't let setns() lend CAP_SETFCAP
> userns: check the opener and the writer before mapping uid 0
> capabilities: limit fscaps to where CAP_SETFCAP reaches
> capabilities: don't let ptrace borrow CAP_SETFCAP
>
> include/linux/capability.h | 7 ++
> include/linux/user_namespace.h | 7 +-
> kernel/user_namespace.c | 37 +++++++--
> security/commoncap.c | 183 +++++++++++++++++++++++++++++++++++++++--
> 4 files changed, 214 insertions(+), 20 deletions(-)
> ---
> base-commit: 2c3ba1f1cb416b81d617b92a24a4bcaa48d574e3
> change-id: 20261006-b4-setfcap-userns-d63185a31ce3
prev parent reply other threads:[~2026-10-22 22:42 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-22 18:36 [PATCH v4 0/5] capabilities: close the ways around the CAP_SETFCAP rule for uid 0 Josef Bacik
2026-10-22 18:36 ` [PATCH v4 1/5] userns: record how far up CAP_SETFCAP reaches Josef Bacik
2026-10-22 18:42 ` sashiko-bot
2026-10-22 18:36 ` [PATCH v4 2/5] userns: don't let setns() lend CAP_SETFCAP Josef Bacik
2026-10-22 18:47 ` sashiko-bot
2026-10-22 18:36 ` [PATCH v4 3/5] userns: check the opener and the writer before mapping uid 0 Josef Bacik
2026-10-22 19:03 ` sashiko-bot
2026-10-22 18:36 ` [PATCH v4 4/5] capabilities: limit fscaps to where CAP_SETFCAP reaches Josef Bacik
2026-10-22 18:59 ` sashiko-bot
2026-10-22 18:36 ` [PATCH v4 5/5] capabilities: don't let ptrace borrow CAP_SETFCAP Josef Bacik
2026-10-22 18:52 ` sashiko-bot
2026-10-22 22:42 ` Serge E. Hallyn [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=atqRPZfUUUKzebNU@hallyn.com \
--to=serge@hallyn.com \
--cc=brads@mainlining.org \
--cc=brauner@kernel.org \
--cc=dhowells@redhat.com \
--cc=jarkko@kernel.org \
--cc=jmorris@namei.org \
--cc=josef@toxicpanda.com \
--cc=linux-security-module@vger.kernel.org \
--cc=morgan@kernel.org \
--cc=paul@paul-moore.com \
--cc=sergeh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.