bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [BUG] libbpf: BTF dedup merges arrays with different element types
@ 2026-09-06 10:23 Mingpei CAO
  2026-09-06 21:27 ` Alexei Starovoitov
  2026-09-07 13:10 ` [PATCH bpf 0/2] libbpf: Fix array comparison in BTF dedup Mingpei CAO
  0 siblings, 2 replies; 7+ messages in thread
From: Mingpei CAO @ 2026-09-06 10:23 UTC (permalink / raw)
  To: bpf; +Cc: andrii, eddyz87

Hello,

I found a deduplication bug in libbpf's linker. In the recursive identical
type check, libbpf obtains both array descriptors from the first type.
Arrays with the same length but different element types can therefore be
treated as identical. In a valid two-source BPF program, this changed a
CO-RE access from tls_array[0].limit0 to tls_array[0].blob and caused the
verifier to reject.

The two source files and full build and run logs are available on request.

AI assistance was used in preparing this report, I independently reviewed
the source and results.

Affected versions
-----------------

The faulty recursive array comparison was introduced in libbpf v1.6.0. I
verified it in v1.6.0, v1.6.1, v1.6.2, v1.6.3, v1.7.0, current libbpf
master, and current bpf-next as of September 6, 2026. v1.5.1 uses the
earlier two-array comparison and does not contain this root cause. No fixed
release was known at the time of testing.

Trigger conditions
------------------

The reproducer consists of two source files, cu-a.c and cu-b.c. Within each
pipeline, each file is compiled once, producing two compilation units that
are then linked. Both files define struct thread_struct___dedup_probe with
the same name, size, member names, and member offsets.

In cu-a.c, both arrays contain struct wrong_desc, whose only member is the
64-bit field blob. In cu-b.c, the first array also contains wrong_desc,
while the second contains struct desc_struct___dedup_probe, whose first
member is the 16-bit field limit0 followed by padding. Both element records
are exactly eight bytes, so no size adjustment is involved.

The BPF program is defined in cu-b.c and has one CO-RE relocation for:

    thread->tls_array[0].limit0

The first matching array establishes the hypothetical type mapping that
reaches the faulty recursive comparison for the second array.

Root cause
----------

In btf_dedup_identical_types(), the BTF_KIND_ARRAY branch at
src/btf.c:4829-4830 reads t1 twice:

    a1 = btf_array(t1);
    a2 = btf_array(t1);

btf_compat_array(t1, t2) checks common array metadata and the element
count, but intentionally leaves referenced types for the following
recursive checks. Because a1 and a2 both point into t1, their index and
element type IDs are equal, those checks are skipped, and the function
returns true without examining t2's referenced types.

The linker calls btf__dedup() from finalize_btf() in src/linker.c.

Observed results
----------------

I compiled cu-a.c and cu-b.c with clang 18.1.3. For libbpf, each source
file was compiled to one BPF ELF object before linking. For Aya, the same
two source files were compiled to LLVM bitcode before linking with
bpf-linker v0.11.0. I tested both resulting programs in an x86-64 Linux
6.8.12 QEMU guest.

The current libbpf linker collapsed the two outer records into one. The
CO-RE access string remained 0:1:0:0, but its remapped root made that
string describe tls_array[0].blob instead of tls_array[0].limit0. The
matching libbpf loader completed user-space relocation, submitted
BPF_PROG_LOAD, and the verifier rejected the poisoned unresolved CO-RE
relocation with EINVAL. This reproduced with both the BPF JIT enabled and
disabled.

Aya bpf-linker retained both outer records and the intended limit0 access.
The matching Aya loader submitted BPF_PROG_LOAD and the verifier accepted
the program with both the JIT enabled and disabled.

As a causal control, I rebuilt the libbpf linker with only the t1/t2 change
shown below. The same two input objects then retained both outer records
and the limit0 access. The matching libbpf loader accepted the program with
the JIT enabled and disabled.

Impact
------

The confirmed impact is incorrect BTF type identity and CO-RE metadata from
the libbpf linker, causing a valid multi-CU BPF program to be rejected.

Proposed fix
------------

The second array descriptor should be obtained from t2:

    a1 = btf_array(t1);
    a2 = btf_array(t2);

I applied this change to the assessed source and reran the libbpf linker and
loader controls. The output retained both types and the verifier accepted
the program.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-09-07 16:30 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-06 10:23 [BUG] libbpf: BTF dedup merges arrays with different element types Mingpei CAO
2026-09-06 21:27 ` Alexei Starovoitov
2026-09-07 13:10 ` [PATCH bpf 0/2] libbpf: Fix array comparison in BTF dedup Mingpei CAO
2026-09-07 13:10   ` [PATCH bpf 1/2] " Mingpei CAO
2026-09-07 13:10   ` [PATCH bpf 2/2] selftests/bpf: Test array element " Mingpei CAO
2026-09-07 15:45     ` Alan Maguire
2026-09-07 16:30       ` Mingpei CAO

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).