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))
|
||||
#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
|
||||
* 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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 const struct btf_type *
|
||||
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,
|
||||
va_list args)
|
||||
@ -274,6 +275,7 @@ struct bpf_program {
|
||||
bpf_program_clear_priv_t clear_priv;
|
||||
|
||||
bool load;
|
||||
bool mark_btf_static;
|
||||
enum bpf_prog_type type;
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
int prog_ifindex;
|
||||
@ -698,6 +700,15 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
|
||||
if (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++;
|
||||
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;
|
||||
bool btf_mandatory, sanitize;
|
||||
int err = 0;
|
||||
int i, err = 0;
|
||||
|
||||
if (!obj->btf)
|
||||
return 0;
|
||||
@ -2632,6 +2643,38 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
|
||||
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);
|
||||
if (sanitize) {
|
||||
const void *raw_data;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#pragma GCC poison reallocarray
|
||||
|
||||
#include "libbpf.h"
|
||||
#include "btf.h"
|
||||
|
||||
#ifndef EM_BPF
|
||||
#define EM_BPF 247
|
||||
@ -132,6 +133,11 @@ struct btf_type;
|
||||
|
||||
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,
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user