bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: KP Singh <kpsingh@chromium.org>
To: Casey Schaufler <casey@schaufler-ca.com>
Cc: LKML <linux-kernel@vger.kernel.org>,
	Linux Security Module list 
	<linux-security-module@vger.kernel.org>,
	bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v3 04/10] bpf: lsm: Add mutable hooks list for the BPF LSM
Date: Thu, 23 Jan 2020 14:24:36 -0800	[thread overview]
Message-ID: <20200123222436.GA1598@chromium.org> (raw)
In-Reply-To: <5004b3f4-ca5b-a546-4e87-b852cc248079@schaufler-ca.com>

On 23-Jan 11:09, Casey Schaufler wrote:
> On 1/23/2020 9:59 AM, KP Singh wrote:
> > On 23-Jan 09:03, Casey Schaufler wrote:
> >> On 1/23/2020 7:24 AM, KP Singh wrote:
> >>> From: KP Singh <kpsingh@google.com>
> >>>
> >>> - The list of hooks registered by an LSM is currently immutable as they
> >>>   are declared with __lsm_ro_after_init and they are attached to a
> >>>   security_hook_heads struct.
> >>> - For the BPF LSM we need to de/register the hooks at runtime. Making
> >>>   the existing security_hook_heads mutable broadens an
> >>>   attack vector, so a separate security_hook_heads is added for only
> >>>   those that ~must~ be mutable.
> >>> - These mutable hooks are run only after all the static hooks have
> >>>   successfully executed.
> >>>
> >>> This is based on the ideas discussed in:
> >>>
> >>>   https://lore.kernel.org/lkml/20180408065916.GA2832@ircssh-2.c.rugged-nimbus-611.internal
> >>>
> >>> Reviewed-by: Brendan Jackman <jackmanb@google.com>
> >>> Reviewed-by: Florent Revest <revest@google.com>
> >>> Reviewed-by: Thomas Garnier <thgarnie@google.com>
> >>> Signed-off-by: KP Singh <kpsingh@google.com>
> >>> ---
> >>>  MAINTAINERS             |  1 +
> >>>  include/linux/bpf_lsm.h | 72 +++++++++++++++++++++++++++++++++++++++++
> >>>  security/bpf/Kconfig    |  1 +
> >>>  security/bpf/Makefile   |  2 +-
> >>>  security/bpf/hooks.c    | 20 ++++++++++++
> >>>  security/bpf/lsm.c      |  7 ++++
> >>>  security/security.c     | 25 +++++++-------
> >>>  7 files changed, 116 insertions(+), 12 deletions(-)
> >>>  create mode 100644 include/linux/bpf_lsm.h
> >>>  create mode 100644 security/bpf/hooks.c
> >>>
> >>> diff --git a/MAINTAINERS b/MAINTAINERS
> >>> index e2b7f76a1a70..c606b3d89992 100644
> >>> --- a/MAINTAINERS
> >>> +++ b/MAINTAINERS
> >>> @@ -3209,6 +3209,7 @@ L:	linux-security-module@vger.kernel.org
> >>>  L:	bpf@vger.kernel.org
> >>>  S:	Maintained
> >>>  F:	security/bpf/
> >>> +F:	include/linux/bpf_lsm.h
> >>>  
> >>>  BROADCOM B44 10/100 ETHERNET DRIVER
> >>>  M:	Michael Chan <michael.chan@broadcom.com>
> >>> diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
> >>> new file mode 100644
> >>> index 000000000000..57c20b2cd2f4
> >>> --- /dev/null
> >>> +++ b/include/linux/bpf_lsm.h
> >>> @@ -0,0 +1,72 @@
> >>> +/* SPDX-License-Identifier: GPL-2.0 */
> >>> +
> >>> +/*
> >>> + * Copyright 2019 Google LLC.
> >>> + */
> >>> +
> >>> +#ifndef _LINUX_BPF_LSM_H
> >>> +#define _LINUX_BPF_LSM_H
> >>> +
> >>> +#include <linux/bpf.h>
> >>> +#include <linux/lsm_hooks.h>
> >>> +
> >>> +#ifdef CONFIG_SECURITY_BPF
> >>> +
> >>> +/* Mutable hooks defined at runtime and executed after all the statically
> >>> + * defined LSM hooks.
> >>> + */
> >>> +extern struct security_hook_heads bpf_lsm_hook_heads;
> >>> +
> >>> +int bpf_lsm_srcu_read_lock(void);
> >>> +void bpf_lsm_srcu_read_unlock(int idx);
> >>> +
> >>> +#define CALL_BPF_LSM_VOID_HOOKS(FUNC, ...)			\
> >>> +	do {							\
> >>> +		struct security_hook_list *P;			\
> >>> +		int _idx;					\
> >>> +								\
> >>> +		if (hlist_empty(&bpf_lsm_hook_heads.FUNC))	\
> >>> +			break;					\
> >>> +								\
> >>> +		_idx = bpf_lsm_srcu_read_lock();		\
> >>> +		hlist_for_each_entry(P, &bpf_lsm_hook_heads.FUNC, list) \
> >>> +			P->hook.FUNC(__VA_ARGS__);		\
> >>> +		bpf_lsm_srcu_read_unlock(_idx);			\
> >>> +	} while (0)
> >>> +
> >>> +#define CALL_BPF_LSM_INT_HOOKS(FUNC, ...) ({			\
> >>> +	int _ret = 0;						\
> >>> +	do {							\
> >>> +		struct security_hook_list *P;			\
> >>> +		int _idx;					\
> >>> +								\
> >>> +		if (hlist_empty(&bpf_lsm_hook_heads.FUNC))	\
> >>> +			break;					\
> >>> +								\
> >>> +		_idx = bpf_lsm_srcu_read_lock();		\
> >>> +								\
> >>> +		hlist_for_each_entry(P,				\
> >>> +			&bpf_lsm_hook_heads.FUNC, list) {	\
> >>> +			_ret = P->hook.FUNC(__VA_ARGS__);		\
> >>> +			if (_ret && IS_ENABLED(CONFIG_SECURITY_BPF_ENFORCE)) \
> >>> +				break;				\
> >>> +		}						\
> >>> +		bpf_lsm_srcu_read_unlock(_idx);			\
> >>> +	} while (0);						\
> >>> +	IS_ENABLED(CONFIG_SECURITY_BPF_ENFORCE) ? _ret : 0;	\
> >>> +})
> >>> +
> >>> +#else /* !CONFIG_SECURITY_BPF */
> >>> +
> >>> +#define CALL_BPF_LSM_INT_HOOKS(FUNC, ...) (0)
> >>> +#define CALL_BPF_LSM_VOID_HOOKS(...)
> >>> +
> >>> +static inline int bpf_lsm_srcu_read_lock(void)
> >>> +{
> >>> +	return 0;
> >>> +}
> >>> +static inline void bpf_lsm_srcu_read_unlock(int idx) {}
> >>> +
> >>> +#endif /* CONFIG_SECURITY_BPF */
> >>> +
> >>> +#endif /* _LINUX_BPF_LSM_H */
> >>> diff --git a/security/bpf/Kconfig b/security/bpf/Kconfig
> >>> index a5f6c67ae526..595e4ad597ae 100644
> >>> --- a/security/bpf/Kconfig
> >>> +++ b/security/bpf/Kconfig
> >>> @@ -6,6 +6,7 @@ config SECURITY_BPF
> >>>  	bool "BPF-based MAC and audit policy"
> >>>  	depends on SECURITY
> >>>  	depends on BPF_SYSCALL
> >>> +	depends on SRCU
> >>>  	help
> >>>  	  This enables instrumentation of the security hooks with
> >>>  	  eBPF programs.
> >>> diff --git a/security/bpf/Makefile b/security/bpf/Makefile
> >>> index c78a8a056e7e..c526927c337d 100644
> >>> --- a/security/bpf/Makefile
> >>> +++ b/security/bpf/Makefile
> >>> @@ -2,4 +2,4 @@
> >>>  #
> >>>  # Copyright 2019 Google LLC.
> >>>  
> >>> -obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o
> >>> +obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o hooks.o
> >>> diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
> >>> new file mode 100644
> >>> index 000000000000..b123d9cb4cd4
> >>> --- /dev/null
> >>> +++ b/security/bpf/hooks.c
> >>> @@ -0,0 +1,20 @@
> >>> +// SPDX-License-Identifier: GPL-2.0
> >>> +
> >>> +/*
> >>> + * Copyright 2019 Google LLC.
> >>> + */
> >>> +
> >>> +#include <linux/bpf_lsm.h>
> >>> +#include <linux/srcu.h>
> >>> +
> >>> +DEFINE_STATIC_SRCU(security_hook_srcu);
> >>> +
> >>> +int bpf_lsm_srcu_read_lock(void)
> >>> +{
> >>> +	return srcu_read_lock(&security_hook_srcu);
> >>> +}
> >>> +
> >>> +void bpf_lsm_srcu_read_unlock(int idx)
> >>> +{
> >>> +	return srcu_read_unlock(&security_hook_srcu, idx);
> >>> +}
> >>> diff --git a/security/bpf/lsm.c b/security/bpf/lsm.c
> >>> index dc9ac03c7aa0..a25a068e1781 100644
> >>> --- a/security/bpf/lsm.c
> >>> +++ b/security/bpf/lsm.c
> >>> @@ -4,6 +4,7 @@
> >>>   * Copyright 2019 Google LLC.
> >>>   */
> >>>  
> >>> +#include <linux/bpf_lsm.h>
> >>>  #include <linux/lsm_hooks.h>
> >>>  
> >>>  /* This is only for internal hooks, always statically shipped as part of the
> >>> @@ -12,6 +13,12 @@
> >>>   */
> >>>  static struct security_hook_list bpf_lsm_hooks[] __lsm_ro_after_init = {};
> >>>  
> >>> +/* Security hooks registered dynamically by the BPF LSM and must be accessed
> >>> + * by holding bpf_lsm_srcu_read_lock and bpf_lsm_srcu_read_unlock. The mutable
> >>> + * hooks dynamically allocated by the BPF LSM are appeneded here.
> >>> + */
> >>> +struct security_hook_heads bpf_lsm_hook_heads;
> >>> +
> >>>  static int __init bpf_lsm_init(void)
> >>>  {
> >>>  	security_add_hooks(bpf_lsm_hooks, ARRAY_SIZE(bpf_lsm_hooks), "bpf");
> >>> diff --git a/security/security.c b/security/security.c
> >>> index 30a8aa700557..95a46ca25dcd 100644
> >>> --- a/security/security.c
> >>> +++ b/security/security.c
> >>> @@ -27,6 +27,7 @@
> >>>  #include <linux/backing-dev.h>
> >>>  #include <linux/string.h>
> >>>  #include <linux/msg.h>
> >>> +#include <linux/bpf_lsm.h>
> >>>  #include <net/flow.h>
> >>>  
> >>>  #define MAX_LSM_EVM_XATTR	2
> >>> @@ -657,20 +658,22 @@ static void __init lsm_early_task(struct task_struct *task)
> >>>  								\
> >>>  		hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \
> >>>  			P->hook.FUNC(__VA_ARGS__);		\
> >>> +		CALL_BPF_LSM_VOID_HOOKS(FUNC, __VA_ARGS__);	\
> >> I'm sorry if I wasn't clear on the v2 review.
> >> This does not belong in the infrastructure. You should be
> >> doing all the bpf_lsm hook processing in you module.
> >> bpf_lsm_task_alloc() should loop though all the bpf
> >> task_alloc hooks if they have to be handled differently
> >> from "normal" LSM hooks.
> > The BPF LSM does not define static hooks (the ones registered to
> > security_hook_heads in security.c with __lsm_ro_after_init) for each
> > LSM hook. If it tries to do that one ends with what was in v1:
> >
> >   https://lore.kernel.org/bpf/20191220154208.15895-7-kpsingh@chromium.org
> >
> > This gets quite ugly (security/bpf/hooks.h from v1) and was noted by
> > the BPF maintainers:
> >
> >   https://lore.kernel.org/bpf/20191222012722.gdqhppxpfmqfqbld@ast-mbp.dhcp.thefacebook.com/
> >
> > As I mentioned, some of the ideas we used here are based on:
> >
> >   https://lore.kernel.org/lkml/20180408065916.GA2832@ircssh-2.c.rugged-nimbus-611.internal
> >
> > Which gave each LSM the ability to add mutable hooks at runtime. If
> > you prefer we can make this generic and allow the LSMs to register
> > mutable hooks with the BPF LSM be the only LSM that uses it (and
> > enforce it with a whitelist).
> >
> > Would this generic approach be something you would consider better
> > than just calling the BPF mutable hooks directly?
> 
> What I think makes sense is for the BPF LSM to have a hook
> for each of the interfaces and for that hook to handle the
> mutable list for the interface. If BPF not included there
> will be no mutable hooks. 
> 
> Yes, your v1 got this right.

BPF LSM does provide mutable LSM hooks and it ends up being simpler
to implement/maintain when they are treated as such.

 The other approaches which we have considered are:

- Using macro magic to allocate static hook bodies which call eBPF
  programs as implemented in v1. This entails maintaining a
  separate list of LSM hooks in the BPF LSM which is evident from the
  giant security/bpf/include/hooks.h in:

  https://lore.kernel.org/bpf/20191220154208.15895-7-kpsingh@chromium.org

- Another approach one can think of is to allocate all the trampoline
  images (one page each) at __init and update these images to invoke
  BPF programs when they are attached.

Both these approaches seem to suffer from the downside of doing more
work when it's not really needed (i.e. doing prep work for hooks which
have no eBPF programs attached) and they appear to to mask the fact
that what the BPF LSM provides is actually mutable LSM hooks by
allocating static wrappers around mutable callbacks.

Are there other downsides apart from the fact we have an explicit call
to the mutable hooks in the LSM code? (Note that we want to have these
mutable hooks run after all the static LSM hooks so ordering
would still end up being LSM_ORDER_LAST)

It would be great to hear the maintainers' perspective based on the
trade-offs involved with the different approaches discussed.

We are happy to adapt our approach based on the consensus we reach
here.

- KP

> 
> >
> > - KP
> >
> >>>  	} while (0)
> >>>  
> >>> -#define call_int_hook(FUNC, IRC, ...) ({			\
> >>> -	int RC = IRC;						\
> >>> -	do {							\
> >>> -		struct security_hook_list *P;			\
> >>> -								\
> >>> +#define call_int_hook(FUNC, IRC, ...) ({				\
> >>> +	int RC = IRC;							\
> >>> +	do {								\
> >>> +		struct security_hook_list *P;				\
> >>>  		hlist_for_each_entry(P, &security_hook_heads.FUNC, list) { \
> >>> -			RC = P->hook.FUNC(__VA_ARGS__);		\
> >>> -			if (RC != 0)				\
> >>> -				break;				\
> >>> -		}						\
> >>> -	} while (0);						\
> >>> -	RC;							\
> >>> +			RC = P->hook.FUNC(__VA_ARGS__);			\
> >>> +			if (RC != 0)					\
> >>> +				break;					\
> >>> +		}							\
> >>> +		if (RC == 0)						\
> >>> +			RC = CALL_BPF_LSM_INT_HOOKS(FUNC, __VA_ARGS__);	\
> >>> +	} while (0);							\
> >>> +	RC;								\
> >>>  })
> >>>  
> >>>  /* Security operations */
> 

  reply	other threads:[~2020-01-23 22:24 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-23 15:24 [PATCH bpf-next v3 00/10] MAC and Audit policy using eBPF (KRSI) KP Singh
2020-01-23 15:24 ` [PATCH bpf-next v3 01/10] bpf: btf: Add btf_type_by_name_kind KP Singh
2020-01-23 20:06   ` Andrii Nakryiko
2020-01-24 14:12     ` KP Singh
2020-01-23 15:24 ` [PATCH bpf-next v3 02/10] bpf: lsm: Add a skeleton and config options KP Singh
2020-02-10 23:52   ` Alexei Starovoitov
2020-02-11 12:45     ` KP Singh
2020-01-23 15:24 ` [PATCH bpf-next v3 03/10] bpf: lsm: Introduce types for eBPF based LSM KP Singh
2020-02-10 23:58   ` Alexei Starovoitov
2020-02-11 12:44     ` KP Singh
2020-01-23 15:24 ` [PATCH bpf-next v3 04/10] bpf: lsm: Add mutable hooks list for the BPF LSM KP Singh
2020-01-23 17:03   ` Casey Schaufler
2020-01-23 17:59     ` KP Singh
2020-01-23 19:09       ` Casey Schaufler
2020-01-23 22:24         ` KP Singh [this message]
2020-01-23 23:50           ` Casey Schaufler
2020-01-24  1:25             ` KP Singh
2020-01-24 21:55               ` James Morris
2020-02-11  3:12   ` Alexei Starovoitov
2020-02-11 12:43     ` KP Singh
2020-02-11 17:58       ` Alexei Starovoitov
2020-02-11 18:44         ` BPF LSM and fexit [was: [PATCH bpf-next v3 04/10] bpf: lsm: Add mutable hooks list for the BPF LSM] Jann Horn
2020-02-11 19:09           ` Alexei Starovoitov
2020-02-11 19:36             ` Jann Horn
2020-02-11 20:10               ` Alexei Starovoitov
2020-02-11 20:33                 ` Jann Horn
2020-02-11 21:32                   ` Jann Horn
2020-02-11 21:38                   ` Alexei Starovoitov
2020-02-11 23:26                     ` Alexei Starovoitov
2020-02-12  0:09                       ` Daniel Borkmann
2020-02-12  2:45                         ` Alexei Starovoitov
2020-02-12 13:27                           ` Daniel Borkmann
2020-02-12 16:04                             ` KP Singh
2020-02-12 15:52                           ` Casey Schaufler
2020-02-12 16:26                             ` KP Singh
2020-02-12 18:59                               ` Casey Schaufler
2020-01-23 15:24 ` [PATCH bpf-next v3 05/10] bpf: lsm: BTF API for LSM hooks KP Singh
2020-01-23 15:24 ` [PATCH bpf-next v3 06/10] bpf: lsm: Implement attach, detach and execution KP Singh
2020-01-23 15:24 ` [PATCH bpf-next v3 07/10] bpf: lsm: Make the allocated callback RO+X KP Singh
2020-01-23 15:24 ` [PATCH bpf-next v3 08/10] tools/libbpf: Add support for BPF_PROG_TYPE_LSM KP Singh
2020-01-23 18:00   ` Andrii Nakryiko
2020-01-24 14:16     ` KP Singh
2020-01-23 15:24 ` [PATCH bpf-next v3 09/10] bpf: lsm: Add selftests " KP Singh
2020-01-23 15:24 ` [PATCH bpf-next v3 10/10] bpf: lsm: Add Documentation KP Singh

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=20200123222436.GA1598@chromium.org \
    --to=kpsingh@chromium.org \
    --cc=bpf@vger.kernel.org \
    --cc=casey@schaufler-ca.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.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;
as well as URLs for NNTP newsgroup(s).