Commit 0d13bfce authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Alexei Starovoitov

libbpf: Don't require root for bpf_object__open()

Reorganize bpf_object__open and bpf_object__load steps such that
bpf_object__open doesn't need root access. This was previously done for
feature probing and BTF sanitization. This doesn't have to happen on open,
though, so move all those steps into the load phase.

This is important, because it makes it possible for tools like bpftool, to
just open BPF object file and inspect their contents: programs, maps, BTF,
etc. For such operations it is prohibitive to require root access. On the
other hand, there is a lot of custom libbpf logic in those steps, so its best
avoided for tools to reimplement all that on their own.
Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarMartin KaFai Lau <kafai@fb.com>
Link: https://lore.kernel.org/bpf/20191214014341.3442258-2-andriin@fb.com
parent aa915931
...@@ -101,13 +101,6 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...) ...@@ -101,13 +101,6 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
#define STRERR_BUFSIZE 128 #define STRERR_BUFSIZE 128
#define CHECK_ERR(action, err, out) do { \
err = action; \
if (err) \
goto out; \
} while (0)
/* Copied from tools/perf/util/util.h */ /* Copied from tools/perf/util/util.h */
#ifndef zfree #ifndef zfree
# define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) # define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
...@@ -864,8 +857,7 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type, ...@@ -864,8 +857,7 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,
def->value_size = data->d_size; def->value_size = data->d_size;
def->max_entries = 1; def->max_entries = 1;
def->map_flags = type == LIBBPF_MAP_RODATA ? BPF_F_RDONLY_PROG : 0; def->map_flags = type == LIBBPF_MAP_RODATA ? BPF_F_RDONLY_PROG : 0;
if (obj->caps.array_mmap) def->map_flags |= BPF_F_MMAPABLE;
def->map_flags |= BPF_F_MMAPABLE;
pr_debug("map '%s' (global data): at sec_idx %d, offset %zu, flags %x.\n", pr_debug("map '%s' (global data): at sec_idx %d, offset %zu, flags %x.\n",
map_name, map->sec_idx, map->sec_offset, def->map_flags); map_name, map->sec_idx, map->sec_offset, def->map_flags);
...@@ -888,8 +880,6 @@ static int bpf_object__init_global_data_maps(struct bpf_object *obj) ...@@ -888,8 +880,6 @@ static int bpf_object__init_global_data_maps(struct bpf_object *obj)
{ {
int err; int err;
if (!obj->caps.global_data)
return 0;
/* /*
* Populate obj->maps with libbpf internal maps. * Populate obj->maps with libbpf internal maps.
*/ */
...@@ -1393,10 +1383,11 @@ static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict, ...@@ -1393,10 +1383,11 @@ static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict,
return 0; return 0;
} }
static int bpf_object__init_maps(struct bpf_object *obj, bool relaxed_maps, static int bpf_object__init_maps(struct bpf_object *obj,
const char *pin_root_path) struct bpf_object_open_opts *opts)
{ {
bool strict = !relaxed_maps; const char *pin_root_path = OPTS_GET(opts, pin_root_path, NULL);
bool strict = !OPTS_GET(opts, relaxed_maps, false);
int err; int err;
err = bpf_object__init_user_maps(obj, strict); err = bpf_object__init_user_maps(obj, strict);
...@@ -1592,8 +1583,7 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj) ...@@ -1592,8 +1583,7 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
return 0; return 0;
} }
static int bpf_object__elf_collect(struct bpf_object *obj, bool relaxed_maps, static int bpf_object__elf_collect(struct bpf_object *obj)
const char *pin_root_path)
{ {
Elf *elf = obj->efile.elf; Elf *elf = obj->efile.elf;
GElf_Ehdr *ep = &obj->efile.ehdr; GElf_Ehdr *ep = &obj->efile.ehdr;
...@@ -1728,14 +1718,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj, bool relaxed_maps, ...@@ -1728,14 +1718,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj, bool relaxed_maps,
pr_warn("Corrupted ELF file: index of strtab invalid\n"); pr_warn("Corrupted ELF file: index of strtab invalid\n");
return -LIBBPF_ERRNO__FORMAT; return -LIBBPF_ERRNO__FORMAT;
} }
err = bpf_object__init_btf(obj, btf_data, btf_ext_data); return bpf_object__init_btf(obj, btf_data, btf_ext_data);
if (!err)
err = bpf_object__init_maps(obj, relaxed_maps, pin_root_path);
if (!err)
err = bpf_object__sanitize_and_load_btf(obj);
if (!err)
err = bpf_object__init_prog_names(obj);
return err;
} }
static struct bpf_program * static struct bpf_program *
...@@ -1876,11 +1859,6 @@ static int bpf_program__record_reloc(struct bpf_program *prog, ...@@ -1876,11 +1859,6 @@ static int bpf_program__record_reloc(struct bpf_program *prog,
pr_warn("bad data relo against section %u\n", shdr_idx); pr_warn("bad data relo against section %u\n", shdr_idx);
return -LIBBPF_ERRNO__RELOC; return -LIBBPF_ERRNO__RELOC;
} }
if (!obj->caps.global_data) {
pr_warn("relocation: kernel does not support global \'%s\' variable access in insns[%d]\n",
name, insn_idx);
return -LIBBPF_ERRNO__RELOC;
}
for (map_idx = 0; map_idx < nr_maps; map_idx++) { for (map_idx = 0; map_idx < nr_maps; map_idx++) {
map = &obj->maps[map_idx]; map = &obj->maps[map_idx];
if (map->libbpf_type != type) if (map->libbpf_type != type)
...@@ -3918,12 +3896,10 @@ static struct bpf_object * ...@@ -3918,12 +3896,10 @@ static struct bpf_object *
__bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
struct bpf_object_open_opts *opts) struct bpf_object_open_opts *opts)
{ {
const char *pin_root_path;
struct bpf_program *prog; struct bpf_program *prog;
struct bpf_object *obj; struct bpf_object *obj;
const char *obj_name; const char *obj_name;
char tmp_name[64]; char tmp_name[64];
bool relaxed_maps;
__u32 attach_prog_fd; __u32 attach_prog_fd;
int err; int err;
...@@ -3953,16 +3929,16 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, ...@@ -3953,16 +3929,16 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
return obj; return obj;
obj->relaxed_core_relocs = OPTS_GET(opts, relaxed_core_relocs, false); obj->relaxed_core_relocs = OPTS_GET(opts, relaxed_core_relocs, false);
relaxed_maps = OPTS_GET(opts, relaxed_maps, false);
pin_root_path = OPTS_GET(opts, pin_root_path, NULL);
attach_prog_fd = OPTS_GET(opts, attach_prog_fd, 0); attach_prog_fd = OPTS_GET(opts, attach_prog_fd, 0);
CHECK_ERR(bpf_object__elf_init(obj), err, out); err = bpf_object__elf_init(obj);
CHECK_ERR(bpf_object__check_endianness(obj), err, out); err = err ? : bpf_object__check_endianness(obj);
CHECK_ERR(bpf_object__probe_caps(obj), err, out); err = err ? : bpf_object__elf_collect(obj);
CHECK_ERR(bpf_object__elf_collect(obj, relaxed_maps, pin_root_path), err = err ? : bpf_object__init_maps(obj, opts);
err, out); err = err ? : bpf_object__init_prog_names(obj);
CHECK_ERR(bpf_object__collect_reloc(obj), err, out); err = err ? : bpf_object__collect_reloc(obj);
if (err)
goto out;
bpf_object__elf_finish(obj); bpf_object__elf_finish(obj);
bpf_object__for_each_program(prog, obj) { bpf_object__for_each_program(prog, obj) {
...@@ -4080,6 +4056,24 @@ int bpf_object__unload(struct bpf_object *obj) ...@@ -4080,6 +4056,24 @@ int bpf_object__unload(struct bpf_object *obj)
return 0; return 0;
} }
static int bpf_object__sanitize_maps(struct bpf_object *obj)
{
struct bpf_map *m;
bpf_object__for_each_map(m, obj) {
if (!bpf_map__is_internal(m))
continue;
if (!obj->caps.global_data) {
pr_warn("kernel doesn't support global data\n");
return -ENOTSUP;
}
if (!obj->caps.array_mmap)
m->def.map_flags ^= BPF_F_MMAPABLE;
}
return 0;
}
int bpf_object__load_xattr(struct bpf_object_load_attr *attr) int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
{ {
struct bpf_object *obj; struct bpf_object *obj;
...@@ -4098,9 +4092,14 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr) ...@@ -4098,9 +4092,14 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
obj->loaded = true; obj->loaded = true;
CHECK_ERR(bpf_object__create_maps(obj), err, out); err = bpf_object__probe_caps(obj);
CHECK_ERR(bpf_object__relocate(obj, attr->target_btf_path), err, out); err = err ? : bpf_object__sanitize_and_load_btf(obj);
CHECK_ERR(bpf_object__load_progs(obj, attr->log_level), err, out); err = err ? : bpf_object__sanitize_maps(obj);
err = err ? : bpf_object__create_maps(obj);
err = err ? : bpf_object__relocate(obj, attr->target_btf_path);
err = err ? : bpf_object__load_progs(obj, attr->log_level);
if (err)
goto out;
return 0; return 0;
out: out:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment