Linux Security Modules development
 help / color / mirror / Atom feed
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

      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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox