Support loads of static 32-bit data when BPF writers make use of convenience macros for accessing static global data variables. A later patch in this series will demonstrate its usage in a selftest.
As of LLVM-7, this technique only works with 32-bit data, as LLVM will complain if this technique is attempted with data of other sizes: LLVM ERROR: Unsupported relocation: try to compile with -O2 or above, or check your static variable usage Based on the proof of concept by Daniel Borkmann (presented at LPC 2018). Signed-off-by: Joe Stringer <j...@wand.net.nz> --- tools/lib/bpf/libbpf.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 1ec28d5154dc..da35d5559b22 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -140,11 +140,13 @@ struct bpf_program { enum { RELO_LD64, RELO_CALL, + RELO_DATA, } type; int insn_idx; union { int map_idx; int text_off; + uint32_t data; }; } *reloc_desc; int nr_reloc; @@ -210,6 +212,7 @@ struct bpf_object { Elf *elf; GElf_Ehdr ehdr; Elf_Data *symbols; + Elf_Data *global_data; size_t strtabidx; struct { GElf_Shdr shdr; @@ -218,6 +221,7 @@ struct bpf_object { int nr_reloc; int maps_shndx; int text_shndx; + int data_shndx; } efile; /* * All loaded bpf_object is linked in a list, which is @@ -476,6 +480,7 @@ static void bpf_object__elf_finish(struct bpf_object *obj) obj->efile.elf = NULL; } obj->efile.symbols = NULL; + obj->efile.global_data = NULL; zfree(&obj->efile.reloc); obj->efile.nr_reloc = 0; @@ -866,6 +871,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) pr_warning("failed to alloc program %s (%s): %s", name, obj->path, cp); } + } else if (strcmp(name, ".data") == 0) { + obj->efile.global_data = data; + obj->efile.data_shndx = idx; } } else if (sh.sh_type == SHT_REL) { void *reloc = obj->efile.reloc; @@ -962,6 +970,7 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, Elf_Data *symbols = obj->efile.symbols; int text_shndx = obj->efile.text_shndx; int maps_shndx = obj->efile.maps_shndx; + int data_shndx = obj->efile.data_shndx; struct bpf_map *maps = obj->maps; size_t nr_maps = obj->nr_maps; int i, nrels; @@ -1000,8 +1009,9 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, (long long) (rel.r_info >> 32), (long long) sym.st_value, sym.st_name); - if (sym.st_shndx != maps_shndx && sym.st_shndx != text_shndx) { - pr_warning("Program '%s' contains non-map related relo data pointing to section %u\n", + if (sym.st_shndx != maps_shndx && sym.st_shndx != text_shndx && + sym.st_shndx != data_shndx) { + pr_warning("Program '%s' contains unrecognized relo data pointing to section %u\n", prog->section_name, sym.st_shndx); return -LIBBPF_ERRNO__RELOC; } @@ -1046,6 +1056,20 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, prog->reloc_desc[i].type = RELO_LD64; prog->reloc_desc[i].insn_idx = insn_idx; prog->reloc_desc[i].map_idx = map_idx; + } else if (sym.st_shndx == data_shndx) { + Elf_Data *global_data = obj->efile.global_data; + uint32_t *static_data; + + if (sym.st_value + sizeof(uint32_t) > (int)global_data->d_size) { + pr_warning("bpf relocation: static data load beyond data size %lu\n", + global_data->d_size); + return -LIBBPF_ERRNO__RELOC; + } + + static_data = global_data->d_buf + sym.st_value; + prog->reloc_desc[i].type = RELO_DATA; + prog->reloc_desc[i].insn_idx = insn_idx; + prog->reloc_desc[i].data = *static_data; } } return 0; @@ -1399,6 +1423,12 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) &prog->reloc_desc[i]); if (err) return err; + } else if (prog->reloc_desc[i].type == RELO_DATA) { + struct bpf_insn *insns = prog->insns; + int insn_idx; + + insn_idx = prog->reloc_desc[i].insn_idx; + insns[insn_idx].imm = prog->reloc_desc[i].data; } } -- 2.19.1