perf bpf: Check relocation target section
Libbpf should check the target section before doing relocation to ensure the relocation is correct. If not, a bug in LLVM causes an error. See [1]. Also, if an incorrect BPF script uses both global variable and map, global variable whould be treated as map and be relocated without error. This patch saves the id of the map section into obj->efile and compare target section of a relocation symbol against it during relocation. Previous patch introduces a test case about this problem. After this patch: # ~/perf test BPF 37: Test BPF filter : 37.1: Test basic BPF filtering : Ok 37.2: Test BPF prologue generation : Ok 37.3: Test BPF relocation checker : Ok # perf test -v BPF ... 37.3: Test BPF relocation checker : ... libbpf: loading object '[bpf_relocation_test]' from buffer libbpf: section .strtab, size 126, link 0, flags 0, type=3 libbpf: section .text, size 0, link 0, flags 6, type=1 libbpf: section .data, size 0, link 0, flags 3, type=1 libbpf: section .bss, size 0, link 0, flags 3, type=8 libbpf: section func=sys_write, size 104, link 0, flags 6, type=1 libbpf: found program func=sys_write libbpf: section .relfunc=sys_write, size 16, link 10, flags 0, type=9 libbpf: section maps, size 16, link 0, flags 3, type=1 libbpf: maps in [bpf_relocation_test]: 16 bytes libbpf: section license, size 4, link 0, flags 3, type=1 libbpf: license of [bpf_relocation_test] is GPL libbpf: section version, size 4, link 0, flags 3, type=1 libbpf: kernel version of [bpf_relocation_test] is 40400 libbpf: section .symtab, size 144, link 1, flags 0, type=2 libbpf: map 0 is "my_table" libbpf: collecting relocating info for: 'func=sys_write' libbpf: Program 'func=sys_write' contains non-map related relo data pointing to section 65522 bpf: failed to load buffer Compile BPF program failed. test child finished with 0 ---- end ---- Test BPF filter subtest 2: Ok [1] https://llvm.org/bugs/show_bug.cgi?id=26243 Signed-off-by: Wang Nan <wangnan0@huawei.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: He Kuang <hekuang@huawei.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Li Zefan <lizefan@huawei.com> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Will Deacon <will.deacon@arm.com> Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1453715801-7732-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
7b6982ce4b
commit
666810e86a
|
@ -201,6 +201,7 @@ struct bpf_object {
|
||||||
Elf_Data *data;
|
Elf_Data *data;
|
||||||
} *reloc;
|
} *reloc;
|
||||||
int nr_reloc;
|
int nr_reloc;
|
||||||
|
int maps_shndx;
|
||||||
} efile;
|
} efile;
|
||||||
/*
|
/*
|
||||||
* All loaded bpf_object is linked in a list, which is
|
* All loaded bpf_object is linked in a list, which is
|
||||||
|
@ -350,6 +351,7 @@ static struct bpf_object *bpf_object__new(const char *path,
|
||||||
*/
|
*/
|
||||||
obj->efile.obj_buf = obj_buf;
|
obj->efile.obj_buf = obj_buf;
|
||||||
obj->efile.obj_buf_sz = obj_buf_sz;
|
obj->efile.obj_buf_sz = obj_buf_sz;
|
||||||
|
obj->efile.maps_shndx = -1;
|
||||||
|
|
||||||
obj->loaded = false;
|
obj->loaded = false;
|
||||||
|
|
||||||
|
@ -529,12 +531,12 @@ bpf_object__init_maps(struct bpf_object *obj, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx)
|
bpf_object__init_maps_name(struct bpf_object *obj)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
Elf_Data *symbols = obj->efile.symbols;
|
Elf_Data *symbols = obj->efile.symbols;
|
||||||
|
|
||||||
if (!symbols || maps_shndx < 0)
|
if (!symbols || obj->efile.maps_shndx < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
|
for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
|
||||||
|
@ -544,7 +546,7 @@ bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx)
|
||||||
|
|
||||||
if (!gelf_getsym(symbols, i, &sym))
|
if (!gelf_getsym(symbols, i, &sym))
|
||||||
continue;
|
continue;
|
||||||
if (sym.st_shndx != maps_shndx)
|
if (sym.st_shndx != obj->efile.maps_shndx)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
map_name = elf_strptr(obj->efile.elf,
|
map_name = elf_strptr(obj->efile.elf,
|
||||||
|
@ -572,7 +574,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
|
||||||
Elf *elf = obj->efile.elf;
|
Elf *elf = obj->efile.elf;
|
||||||
GElf_Ehdr *ep = &obj->efile.ehdr;
|
GElf_Ehdr *ep = &obj->efile.ehdr;
|
||||||
Elf_Scn *scn = NULL;
|
Elf_Scn *scn = NULL;
|
||||||
int idx = 0, err = 0, maps_shndx = -1;
|
int idx = 0, err = 0;
|
||||||
|
|
||||||
/* Elf is corrupted/truncated, avoid calling elf_strptr. */
|
/* Elf is corrupted/truncated, avoid calling elf_strptr. */
|
||||||
if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) {
|
if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) {
|
||||||
|
@ -625,7 +627,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
|
||||||
else if (strcmp(name, "maps") == 0) {
|
else if (strcmp(name, "maps") == 0) {
|
||||||
err = bpf_object__init_maps(obj, data->d_buf,
|
err = bpf_object__init_maps(obj, data->d_buf,
|
||||||
data->d_size);
|
data->d_size);
|
||||||
maps_shndx = idx;
|
obj->efile.maps_shndx = idx;
|
||||||
} else if (sh.sh_type == SHT_SYMTAB) {
|
} else if (sh.sh_type == SHT_SYMTAB) {
|
||||||
if (obj->efile.symbols) {
|
if (obj->efile.symbols) {
|
||||||
pr_warning("bpf: multiple SYMTAB in %s\n",
|
pr_warning("bpf: multiple SYMTAB in %s\n",
|
||||||
|
@ -674,8 +676,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
|
||||||
pr_warning("Corrupted ELF file: index of strtab invalid\n");
|
pr_warning("Corrupted ELF file: index of strtab invalid\n");
|
||||||
return LIBBPF_ERRNO__FORMAT;
|
return LIBBPF_ERRNO__FORMAT;
|
||||||
}
|
}
|
||||||
if (maps_shndx >= 0)
|
if (obj->efile.maps_shndx >= 0)
|
||||||
err = bpf_object__init_maps_name(obj, maps_shndx);
|
err = bpf_object__init_maps_name(obj);
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -697,7 +699,8 @@ bpf_object__find_prog_by_idx(struct bpf_object *obj, int idx)
|
||||||
static int
|
static int
|
||||||
bpf_program__collect_reloc(struct bpf_program *prog,
|
bpf_program__collect_reloc(struct bpf_program *prog,
|
||||||
size_t nr_maps, GElf_Shdr *shdr,
|
size_t nr_maps, GElf_Shdr *shdr,
|
||||||
Elf_Data *data, Elf_Data *symbols)
|
Elf_Data *data, Elf_Data *symbols,
|
||||||
|
int maps_shndx)
|
||||||
{
|
{
|
||||||
int i, nrels;
|
int i, nrels;
|
||||||
|
|
||||||
|
@ -724,9 +727,6 @@ bpf_program__collect_reloc(struct bpf_program *prog,
|
||||||
return -LIBBPF_ERRNO__FORMAT;
|
return -LIBBPF_ERRNO__FORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
insn_idx = rel.r_offset / sizeof(struct bpf_insn);
|
|
||||||
pr_debug("relocation: insn_idx=%u\n", insn_idx);
|
|
||||||
|
|
||||||
if (!gelf_getsym(symbols,
|
if (!gelf_getsym(symbols,
|
||||||
GELF_R_SYM(rel.r_info),
|
GELF_R_SYM(rel.r_info),
|
||||||
&sym)) {
|
&sym)) {
|
||||||
|
@ -735,6 +735,15 @@ bpf_program__collect_reloc(struct bpf_program *prog,
|
||||||
return -LIBBPF_ERRNO__FORMAT;
|
return -LIBBPF_ERRNO__FORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sym.st_shndx != maps_shndx) {
|
||||||
|
pr_warning("Program '%s' contains non-map related relo data pointing to section %u\n",
|
||||||
|
prog->section_name, sym.st_shndx);
|
||||||
|
return -LIBBPF_ERRNO__RELOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
insn_idx = rel.r_offset / sizeof(struct bpf_insn);
|
||||||
|
pr_debug("relocation: insn_idx=%u\n", insn_idx);
|
||||||
|
|
||||||
if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) {
|
if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) {
|
||||||
pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n",
|
pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n",
|
||||||
insn_idx, insns[insn_idx].code);
|
insn_idx, insns[insn_idx].code);
|
||||||
|
@ -863,7 +872,8 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
|
||||||
|
|
||||||
err = bpf_program__collect_reloc(prog, nr_maps,
|
err = bpf_program__collect_reloc(prog, nr_maps,
|
||||||
shdr, data,
|
shdr, data,
|
||||||
obj->efile.symbols);
|
obj->efile.symbols,
|
||||||
|
obj->efile.maps_shndx);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue