Re: [BUG] libbpf: OOB access when relocating a terminal LDIMM64

Andrii Nakryiko <[email protected]>
Newsgroups org.kernel.vger.bpf
Message-ID <CAEf4BzaeSBQAY9G9L7FbCQBZJs9M9921pbBvuz=O7d52ZxUMcg@mail.gmail.com>
On Wed, Aug 12, 2026 at 6:30 PM Mingpei CAO <[email protected]> wrote:
>
> Hello,
>
> Resending as plain text because the previous message was rejected
> by the bpf mailing list due to an HTML MIME part.
>
> I found an out-of-bounds access in libbpf's CO-RE relocation handling. A
> malformed BPF ELF object can place the first half of an LDIMM64 instruction

libbpf doesn't try to protect against maliciously modified BPF ELF
files. You are not supposed to use untrusted ELF files to load BPF
programs into the kernel, which is a hugely privileged operation and
shouldn't be taken lightly.

> in the program's final instruction slot and direct a CO-RE relocation to
> it. libbpf validates the relocation's starting instruction index, but does
> not verify that the required second LDIMM64 slot exists before accessing
> insn[1].
>
> The affected path is:
>     bpf_object__relocate_core() -> bpf_core_patch_insn()
> This affects both normal relocation and relocation poisoning.
>
> AI assistance was used in preparing this report. I independently reviewed
> the source, traced the affected versions, and reproduced both the
> out-of-bounds read and write with AddressSanitizer. Reproducer files are
> available on request.
>
> Affected versions
> -----------------
>
> The poisoning write is present starting in libbpf v0.2. The normal
> out-of-bounds read is present starting in v0.5, and both remain present
> through v1.7.0 and current master:
>     f7081a6baf3f54949aacb8c2fc11bb30783b83e9
> Commit f81dbd3475c4 removed the previous check for:
>     insn_idx + 1 >= prog->insns_cnt
> which made the normal LDIMM64 relocation path susceptible to the
> out-of-bounds read.
> Thus, the normal read path is affected from v0.5 onward, while the
> poisoning write path predates it.
>
> Related public discussion
> -------------------------
>
> I found a related 2021 fix:
> https://lore.kernel.org/bpf/[email protected]/
> That change corrected the CO-RE relocation index check from '>' to '>=',
> but it validates only the first instruction slot. It does not reject a
> terminal LDIMM64 instruction whose required second slot is missing.
>
> I therefore do not believe this issue is a duplicate.
>
> Trigger conditions
> ------------------
>
> A malformed BPF ELF object must contain a program whose final eight-byte
> instruction slot starts an LDIMM64 instruction but has no second slot. A
> .BTF.ext CO-RE relocation must target that instruction.
> The invalid access occurs during user-space relocation, before the
> malformed program reaches the kernel.
>
> Root cause
> ----------
>
> bpf_object__init_prog() allocates exactly the size of the instruction
> section at src/libbpf.c:892.
>
> bpf_object__relocate_core() validates only:
>     if (insn_idx >= prog->insns_cnt)
>         return -EINVAL;
> It then passes:
>     &prog->insns[insn_idx]
> to bpf_core_patch_insn().
>
> For LDIMM64, the normal relocation path reads insn[1] at
> src/relo_core.c:1136 and may write insn[1].imm at line 1153.
>
> The poisoning path passes insn + 1 to bpf_core_poison_insn() at
> src/relo_core.c:1056, which writes through that pointer at line 991.
>
> Neither path verifies that:
>     insn_idx + 1 < prog->insns_cnt
>
> Observed results
> ----------------
>
> Using GCC 13 and ASan on current libbpf in an Ubuntu 24.04 ARM64
> container, with an exact 64-byte instruction allocation, the normal
> relocation input produced:
>
>     ERROR: AddressSanitizer: heap-buffer-overflow
>     READ of size 4
>         #0 bpf_core_patch_insn src/relo_core.c:1136
>         #1 bpf_object__relocate_core src/libbpf.c:6178
>     0 bytes after 64-byte region
>     allocated by bpf_object__init_prog src/libbpf.c:892
>
> The relocation-poisoning input produced:
>
>     ERROR: AddressSanitizer: heap-buffer-overflow
>     WRITE of size 1
>         #0 bpf_core_poison_insn src/relo_core.c:991
>         #1 bpf_core_patch_insn src/relo_core.c:1056
>         #2 bpf_object__relocate_core src/libbpf.c:6178
>     0 bytes after 64-byte region
>     allocated by bpf_object__init_prog src/libbpf.c:892
>
> As controls, current cilium/ebpf rejects the normal relocation input with:
>     64bit immediate is missing second half
> while current Aya returns:
>     InvalidInstructionIndex
>
> Impact
> ------
>
> The confirmed impact is a heap out-of-bounds read on the normal relocation
> path and a heap out-of-bounds write on the poisoning path.
>
> ASan aborts on the first invalid access. I have not demonstrated
> exploitation in a production build, memory disclosure, code execution,
> privilege escalation, or kernel compromise.
>
> Proposed fix
> ------------
>
> Reject an LDIMM64 instruction when its second slot lies outside the
> program, for example:
>
>     if (is_ldimm64_insn(insn) &&
>         insn_idx + 1 >= prog->insns_cnt)
>         return -EINVAL;
>
> The check should cover both normal relocation and relocation poisoning.
>
> I applied this guard to the assessed commit and reran both ASan
> reproducers. Both completed without sanitizer findings.
>
> A regression test should cover both malformed inputs, together with a
> valid two-slot LDIMM64 control.
>
> I can provide the ELF files, full ASan logs, or help test an upstream
> patch.
>
> Regards,
> Mingpei
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.