Signed-off-by: zhang-mingyi66 <zhangmingyi5@huawei.com> (cherry picked from commit c93fa88cb0c11cd67c85e48654dc403447bc9df0)
139 lines
4.6 KiB
Diff
139 lines
4.6 KiB
Diff
From 984dcc97ae50c566924277aedc4967e1222e38c2 Mon Sep 17 00:00:00 2001
|
|
From: Quentin Monnet <qmo@kernel.org>
|
|
Date: Thu, 5 Dec 2024 13:59:42 +0000
|
|
Subject: [PATCH] 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.
|
|
|
|
Conflict:Context adapt
|
|
Reference: https://github.com/libbpf/libbpf/commit/984dcc97ae50c566924277aedc4967e1222e38c2
|
|
|
|
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
|
|
---
|
|
src/linker.c | 22 ++++++++--------------
|
|
1 file changed, 8 insertions(+), 14 deletions(-)
|
|
|
|
diff --git a/src/linker.c b/src/linker.c
|
|
index cf71d149f..e56ba6e67 100644
|
|
--- a/src/linker.c
|
|
+++ b/src/linker.c
|
|
@@ -566,17 +566,15 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
|
|
}
|
|
obj->elf = elf_begin(obj->fd, ELF_C_READ_MMAP, NULL);
|
|
if (!obj->elf) {
|
|
- err = -errno;
|
|
pr_warn_elf("failed to parse ELF file '%s'", filename);
|
|
- return err;
|
|
+ return -EINVAL;
|
|
}
|
|
|
|
/* Sanity check ELF file high-level properties */
|
|
ehdr = elf64_getehdr(obj->elf);
|
|
if (!ehdr) {
|
|
- err = -errno;
|
|
pr_warn_elf("failed to get ELF header for %s", filename);
|
|
- return err;
|
|
+ return -EINVAL;
|
|
}
|
|
if (ehdr->e_ident[EI_DATA] != host_endianness) {
|
|
err = -EOPNOTSUPP;
|
|
@@ -606,9 +604,8 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
|
|
}
|
|
|
|
if (elf_getshdrstrndx(obj->elf, &obj->shstrs_sec_idx)) {
|
|
- err = -errno;
|
|
pr_warn_elf("failed to get SHSTRTAB section index for %s", filename);
|
|
- return err;
|
|
+ return -EINVAL;
|
|
}
|
|
|
|
scn = NULL;
|
|
@@ -618,26 +615,23 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
|
|
|
|
shdr = elf64_getshdr(scn);
|
|
if (!shdr) {
|
|
- err = -errno;
|
|
pr_warn_elf("failed to get section #%zu header for %s",
|
|
sec_idx, filename);
|
|
- return err;
|
|
+ return -EINVAL;
|
|
}
|
|
|
|
sec_name = elf_strptr(obj->elf, obj->shstrs_sec_idx, shdr->sh_name);
|
|
if (!sec_name) {
|
|
- err = -errno;
|
|
pr_warn_elf("failed to get section #%zu name for %s",
|
|
sec_idx, filename);
|
|
- return err;
|
|
+ return -EINVAL;
|
|
}
|
|
|
|
data = elf_getdata(scn, 0);
|
|
if (!data) {
|
|
- err = -errno;
|
|
pr_warn_elf("failed to get section #%zu (%s) data from %s",
|
|
sec_idx, sec_name, filename);
|
|
- return err;
|
|
+ return -EINVAL;
|
|
}
|
|
|
|
sec = add_src_sec(obj, sec_name);
|
|
@@ -2680,14 +2674,14 @@ int bpf_linker__finalize(struct bpf_linker *linker)
|
|
|
|
/* Finalize ELF layout */
|
|
if (elf_update(linker->elf, ELF_C_NULL) < 0) {
|
|
- err = -errno;
|
|
+ err = -EINVAL;
|
|
pr_warn_elf("failed to finalize ELF layout");
|
|
return libbpf_err(err);
|
|
}
|
|
|
|
/* Write out final ELF contents */
|
|
if (elf_update(linker->elf, ELF_C_WRITE) < 0) {
|
|
- err = -errno;
|
|
+ err = -EINVAL;
|
|
pr_warn_elf("failed to write ELF contents");
|
|
return libbpf_err(err);
|
|
}
|
|
|
|
|