All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrii Nakryiko <andrii.nakryiko@gmail.com>
To: KP Singh <kpsingh@chromium.org>
Cc: "open list" <linux-kernel@vger.kernel.org>,
	bpf <bpf@vger.kernel.org>,
	linux-security-module@vger.kernel.org,
	"Alexei Starovoitov" <ast@kernel.org>,
	"Daniel Borkmann" <daniel@iogearbox.net>,
	"James Morris" <jmorris@namei.org>,
	"Kees Cook" <keescook@chromium.org>,
	"Thomas Garnier" <thgarnie@chromium.org>,
	"Michael Halcrow" <mhalcrow@google.com>,
	"Paul Turner" <pjt@google.com>,
	"Brendan Gregg" <brendan.d.gregg@gmail.com>,
	"Jann Horn" <jannh@google.com>,
	"Matthew Garrett" <mjg59@google.com>,
	"Christian Brauner" <christian@brauner.io>,
	"Mickaël Salaün" <mic@digikod.net>,
	"Florent Revest" <revest@chromium.org>,
	"Brendan Jackman" <jackmanb@chromium.org>,
	"Martin KaFai Lau" <kafai@fb.com>,
	"Song Liu" <songliubraving@fb.com>, "Yonghong Song" <yhs@fb.com>,
	"Serge E. Hallyn" <serge@hallyn.com>,
	"Mauro Carvalho Chehab" <mchehab+samsung@kernel.org>,
	"David S. Miller" <davem@davemloft.net>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Nicolas Ferre" <nicolas.ferre@microchip.com>,
	"Stanislav Fomichev" <sdf@google.com>,
	"Quentin Monnet" <quentin.monnet@netronome.com>,
	"Andrey Ignatov" <rdna@fb.com>, "Joe Stringer" <joe@wand.net.nz>
Subject: Re: [PATCH bpf-next v2 05/10] bpf: lsm: BTF API for LSM hooks
Date: Thu, 16 Jan 2020 16:28:03 -0800	[thread overview]
Message-ID: <CAEf4BzYJy40csmwfBgtD+UZY3X+hjqpQ=NwjUQ-cwy+RPF8VHA@mail.gmail.com> (raw)
In-Reply-To: <20200115171333.28811-6-kpsingh@chromium.org>

On Wed, Jan 15, 2020 at 9:14 AM KP Singh <kpsingh@chromium.org> wrote:
>
> From: KP Singh <kpsingh@google.com>
>
> The BTF API provides information required by the BPF verifier to
> attach eBPF programs to the LSM hooks by using the BTF information of
> two types:
>
> - struct security_hook_heads: This type provides the offset which
>   a new dynamically allocated security hook must be attached to.
> - union security_list_options: This provides the information about the
>   function prototype required by the hook.
>
> When the program is loaded:
>
> - The verifier receives the index of a member in struct
>   security_hook_heads to which a program must be attached as
>   prog->aux->lsm_hook_index. The index is one-based for better
>   verification.
> - bpf_lsm_type_by_index is used to determine the func_proto of
>   the LSM hook and updates prog->aux->attach_func_proto
> - bpf_lsm_head_by_index is used to determine the hlist_head to which
>   the BPF program must be attached.
>
> Signed-off-by: KP Singh <kpsingh@google.com>
> ---
>  include/linux/bpf_lsm.h |  12 +++++
>  security/bpf/Kconfig    |   1 +
>  security/bpf/hooks.c    | 104 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 117 insertions(+)
>
> diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
> index 9883cf25241c..a9b4f7b41c65 100644
> --- a/include/linux/bpf_lsm.h
> +++ b/include/linux/bpf_lsm.h
> @@ -19,6 +19,8 @@ extern struct security_hook_heads bpf_lsm_hook_heads;
>
>  int bpf_lsm_srcu_read_lock(void);
>  void bpf_lsm_srcu_read_unlock(int idx);
> +const struct btf_type *bpf_lsm_type_by_index(struct btf *btf, u32 offset);
> +const struct btf_member *bpf_lsm_head_by_index(struct btf *btf, u32 id);
>
>  #define CALL_BPF_LSM_VOID_HOOKS(FUNC, ...)                     \
>         do {                                                    \
> @@ -65,6 +67,16 @@ static inline int bpf_lsm_srcu_read_lock(void)
>         return 0;
>  }
>  static inline void bpf_lsm_srcu_read_unlock(int idx) {}
> +static inline const struct btf_type *bpf_lsm_type_by_index(
> +       struct btf *btf, u32 index)
> +{
> +       return ERR_PTR(-EOPNOTSUPP);
> +}
> +static inline const struct btf_member *bpf_lsm_head_by_index(
> +       struct btf *btf, u32 id)
> +{
> +       return ERR_PTR(-EOPNOTSUPP);
> +}
>
>  #endif /* CONFIG_SECURITY_BPF */
>
> diff --git a/security/bpf/Kconfig b/security/bpf/Kconfig
> index 595e4ad597ae..9438d899b618 100644
> --- a/security/bpf/Kconfig
> +++ b/security/bpf/Kconfig
> @@ -7,6 +7,7 @@ config SECURITY_BPF
>         depends on SECURITY
>         depends on BPF_SYSCALL
>         depends on SRCU
> +       depends on DEBUG_INFO_BTF
>         help
>           This enables instrumentation of the security hooks with
>           eBPF programs.
> diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
> index b123d9cb4cd4..82725611693d 100644
> --- a/security/bpf/hooks.c
> +++ b/security/bpf/hooks.c
> @@ -5,6 +5,8 @@
>   */
>
>  #include <linux/bpf_lsm.h>
> +#include <linux/bpf.h>
> +#include <linux/btf.h>
>  #include <linux/srcu.h>
>
>  DEFINE_STATIC_SRCU(security_hook_srcu);
> @@ -18,3 +20,105 @@ void bpf_lsm_srcu_read_unlock(int idx)
>  {
>         return srcu_read_unlock(&security_hook_srcu, idx);
>  }
> +
> +static inline int validate_hlist_head(struct btf *btf, u32 type_id)
> +{
> +       s32 hlist_id;
> +
> +       hlist_id = btf_find_by_name_kind(btf, "hlist_head", BTF_KIND_STRUCT);
> +       if (hlist_id < 0 || hlist_id != type_id)
> +               return -EINVAL;

This feels backwards and expensive. You already have type_id you want
to check. Do a quick look up, check type and other attributes, if you
want. There is no need to do linear search for struct named
"hlist_head".

But in reality, you should trust kernel BTF, you already know that you
found correct "security_hook_heads" struct, so its member has to be
hlist_head, no?

> +
> +       return 0;
> +}
> +
> +/* Find the BTF representation of the security_hook_heads member for a member
> + * with a given index in struct security_hook_heads.
> + */
> +const struct btf_member *bpf_lsm_head_by_index(struct btf *btf, u32 index)
> +{
> +       const struct btf_member *member;
> +       const struct btf_type *t;
> +       u32 off, i;
> +       int ret;
> +
> +       t = btf_type_by_name_kind(btf, "security_hook_heads", BTF_KIND_STRUCT);
> +       if (WARN_ON_ONCE(IS_ERR(t)))
> +               return ERR_CAST(t);
> +
> +       for_each_member(i, t, member) {
> +               /* We've found the id requested and need to check the
> +                * the following:
> +                *
> +                * - Is it at a valid alignment for struct hlist_head?
> +                *
> +                * - Is it a valid hlist_head struct?
> +                */
> +               if (index == i) {

Also not efficient. Check index to be < vlen(t), then member =
btf_type_member(t) + index;


> +                       off = btf_member_bit_offset(t, member);
> +                       if (off % 8)
> +                               /* valid c code cannot generate such btf */
> +                               return ERR_PTR(-EINVAL);
> +                       off /= 8;
> +
> +                       if (off % __alignof__(struct hlist_head))
> +                               return ERR_PTR(-EINVAL);
> +
> +                       ret = validate_hlist_head(btf, member->type);
> +                       if (ret < 0)
> +                               return ERR_PTR(ret);
> +
> +                       return member;

This feels a bit over-cautious to double-check this. If
security_hook_heads definition is controlled by kernel sources, then
we could just trust vmlinux BTF?

> +               }
> +       }
> +
> +       return ERR_PTR(-ENOENT);
> +}
> +
> +/* Given an index of a member in security_hook_heads return the
> + * corresponding type for the LSM hook. The members of the union
> + * security_list_options have the same name as the security_hook_heads which
> + * is ensured by the LSM_HOOK_INIT macro defined in include/linux/lsm_hooks.h
> + */
> +const struct btf_type *bpf_lsm_type_by_index(struct btf *btf, u32 index)
> +{
> +       const struct btf_member *member, *hook_head = NULL;
> +       const struct btf_type *t, *hook_type = NULL;
> +       u32 i;
> +
> +       hook_head = bpf_lsm_head_by_index(btf, index);
> +       if (IS_ERR(hook_head))
> +               return ERR_PTR(PTR_ERR(hook_head));
> +
> +       t = btf_type_by_name_kind(btf, "security_list_options", BTF_KIND_UNION);
> +       if (WARN_ON_ONCE(IS_ERR(t)))
> +               return ERR_CAST(t);

btf_type_by_name_kind() is a linear search (at least right now), so it
might be a good idea to cache found type_id's of security_list_options
and security_hook_heads?

> +
> +       for_each_member(i, t, member) {
> +               if (hook_head->name_off == member->name_off) {
> +                       /* There should be only one member with the same name
> +                        * as the LSM hook. This should never really happen
> +                        * and either indicates malformed BTF or someone trying
> +                        * trick the LSM.
> +                        */
> +                       if (WARN_ON(hook_type))
> +                               return ERR_PTR(-EINVAL);
> +
> +                       hook_type = btf_type_by_id(btf, member->type);
> +                       if (unlikely(!hook_type))
> +                               return ERR_PTR(-EINVAL);
> +
> +                       if (!btf_type_is_ptr(hook_type))
> +                               return ERR_PTR(-EINVAL);
> +               }
> +       }
> +
> +       if (!hook_type)
> +               return ERR_PTR(-ENOENT);
> +
> +       t = btf_type_by_id(btf, hook_type->type);
> +       if (unlikely(!t))
> +               return ERR_PTR(-EINVAL);

why not do this inside the loop when you find correct member and not
continue processing all the fields?

> +
> +       return t;
> +}
> --
> 2.20.1
>

  reply	other threads:[~2020-01-17  0:28 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-15 17:13 [PATCH bpf-next v2 00/10] MAC and Audit policy using eBPF (KRSI) KP Singh
2020-01-15 17:13 ` [PATCH bpf-next v2 01/10] bpf: btf: Make some of the API visible outside BTF KP Singh
2020-01-18 12:44   ` kbuild test robot
2020-01-18 12:44     ` kbuild test robot
2020-01-20 11:00     ` KP Singh
2020-01-20 11:00       ` KP Singh
2020-01-15 17:13 ` [PATCH bpf-next v2 02/10] bpf: lsm: Add a skeleton and config options KP Singh
2020-01-16  7:04   ` Casey Schaufler
2020-01-16 12:52     ` KP Singh
2020-01-15 17:13 ` [PATCH bpf-next v2 03/10] bpf: lsm: Introduce types for eBPF based LSM KP Singh
2020-01-15 17:13 ` [PATCH bpf-next v2 04/10] bpf: lsm: Add mutable hooks list for the BPF LSM KP Singh
2020-01-15 17:30   ` Stephen Smalley
2020-01-16  9:48     ` KP Singh
2020-01-16  6:33   ` Casey Schaufler
2020-01-16 10:19     ` KP Singh
2020-01-15 17:13 ` [PATCH bpf-next v2 05/10] bpf: lsm: BTF API for LSM hooks KP Singh
2020-01-17  0:28   ` Andrii Nakryiko [this message]
2020-01-20 11:10     ` KP Singh
2020-01-15 17:13 ` [PATCH bpf-next v2 06/10] bpf: lsm: Implement attach, detach and execution KP Singh
2020-01-15 17:24   ` Greg Kroah-Hartman
2020-01-16  9:45     ` KP Singh
2020-01-15 17:13 ` [PATCH bpf-next v2 07/10] bpf: lsm: Make the allocated callback RO+X KP Singh
2020-01-15 17:13 ` [PATCH bpf-next v2 08/10] tools/libbpf: Add support for BPF_PROG_TYPE_LSM KP Singh
2020-01-15 21:19   ` Andrii Nakryiko
2020-01-15 21:37     ` Andrii Nakryiko
2020-01-16 12:49     ` KP Singh
2020-01-16 17:26       ` KP Singh
2020-01-16 19:10       ` Andrii Nakryiko
2020-01-17 22:16         ` KP Singh
2020-01-15 17:13 ` [PATCH bpf-next v2 09/10] bpf: lsm: Add selftests " KP Singh
2020-01-15 17:13 ` [PATCH bpf-next v2 10/10] bpf: lsm: Add Documentation KP Singh
2020-01-15 22:12 ` [PATCH bpf-next v2 00/10] MAC and Audit policy using eBPF (KRSI) Andrii Nakryiko
2020-01-20 11:12   ` KP Singh
2020-01-16 10:03 ` Brendan Jackman

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='CAEf4BzYJy40csmwfBgtD+UZY3X+hjqpQ=NwjUQ-cwy+RPF8VHA@mail.gmail.com' \
    --to=andrii.nakryiko@gmail.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=brendan.d.gregg@gmail.com \
    --cc=christian@brauner.io \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=jackmanb@chromium.org \
    --cc=jannh@google.com \
    --cc=jmorris@namei.org \
    --cc=joe@wand.net.nz \
    --cc=kafai@fb.com \
    --cc=keescook@chromium.org \
    --cc=kpsingh@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=mchehab+samsung@kernel.org \
    --cc=mhalcrow@google.com \
    --cc=mic@digikod.net \
    --cc=mjg59@google.com \
    --cc=nicolas.ferre@microchip.com \
    --cc=pjt@google.com \
    --cc=quentin.monnet@netronome.com \
    --cc=rdna@fb.com \
    --cc=revest@chromium.org \
    --cc=sdf@google.com \
    --cc=serge@hallyn.com \
    --cc=songliubraving@fb.com \
    --cc=thgarnie@chromium.org \
    --cc=yhs@fb.com \
    /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.