The static linker sanity-checks relocation sections before appending them,
but for executable target sections it only verifies that r_offset is
BPF-instruction aligned. It does not verify that the offset is inside the
relocated section.
A malformed object can therefore pass an out-of-range offset through
linker_sanity_check_elf_relos(). When the relocation is against an
STT_SECTION symbol, linker_append_elf_relos() uses the unchecked offset to
find the instruction to adjust:
insn = dst_linked_sec->raw_data + dst_rel->r_offset;
and then reads insn->code and updates insn->imm.
This is reproducible with bpftool's static linker by crafting a BPF object
with a 16-byte executable section and a relocation in its .rel section
whose r_offset is 0x1000:
BUG: AddressSanitizer: heap-buffer-overflow in linker_append_elf_relos
READ of size 1
linker_append_elf_relos
bpf_linker_add_file
bpf_linker__add_file
do_object
Reject relocation offsets that are outside the relocated section before any
later use. This mirrors the normal object loading path, which already
rejects executable relocations whose r_offset is not inside the program
section.
Fixes: faf6ed321cf6 ("libbpf: Add BPF static linker APIs")
Cc: [email protected]
Assisted-by: Codex:gpt-5
Signed-off-by: HyeongJun An <[email protected]>
---
tools/lib/bpf/linker.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c
index 78f92c39290a..3eb23da167d2 100644
--- a/tools/lib/bpf/linker.c
+++ b/tools/lib/bpf/linker.c
@@ -1048,6 +1048,12 @@ static int linker_sanity_check_elf_relos(struct src_obj
*obj, struct src_sec *se
return -EINVAL;
}
+ if (relo->r_offset >= link_sec->shdr->sh_size) {
+ pr_warn("ELF relo #%d in section #%zu has invalid
offset %zu in %s\n",
+ i, sec->sec_idx, (size_t)relo->r_offset,
obj->filename);
+ return -EINVAL;
+ }
+
if (link_sec->shdr->sh_flags & SHF_EXECINSTR) {
if (relo->r_offset % sizeof(struct bpf_insn) != 0) {
pr_warn("ELF relo #%d in section #%zu points to
missing symbol #%zu in %s\n",
--
2.43.0