Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: faf6ed321cf6 ("libbpf: Add BPF static linker APIs")
Signed-off-by: Quentin Monnet <qmo@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20241205135942.65262-1-qmo@kernel.org

authored by

Quentin Monnet and committed by
Andrii Nakryiko
e10500b6 dff8470b

+8 -14
+8 -14
tools/lib/bpf/linker.c
··· 566 566 } 567 567 obj->elf = elf_begin(obj->fd, ELF_C_READ_MMAP, NULL); 568 568 if (!obj->elf) { 569 - err = -errno; 570 569 pr_warn_elf("failed to parse ELF file '%s'", filename); 571 - return err; 570 + return -EINVAL; 572 571 } 573 572 574 573 /* Sanity check ELF file high-level properties */ 575 574 ehdr = elf64_getehdr(obj->elf); 576 575 if (!ehdr) { 577 - err = -errno; 578 576 pr_warn_elf("failed to get ELF header for %s", filename); 579 - return err; 577 + return -EINVAL; 580 578 } 581 579 582 580 /* Linker output endianness set by first input object */ ··· 604 606 } 605 607 606 608 if (elf_getshdrstrndx(obj->elf, &obj->shstrs_sec_idx)) { 607 - err = -errno; 608 609 pr_warn_elf("failed to get SHSTRTAB section index for %s", filename); 609 - return err; 610 + return -EINVAL; 610 611 } 611 612 612 613 scn = NULL; ··· 615 618 616 619 shdr = elf64_getshdr(scn); 617 620 if (!shdr) { 618 - err = -errno; 619 621 pr_warn_elf("failed to get section #%zu header for %s", 620 622 sec_idx, filename); 621 - return err; 623 + return -EINVAL; 622 624 } 623 625 624 626 sec_name = elf_strptr(obj->elf, obj->shstrs_sec_idx, shdr->sh_name); 625 627 if (!sec_name) { 626 - err = -errno; 627 628 pr_warn_elf("failed to get section #%zu name for %s", 628 629 sec_idx, filename); 629 - return err; 630 + return -EINVAL; 630 631 } 631 632 632 633 data = elf_getdata(scn, 0); 633 634 if (!data) { 634 - err = -errno; 635 635 pr_warn_elf("failed to get section #%zu (%s) data from %s", 636 636 sec_idx, sec_name, filename); 637 - return err; 637 + return -EINVAL; 638 638 } 639 639 640 640 sec = add_src_sec(obj, sec_name); ··· 2674 2680 2675 2681 /* Finalize ELF layout */ 2676 2682 if (elf_update(linker->elf, ELF_C_NULL) < 0) { 2677 - err = -errno; 2683 + err = -EINVAL; 2678 2684 pr_warn_elf("failed to finalize ELF layout"); 2679 2685 return libbpf_err(err); 2680 2686 } 2681 2687 2682 2688 /* Write out final ELF contents */ 2683 2689 if (elf_update(linker->elf, ELF_C_WRITE) < 0) { 2684 - err = -errno; 2690 + err = -EINVAL; 2685 2691 pr_warn_elf("failed to write ELF contents"); 2686 2692 return libbpf_err(err); 2687 2693 }