libbpf: Mark BPF subprogs with hidden visibility as static for BPF verifier
Define __hidden helper macro in bpf_helpers.h, which is a short-hand for __attribute__((visibility("hidden"))). Add libbpf support to mark BPF subprograms marked with __hidden as static in BTF information to enforce BPF verifier's static function validation algorithm, which takes more information (caller's context) into account during a subprogram validation. Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/bpf/20210423181348.1801389-5-andrii@kernel.org
This commit is contained in:
parent
0fec7a3cee
commit
aea28a602f
@ -47,6 +47,14 @@
|
|||||||
#define __weak __attribute__((weak))
|
#define __weak __attribute__((weak))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use __hidden attribute to mark a non-static BPF subprogram effectively
|
||||||
|
* static for BPF verifier's verification algorithm purposes, allowing more
|
||||||
|
* extensive and permissive BPF verification process, taking into account
|
||||||
|
* subprogram's caller context.
|
||||||
|
*/
|
||||||
|
#define __hidden __attribute__((visibility("hidden")))
|
||||||
|
|
||||||
/* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include
|
/* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include
|
||||||
* any system-level headers (such as stddef.h, linux/version.h, etc), and
|
* any system-level headers (such as stddef.h, linux/version.h, etc), and
|
||||||
* commonly-used macros like NULL and KERNEL_VERSION aren't available through
|
* commonly-used macros like NULL and KERNEL_VERSION aren't available through
|
||||||
|
@ -1605,11 +1605,6 @@ static void *btf_add_type_mem(struct btf *btf, size_t add_sz)
|
|||||||
btf->hdr->type_len, UINT_MAX, add_sz);
|
btf->hdr->type_len, UINT_MAX, add_sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __u32 btf_type_info(int kind, int vlen, int kflag)
|
|
||||||
{
|
|
||||||
return (kflag << 31) | (kind << 24) | vlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void btf_type_inc_vlen(struct btf_type *t)
|
static void btf_type_inc_vlen(struct btf_type *t)
|
||||||
{
|
{
|
||||||
t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, btf_kflag(t));
|
t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, btf_kflag(t));
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
static struct bpf_map *bpf_object__add_map(struct bpf_object *obj);
|
static struct bpf_map *bpf_object__add_map(struct bpf_object *obj);
|
||||||
static const struct btf_type *
|
static const struct btf_type *
|
||||||
skip_mods_and_typedefs(const struct btf *btf, __u32 id, __u32 *res_id);
|
skip_mods_and_typedefs(const struct btf *btf, __u32 id, __u32 *res_id);
|
||||||
|
static bool prog_is_subprog(const struct bpf_object *obj, const struct bpf_program *prog);
|
||||||
|
|
||||||
static int __base_pr(enum libbpf_print_level level, const char *format,
|
static int __base_pr(enum libbpf_print_level level, const char *format,
|
||||||
va_list args)
|
va_list args)
|
||||||
@ -274,6 +275,7 @@ struct bpf_program {
|
|||||||
bpf_program_clear_priv_t clear_priv;
|
bpf_program_clear_priv_t clear_priv;
|
||||||
|
|
||||||
bool load;
|
bool load;
|
||||||
|
bool mark_btf_static;
|
||||||
enum bpf_prog_type type;
|
enum bpf_prog_type type;
|
||||||
enum bpf_attach_type expected_attach_type;
|
enum bpf_attach_type expected_attach_type;
|
||||||
int prog_ifindex;
|
int prog_ifindex;
|
||||||
@ -698,6 +700,15 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
/* if function is a global/weak symbol, but has hidden
|
||||||
|
* visibility (STV_HIDDEN), mark its BTF FUNC as static to
|
||||||
|
* enable more permissive BPF verification mode with more
|
||||||
|
* outside context available to BPF verifier
|
||||||
|
*/
|
||||||
|
if (GELF_ST_BIND(sym.st_info) != STB_LOCAL
|
||||||
|
&& GELF_ST_VISIBILITY(sym.st_other) == STV_HIDDEN)
|
||||||
|
prog->mark_btf_static = true;
|
||||||
|
|
||||||
nr_progs++;
|
nr_progs++;
|
||||||
obj->nr_programs = nr_progs;
|
obj->nr_programs = nr_progs;
|
||||||
|
|
||||||
@ -2618,7 +2629,7 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
|
|||||||
{
|
{
|
||||||
struct btf *kern_btf = obj->btf;
|
struct btf *kern_btf = obj->btf;
|
||||||
bool btf_mandatory, sanitize;
|
bool btf_mandatory, sanitize;
|
||||||
int err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
if (!obj->btf)
|
if (!obj->btf)
|
||||||
return 0;
|
return 0;
|
||||||
@ -2632,6 +2643,38 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Even though some subprogs are global/weak, user might prefer more
|
||||||
|
* permissive BPF verification process that BPF verifier performs for
|
||||||
|
* static functions, taking into account more context from the caller
|
||||||
|
* functions. In such case, they need to mark such subprogs with
|
||||||
|
* __attribute__((visibility("hidden"))) and libbpf will adjust
|
||||||
|
* corresponding FUNC BTF type to be marked as static and trigger more
|
||||||
|
* involved BPF verification process.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < obj->nr_programs; i++) {
|
||||||
|
struct bpf_program *prog = &obj->programs[i];
|
||||||
|
struct btf_type *t;
|
||||||
|
const char *name;
|
||||||
|
int j, n;
|
||||||
|
|
||||||
|
if (!prog->mark_btf_static || !prog_is_subprog(obj, prog))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
n = btf__get_nr_types(obj->btf);
|
||||||
|
for (j = 1; j <= n; j++) {
|
||||||
|
t = btf_type_by_id(obj->btf, j);
|
||||||
|
if (!btf_is_func(t) || btf_func_linkage(t) != BTF_FUNC_GLOBAL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
name = btf__str_by_offset(obj->btf, t->name_off);
|
||||||
|
if (strcmp(name, prog->name) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
t->info = btf_type_info(BTF_KIND_FUNC, BTF_FUNC_STATIC, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sanitize = btf_needs_sanitization(obj);
|
sanitize = btf_needs_sanitization(obj);
|
||||||
if (sanitize) {
|
if (sanitize) {
|
||||||
const void *raw_data;
|
const void *raw_data;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#pragma GCC poison reallocarray
|
#pragma GCC poison reallocarray
|
||||||
|
|
||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
|
#include "btf.h"
|
||||||
|
|
||||||
#ifndef EM_BPF
|
#ifndef EM_BPF
|
||||||
#define EM_BPF 247
|
#define EM_BPF 247
|
||||||
@ -132,6 +133,11 @@ struct btf_type;
|
|||||||
|
|
||||||
struct btf_type *btf_type_by_id(struct btf *btf, __u32 type_id);
|
struct btf_type *btf_type_by_id(struct btf *btf, __u32 type_id);
|
||||||
|
|
||||||
|
static inline __u32 btf_type_info(int kind, int vlen, int kflag)
|
||||||
|
{
|
||||||
|
return (kflag << 31) | (kind << 24) | vlen;
|
||||||
|
}
|
||||||
|
|
||||||
void *libbpf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz,
|
void *libbpf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz,
|
||||||
size_t cur_cnt, size_t max_cnt, size_t add_cnt);
|
size_t cur_cnt, size_t max_cnt, size_t add_cnt);
|
||||||
int libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt);
|
int libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt);
|
||||||
|
Loading…
Reference in New Issue
Block a user