From: Christian Brauner <brauner@kernel.org>
To: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Linus Torvalds <torvalds@linuxfoundation.org>,
Andrii Nakryiko <andrii@kernel.org>,
bpf@vger.kernel.org, netdev@vger.kernel.org, paul@paul-moore.com,
linux-fsdevel@vger.kernel.org,
linux-security-module@vger.kernel.org, kernel-team@meta.com
Subject: Re: [PATCH bpf-next 03/29] bpf: introduce BPF token object
Date: Tue, 16 Jan 2024 17:37:39 +0100 [thread overview]
Message-ID: <20240116-gradmesser-labeln-9a1d9918c92e@brauner> (raw)
In-Reply-To: <CAEf4BzYNRNbaNNGRSUCaY3OQrzXPAdR6gGB0PmXhwsn8rUAs0Q@mail.gmail.com>
On Sat, Jan 13, 2024 at 06:29:33PM -0800, Andrii Nakryiko wrote:
> On Fri, Jan 12, 2024 at 11:17 AM Christian Brauner <brauner@kernel.org> wrote:
> >
> > > > My point is that the capable logic will walk upwards the user namespace
> > > > hierarchy from the token->userns until the user namespace of the caller
> > > > and terminate when it reached the init_user_ns.
> > > >
> > > > A caller is located in some namespace at the point where they call this
> > > > function. They provided a token. The caller isn't capable in the
> > > > namespace of the token so the function falls back to init_user_ns. Two
> > > > interesting cases:
> > > >
> > > > (1) The caller wasn't in an ancestor userns of the token. If that's the
> > > > case then it follows that the caller also wasn't in the init_user_ns
> > > > because the init_user_ns is a descendant of all other user
> > > > namespaces. So falling back will fail.
> > >
> > > agreed
> > >
> > > >
> > > > (2) The caller was in the same or an ancestor user namespace of the
> > > > token but didn't have the capability in that user namespace:
> > > >
> > > > (i) They were in a non-init_user_ns. Therefore they can't be
> > > > privileged in init_user_ns.
> > > > (ii) They were in init_user_ns. Therefore, they lacked privileges in
> > > > the init_user_ns.
> > > >
> > > > In both cases your fallback will do nothing iiuc.
> > >
> > > agreed as well
> > >
> > > And I agree in general that there isn't a *practically useful* case
> > > where this would matter much. But there is still (at least one) case
> > > where there could be a regression: if token is created in
> > > init_user_ns, caller has CAP_BPF in init_user_ns, caller passes that
> > > token to BPF_PROG_LOAD, and LSM policy rejects that token in
> > > security_bpf_token_capable(). Without the above implementation such
> > > operation will be rejected, even though if there was no token passed
> > > it would succeed. With my implementation above it will succeed as
> > > expected.
> >
> > If that's the case then prevent the creation of tokens in the
> > init_user_ns and be done with it. If you fallback anyway then this is
> > the correct solution.
> >
> > Make this change, please. I'm not willing to support this weird fallback
> > stuff which is even hard to reason about.
>
> Alright, added an extra check. Ok, so in summary I have the changes
> below compared to v1 (plus a few extra LSM-related test cases added):
>
> diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c
> index a86fccd57e2d..7d04378560fd 100644
> --- a/kernel/bpf/token.c
> +++ b/kernel/bpf/token.c
> @@ -9,18 +9,22 @@
> #include <linux/user_namespace.h>
> #include <linux/security.h>
>
> +static bool bpf_ns_capable(struct user_namespace *ns, int cap)
> +{
> + return ns_capable(ns, cap) || (cap != CAP_SYS_ADMIN &&
> ns_capable(ns, CAP_SYS_ADMIN));
> +}
> +
> bool bpf_token_capable(const struct bpf_token *token, int cap)
> {
> - /* BPF token allows ns_capable() level of capabilities, but only if
> - * token's userns is *exactly* the same as current user's userns
> - */
> - if (token && current_user_ns() == token->userns) {
> - if (ns_capable(token->userns, cap) ||
> - (cap != CAP_SYS_ADMIN && ns_capable(token->userns,
> CAP_SYS_ADMIN)))
> - return security_bpf_token_capable(token, cap) == 0;
> - }
> - /* otherwise fallback to capable() checks */
> - return capable(cap) || (cap != CAP_SYS_ADMIN && capable(CAP_SYS_ADMIN));
> + struct user_namespace *userns;
> +
> + /* BPF token allows ns_capable() level of capabilities */
> + userns = token ? token->userns : &init_user_ns;
> + if (!bpf_ns_capable(userns, cap))
> + return false;
> + if (token && security_bpf_token_capable(token, cap) < 0)
> + return false;
> + return true;
> }
>
> void bpf_token_inc(struct bpf_token *token)
> @@ -32,7 +36,7 @@ static void bpf_token_free(struct bpf_token *token)
> {
> security_bpf_token_free(token);
> put_user_ns(token->userns);
> - kvfree(token);
> + kfree(token);
> }
>
> static void bpf_token_put_deferred(struct work_struct *work)
> @@ -152,6 +156,12 @@ int bpf_token_create(union bpf_attr *attr)
> goto out_path;
> }
>
> + /* Creating BPF token in init_user_ns doesn't make much sense. */
> + if (current_user_ns() == &init_user_ns) {
> + err = -EOPNOTSUPP;
> + goto out_path;
> + }
> +
> mnt_opts = path.dentry->d_sb->s_fs_info;
> if (mnt_opts->delegate_cmds == 0 &&
> mnt_opts->delegate_maps == 0 &&
> @@ -179,7 +189,7 @@ int bpf_token_create(union bpf_attr *attr)
> goto out_path;
> }
>
> - token = kvzalloc(sizeof(*token), GFP_USER);
> + token = kzalloc(sizeof(*token), GFP_USER);
> if (!token) {
> err = -ENOMEM;
> goto out_file;
Thank you! Looks good,
Acked-by: Christian Brauner <brauner@kernel.org>
next prev parent reply other threads:[~2024-01-16 16:37 UTC|newest]
Thread overview: 59+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-03 22:20 [PATCH bpf-next 00/29] BPF token Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 01/29] bpf: align CAP_NET_ADMIN checks with bpf_capable() approach Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 02/29] bpf: add BPF token delegation mount options to BPF FS Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 03/29] bpf: introduce BPF token object Andrii Nakryiko
2024-01-05 20:25 ` Linus Torvalds
2024-01-05 20:32 ` Matthew Wilcox
2024-01-05 20:45 ` Linus Torvalds
2024-01-05 22:06 ` Andrii Nakryiko
2024-01-05 22:05 ` Andrii Nakryiko
2024-01-05 22:27 ` Alexei Starovoitov
2024-01-05 21:45 ` Linus Torvalds
2024-01-05 22:18 ` Andrii Nakryiko
2024-01-08 12:02 ` Christian Brauner
2024-01-08 23:58 ` Andrii Nakryiko
2024-01-09 14:52 ` Christian Brauner
2024-01-09 19:00 ` Andrii Nakryiko
2024-01-10 14:59 ` Christian Brauner
2024-01-11 0:42 ` Andrii Nakryiko
2024-01-11 10:38 ` Christian Brauner
2024-01-11 17:41 ` Andrii Nakryiko
2024-01-12 7:58 ` Christian Brauner
2024-01-12 18:32 ` Andrii Nakryiko
2024-01-12 19:16 ` Christian Brauner
2024-01-14 2:29 ` Andrii Nakryiko
2024-01-16 16:37 ` Christian Brauner [this message]
2024-01-08 12:01 ` Christian Brauner
2024-01-08 16:45 ` Paul Moore
2024-01-09 0:07 ` Andrii Nakryiko
2024-01-10 19:29 ` Paul Moore
2024-01-08 11:44 ` Christian Brauner
2024-01-03 22:20 ` [PATCH bpf-next 04/29] bpf: add BPF token support to BPF_MAP_CREATE command Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 05/29] bpf: add BPF token support to BPF_BTF_LOAD command Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 06/29] bpf: add BPF token support to BPF_PROG_LOAD command Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 07/29] bpf: take into account BPF token when fetching helper protos Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 08/29] bpf: consistently use BPF token throughout BPF verifier logic Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 09/29] bpf,lsm: refactor bpf_prog_alloc/bpf_prog_free LSM hooks Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 10/29] bpf,lsm: refactor bpf_map_alloc/bpf_map_free " Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 11/29] bpf,lsm: add BPF token " Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 12/29] libbpf: add bpf_token_create() API Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 13/29] libbpf: add BPF token support to bpf_map_create() API Andrii Nakryiko
2024-01-04 19:04 ` Linus Torvalds
2024-01-04 19:23 ` Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 14/29] libbpf: add BPF token support to bpf_btf_load() API Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 15/29] libbpf: add BPF token support to bpf_prog_load() API Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 16/29] selftests/bpf: add BPF token-enabled tests Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 17/29] bpf,selinux: allocate bpf_security_struct per BPF token Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 18/29] bpf: fail BPF_TOKEN_CREATE if no delegation option was set on BPF FS Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 19/29] bpf: support symbolic BPF FS delegation mount options Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 20/29] selftests/bpf: utilize string values for delegate_xxx " Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 21/29] libbpf: split feature detectors definitions from cached results Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 22/29] libbpf: further decouple feature checking logic from bpf_object Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 23/29] libbpf: move feature detection code into its own file Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 24/29] libbpf: wire up token_fd into feature probing logic Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 25/29] libbpf: wire up BPF token support at BPF object level Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 26/29] selftests/bpf: add BPF object loading tests with explicit token passing Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 27/29] selftests/bpf: add tests for BPF object load with implicit token Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 28/29] libbpf: support BPF token path setting through LIBBPF_BPF_TOKEN_PATH envvar Andrii Nakryiko
2024-01-03 22:20 ` [PATCH bpf-next 29/29] selftests/bpf: add tests for " Andrii Nakryiko
2024-01-03 23:49 ` [PATCH bpf-next 00/29] BPF token Jakub Kicinski
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=20240116-gradmesser-labeln-9a1d9918c92e@brauner \
--to=brauner@kernel.org \
--cc=andrii.nakryiko@gmail.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=kernel-team@meta.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=paul@paul-moore.com \
--cc=torvalds@linuxfoundation.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;
as well as URLs for NNTP newsgroup(s).