Re: [PATCH v3 bpf-next 1/7] resolve_btfids: Build separate main and inline BTF objects
flat view
From: bot+bpf-ci@kernel.org
Date: 2026-10-03 20:27:13
Also in:
bpf
resolve_btfids: Build separate main and inline BTF objects
TL;DR: In resolve_btfids --inline, extract_inline_btf() may free a base BTF that the new main BTF still points to, causing a possible use-after-free for modules with .BTF.base; in-tree builds seem unaffected.
quoted hunk ↗ jump to hunk
diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c index 37d7e7224207..dcd289d16faf 100644 --- a/tools/bpf/resolve_btfids/main.c +++ b/tools/bpf/resolve_btfids/main.c
[ ... ]
quoted hunk ↗ jump to hunk
@@ -1510,6 +1569,85 @@ static int btf2btf(struct object *obj) return err; }
[ ... ]
quoted hunk ↗ jump to hunk
+static int extract_inline_btf(struct object *obj) +{ + struct btf *btf = obj->btf, *main_btf, *inline_btf; + __u32 type_cnt = btf__type_cnt(btf); + __u8 *colors; + int err; + + colors = calloc(type_cnt, sizeof(*colors)); + if (!colors) + return -ENOMEM; + err = color_btf(obj, colors); + if (err) + goto out; + err = btf_split_by_color(btf, colors, &main_btf, &inline_btf); + if (!err) { + obj->btf = main_btf; + obj->inline_btf = inline_btf; + btf__free(btf);
^^^^
Can this btf__free(btf) free a base BTF that the new obj->btf still points
to?
btf_split_by_color() creates main_btf with .base_btf set to
btf__base_btf(src), and btf_new_empty() stores that pointer without taking
ownership. btf__free() on the source also frees its base when the source
owns it:
if (btf->owns_base)
btf__free(btf->base_btf);
libbpf sets owns_base in btf_parse_elf() when the ELF passed to
btf__parse_split() has a .BTF.base section and no base_btf was given.
This looks reachable with "resolve_btfids --inline mod.ko" (no --btf_base,
no --btf) on an out-of-tree module that already has .BTF, .BTF.base and
.BTF_ids:
load_btf()
btf__parse_split(obj->path, NULL)
owns_base = true, obj->base_btf stays NULL
finalize_btf()
distill is skipped because obj->base_btf is NULL
sort_btf_by_name()
extract_inline_btf()
btf__free(btf)
also frees the distilled base that main_btf->base_btf points to
main()
symbols_resolve()
btf__type_by_id(obj->btf, ...)
btf_type_by_id(btf->base_btf, type_id)
reads freed memory
Without --inline the same command works, because obj->btf keeps owning its
base until main() frees it.
The in-tree build does not appear to be affected, since gen-btf.sh passes a
raw --btf file together with --btf_base, which leaves owns_base false. I did
not find a fix for this later in the series.
Should extract_inline_btf() keep the original BTF alive, for example in a
field of struct object that main() frees after obj->btf? Alternatively,
could it reject or handle the case where btf__base_btf(obj->btf) is set but
obj->base_btf is NULL?
quoted hunk ↗ jump to hunk
+ } +out: + free(colors); + return err; +}
[ ... ] --- AI reviewed your patch. Please fix the bug or email reply why it's not a bug. See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md CI run summary: https://github.com/kernel-patches/bpf/actions/runs/37149955093