lkml.org 
[lkml]   [2020]   [Jan]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH bpf-next v3 05/10] bpf: lsm: BTF API for LSM hooks
    Date
    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 (using the
    lsm_hook_idx passed by the userspace) to which a new dynamically
    allocated security hook must be attached
    - union security_list_options: This provides the information about the
    function prototype required by the hook

    The type_ids for these types are calculated once during __init as
    bpf_type_by_name_kind does an expensive linear search with string
    compariason. Furthermore, the total number of LSM hooks which can be
    determined from the btf_type_vlen of security_hook_heads is needed (in a
    subsequent patch) to initialize the mutable hooks for the BPF LSM.

    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_idx.
    - bpf_lsm_type_by_idx is used to determine the func_proto of
    the LSM hook and updates prog->aux->attach_func_proto
    - bpf_lsm_head_by_idx is used to determine the hlist_head to which
    the BPF program must be attached.

    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>
    ---
    include/linux/bpf_lsm.h | 12 ++++++
    security/bpf/Kconfig | 1 +
    security/bpf/Makefile | 2 +
    security/bpf/hooks.c | 75 ++++++++++++++++++++++++++++++++++
    security/bpf/include/bpf_lsm.h | 21 ++++++++++
    security/bpf/lsm.c | 35 ++++++++++++++++
    6 files changed, 146 insertions(+)
    create mode 100644 security/bpf/include/bpf_lsm.h

    diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
    index 57c20b2cd2f4..5e61c0736001 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_idx(struct btf *btf, u32 offset);
    +const struct btf_member *bpf_lsm_head_by_idx(struct btf *btf, u32 idx);

    #define CALL_BPF_LSM_VOID_HOOKS(FUNC, ...) \
    do { \
    @@ -66,6 +68,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_idx(
    + struct btf *btf, u32 idx)
    +{
    + return ERR_PTR(-EOPNOTSUPP);
    +}
    +static inline const struct btf_member *bpf_lsm_head_by_idx(
    + struct btf *btf, u32 idx)
    +{
    + 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/Makefile b/security/bpf/Makefile
    index c526927c337d..748b9b7d4bc7 100644
    --- a/security/bpf/Makefile
    +++ b/security/bpf/Makefile
    @@ -3,3 +3,5 @@
    # Copyright 2019 Google LLC.

    obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o hooks.o
    +
    +ccflags-y := -I$(srctree)/security/bpf -I$(srctree)/security/bpf/include
    diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
    index b123d9cb4cd4..e9dc6933b6fa 100644
    --- a/security/bpf/hooks.c
    +++ b/security/bpf/hooks.c
    @@ -5,8 +5,12 @@
    */

    #include <linux/bpf_lsm.h>
    +#include <linux/bpf.h>
    +#include <linux/btf.h>
    #include <linux/srcu.h>

    +#include "bpf_lsm.h"
    +
    DEFINE_STATIC_SRCU(security_hook_srcu);

    int bpf_lsm_srcu_read_lock(void)
    @@ -18,3 +22,74 @@ 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,
    + const struct btf_member *member)
    +{
    + const struct btf_type *t;
    +
    + t = btf_type_by_id(btf, member->type);
    + if (unlikely(!t))
    + return -EINVAL;
    +
    + if (BTF_INFO_KIND(t->info) != BTF_KIND_STRUCT)
    + return -EINVAL;
    +
    + if (t->size != sizeof(struct hlist_head))
    + return -EINVAL;
    +
    + 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_idx(struct btf *btf, u32 idx)
    +{
    + const struct btf_member *member;
    + int ret;
    +
    + if (idx >= btf_type_vlen(bpf_lsm_info.btf_hook_heads))
    + return ERR_PTR(-EINVAL);
    +
    + member = btf_type_member(bpf_lsm_info.btf_hook_heads) + idx;
    + ret = validate_hlist_head(btf, member);
    + if (ret < 0)
    + return ERR_PTR(ret);
    +
    + return member;
    +}
    +
    +/* 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_idx(struct btf *btf, u32 idx)
    +{
    + const struct btf_member *member, *hook_head = NULL;
    + const struct btf_type *t;
    + u32 i;
    +
    + hook_head = bpf_lsm_head_by_idx(btf, idx);
    + if (IS_ERR(hook_head))
    + return ERR_PTR(PTR_ERR(hook_head));
    +
    + for_each_member(i, bpf_lsm_info.btf_hook_types, member) {
    + if (hook_head->name_off == member->name_off) {
    + t = btf_type_by_id(btf, member->type);
    + if (unlikely(!t))
    + return ERR_PTR(-EINVAL);
    +
    + if (!btf_type_is_ptr(t))
    + return ERR_PTR(-EINVAL);
    +
    + t = btf_type_by_id(btf, t->type);
    + if (unlikely(!t))
    + return ERR_PTR(-EINVAL);
    + return t;
    + }
    + }
    +
    + return ERR_PTR(-ESRCH);
    +}
    diff --git a/security/bpf/include/bpf_lsm.h b/security/bpf/include/bpf_lsm.h
    new file mode 100644
    index 000000000000..f142596d97bd
    --- /dev/null
    +++ b/security/bpf/include/bpf_lsm.h
    @@ -0,0 +1,21 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +
    +#ifndef _BPF_LSM_H
    +#define _BPF_LSM_H
    +
    +#include <linux/filter.h>
    +#include <linux/bpf.h>
    +#include <linux/btf.h>
    +
    +struct bpf_lsm_info {
    + /* BTF type for security_hook_heads populated at init.
    + */
    + const struct btf_type *btf_hook_heads;
    + /* BTF type for security_list_options populated at init.
    + */
    + const struct btf_type *btf_hook_types;
    +};
    +
    +extern struct bpf_lsm_info bpf_lsm_info;
    +
    +#endif /* _BPF_LSM_H */
    diff --git a/security/bpf/lsm.c b/security/bpf/lsm.c
    index a25a068e1781..736e0ee3f926 100644
    --- a/security/bpf/lsm.c
    +++ b/security/bpf/lsm.c
    @@ -7,6 +7,8 @@
    #include <linux/bpf_lsm.h>
    #include <linux/lsm_hooks.h>

    +#include "bpf_lsm.h"
    +
    /* This is only for internal hooks, always statically shipped as part of the
    * BPF LSM. Statically defined hooks are appended to the security_hook_heads
    * which is common for LSMs and R/O after init.
    @@ -19,6 +21,39 @@ static struct security_hook_list bpf_lsm_hooks[] __lsm_ro_after_init = {};
    */
    struct security_hook_heads bpf_lsm_hook_heads;

    +struct bpf_lsm_info bpf_lsm_info;
    +
    +static __init int bpf_lsm_info_init(void)
    +{
    + const struct btf_type *t;
    +
    + if (!btf_vmlinux)
    + /* No need to grab any locks because we are still in init */
    + btf_vmlinux = btf_parse_vmlinux();
    +
    + if (IS_ERR(btf_vmlinux)) {
    + pr_err("btf_vmlinux is malformed\n");
    + return PTR_ERR(btf_vmlinux);
    + }
    +
    + t = btf_type_by_name_kind(btf_vmlinux, "security_hook_heads",
    + BTF_KIND_STRUCT);
    + if (WARN_ON(IS_ERR(t)))
    + return PTR_ERR(t);
    +
    + bpf_lsm_info.btf_hook_heads = t;
    +
    + t = btf_type_by_name_kind(btf_vmlinux, "security_list_options",
    + BTF_KIND_UNION);
    + if (WARN_ON(IS_ERR(t)))
    + return PTR_ERR(t);
    +
    + bpf_lsm_info.btf_hook_types = t;
    + return 0;
    +}
    +
    +late_initcall(bpf_lsm_info_init);
    +
    static int __init bpf_lsm_init(void)
    {
    security_add_hooks(bpf_lsm_hooks, ARRAY_SIZE(bpf_lsm_hooks), "bpf");
    --
    2.20.1
    \
     
     \ /
      Last update: 2020-01-23 16:26    [W:3.170 / U:0.388 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site