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


Reply via email to