Skip to content

Commit e10500b

Browse files
qmonnetanakryiko
authored andcommitted
libbpf: Fix segfault due to libelf functions not setting errno
Libelf functions do not set errno on failure. Instead, it relies on its internal _elf_errno value, that can be retrieved via elf_errno (or the corresponding message via elf_errmsg()). From "man libelf": If a libelf function encounters an error it will set an internal error code that can be retrieved with elf_errno. Each thread maintains its own separate error code. The meaning of each error code can be determined with elf_errmsg, which returns a string describing the error. As a consequence, libbpf should not return -errno when a function from libelf fails, because an empty value will not be interpreted as an error and won't prevent the program to stop. This is visible in bpf_linker__add_file(), for example, where we call a succession of functions that rely on libelf: err = err ?: linker_load_obj_file(linker, filename, opts, &obj); err = err ?: linker_append_sec_data(linker, &obj); err = err ?: linker_append_elf_syms(linker, &obj); err = err ?: linker_append_elf_relos(linker, &obj); err = err ?: linker_append_btf(linker, &obj); err = err ?: linker_append_btf_ext(linker, &obj); If the object file that we try to process is not, in fact, a correct object file, linker_load_obj_file() may fail with errno not being set, and return 0. In this case we attempt to run linker_append_elf_sysms() and may segfault. This can happen (and was discovered) with bpftool: $ bpftool gen object output.o sample_ret0.bpf.c libbpf: failed to get ELF header for sample_ret0.bpf.c: invalid `Elf' handle zsh: segmentation fault (core dumped) bpftool gen object output.o sample_ret0.bpf.c Fix the issue by returning a non-null error code (-EINVAL) when libelf functions fail. Fixes: faf6ed3 ("libbpf: Add BPF static linker APIs") Signed-off-by: Quentin Monnet <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent dff8470 commit e10500b

File tree

1 file changed

+8
-14
lines changed

1 file changed

+8
-14
lines changed

tools/lib/bpf/linker.c

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -566,17 +566,15 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
566566
}
567567
obj->elf = elf_begin(obj->fd, ELF_C_READ_MMAP, NULL);
568568
if (!obj->elf) {
569-
err = -errno;
570569
pr_warn_elf("failed to parse ELF file '%s'", filename);
571-
return err;
570+
return -EINVAL;
572571
}
573572

574573
/* Sanity check ELF file high-level properties */
575574
ehdr = elf64_getehdr(obj->elf);
576575
if (!ehdr) {
577-
err = -errno;
578576
pr_warn_elf("failed to get ELF header for %s", filename);
579-
return err;
577+
return -EINVAL;
580578
}
581579

582580
/* Linker output endianness set by first input object */
@@ -606,9 +604,8 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
606604
}
607605

608606
if (elf_getshdrstrndx(obj->elf, &obj->shstrs_sec_idx)) {
609-
err = -errno;
610607
pr_warn_elf("failed to get SHSTRTAB section index for %s", filename);
611-
return err;
608+
return -EINVAL;
612609
}
613610

614611
scn = NULL;
@@ -618,26 +615,23 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
618615

619616
shdr = elf64_getshdr(scn);
620617
if (!shdr) {
621-
err = -errno;
622618
pr_warn_elf("failed to get section #%zu header for %s",
623619
sec_idx, filename);
624-
return err;
620+
return -EINVAL;
625621
}
626622

627623
sec_name = elf_strptr(obj->elf, obj->shstrs_sec_idx, shdr->sh_name);
628624
if (!sec_name) {
629-
err = -errno;
630625
pr_warn_elf("failed to get section #%zu name for %s",
631626
sec_idx, filename);
632-
return err;
627+
return -EINVAL;
633628
}
634629

635630
data = elf_getdata(scn, 0);
636631
if (!data) {
637-
err = -errno;
638632
pr_warn_elf("failed to get section #%zu (%s) data from %s",
639633
sec_idx, sec_name, filename);
640-
return err;
634+
return -EINVAL;
641635
}
642636

643637
sec = add_src_sec(obj, sec_name);
@@ -2680,14 +2674,14 @@ int bpf_linker__finalize(struct bpf_linker *linker)
26802674

26812675
/* Finalize ELF layout */
26822676
if (elf_update(linker->elf, ELF_C_NULL) < 0) {
2683-
err = -errno;
2677+
err = -EINVAL;
26842678
pr_warn_elf("failed to finalize ELF layout");
26852679
return libbpf_err(err);
26862680
}
26872681

26882682
/* Write out final ELF contents */
26892683
if (elf_update(linker->elf, ELF_C_WRITE) < 0) {
2690-
err = -errno;
2684+
err = -EINVAL;
26912685
pr_warn_elf("failed to write ELF contents");
26922686
return libbpf_err(err);
26932687
}

0 commit comments

Comments
 (0)