* [PATCH] tools/resolve_btfids: fix OUTPUT leakage from kselftest causing corrupted build paths
@ 2026-07-16 8:57 Jiangshan Yi
2026-07-16 23:45 ` Ihor Solodrai
0 siblings, 1 reply; 3+ messages in thread
From: Jiangshan Yi @ 2026-07-16 8:57 UTC (permalink / raw)
To: ast, daniel, andrii, eddyz87, memxor
Cc: martin.lau, song, yonghong.song, jolsa, emil, ihor.solodrai,
paul.chaignon, bpf, linux-kernel, 13667453960, Jiangshan Yi
When building kselftest-all, the kselftest Makefile passes OUTPUT as a
command-line variable to each test directory:
tools/testing/selftests/Makefile:
$(MAKE) OUTPUT=$$BUILD/$$TARGET -C $$TARGET
GNU Make automatically exports command-line variables to all sub-makes.
This OUTPUT propagates through the entire build chain:
kselftest/mm (OUTPUT=.../selftests/mm)
-> gen_mods_dir -> page_frag (kernel module build)
-> tools/bpf/resolve_btfids (host tool dependency)
The resolve_btfids Makefile uses a conditional assignment:
OUTPUT ?= $(srctree)/tools/bpf/resolve_btfids/
However, ?= cannot override a variable inherited from a parent build's
command line or environment. The inherited OUTPUT points to the wrong
directory (the mm selftest directory) and lacks a trailing slash.
The tools/build Makefile.build system concatenates $(OUTPUT) with
filenames without a separating slash in its pattern rules:
$(OUTPUT)%.o: %.c FORCE
When OUTPUT lacks a trailing '/', this produces corrupted paths such
as ".../selftests/mmmain.o" instead of ".../selftests/mm/main.o".
Meanwhile, the resolve_btfids Makefile itself uses $(OUTPUT)/filename
(with an explicit slash), so the HOSTLD step produces the file at a
different path than where the LINK step looks for it:
HOSTLD produces: .../selftests/mmresolve_btfids-in.o (no slash)
LINK looks for: .../selftests/mm/resolve_btfids-in.o (with slash)
This results in a linker error:
ld: cannot find .../resolve_btfids-in.o: No such file or directory
Fix this by checking the origin of OUTPUT. When it is "command line"
or "environment" (indicating leakage from a parent build such as
kselftest), use 'override' to reset it to the correct directory. When
built normally via the kernel build system, OUTPUT is set by
scripts/Makefile.include with origin "file" from the O= parameter,
which is correct and remains unaffected.
The fix can be reproduced and verified with:
make -C tools/bpf/resolve_btfids clean
# Before fix: fails with corrupted paths
make OUTPUT=/path/to/selftests/mm -C tools/bpf/resolve_btfids
# After fix: succeeds, artifacts in resolve_btfids directory
# Also test environment variable leakage:
OUTPUT=/path/to/selftests/mm make -C tools/bpf/resolve_btfids
Signed-off-by: Jiangshan Yi <yijiangshan@kylinos.cn>
---
tools/bpf/resolve_btfids/Makefile | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/tools/bpf/resolve_btfids/Makefile b/tools/bpf/resolve_btfids/Makefile
index 7672208f65e4..eee88c73fd7a 100644
--- a/tools/bpf/resolve_btfids/Makefile
+++ b/tools/bpf/resolve_btfids/Makefile
@@ -26,6 +26,22 @@ HOSTAR ?= ar
HOSTPKG_CONFIG ?= pkg-config
CROSS_COMPILE =
+# If OUTPUT was inherited from a parent build's command line (e.g. from
+# kselftest), it points to the wrong directory and may lack a trailing
+# slash. The tools/build Makefile.build concatenates $(OUTPUT) with
+# filenames without a separating slash ($(OUTPUT)%.o), so a missing
+# trailing '/' produces corrupted paths such as "mmmain.o" instead of
+# "mm/main.o", and the linker cannot find resolve_btfids-in.o.
+#
+# When built via the kernel build system, OUTPUT is set by
+# scripts/Makefile.include (origin "file") from the O= parameter, which
+# is correct. Only a command-line origin indicates leakage from a
+# parent build and needs to be reset. Both "command line" and
+# "environment" origins indicate leakage; "file" (set by Makefile.include
+# from O=) and "undefined" are legitimate and must not be overridden.
+ifneq ($(filter command line environment,$(origin OUTPUT)),)
+override OUTPUT := $(srctree)/tools/bpf/resolve_btfids/
+endif
OUTPUT ?= $(srctree)/tools/bpf/resolve_btfids/
LIBBPF_SRC := $(srctree)/tools/lib/bpf/
--
2.25.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] tools/resolve_btfids: fix OUTPUT leakage from kselftest causing corrupted build paths
2026-07-16 8:57 [PATCH] tools/resolve_btfids: fix OUTPUT leakage from kselftest causing corrupted build paths Jiangshan Yi
@ 2026-07-16 23:45 ` Ihor Solodrai
2026-07-17 10:14 ` Jiangshan Yi
0 siblings, 1 reply; 3+ messages in thread
From: Ihor Solodrai @ 2026-07-16 23:45 UTC (permalink / raw)
To: Jiangshan Yi, ast, daniel, andrii, eddyz87, memxor
Cc: martin.lau, song, yonghong.song, jolsa, emil, paul.chaignon, bpf,
linux-kernel, 13667453960
On 7/16/26 1:57 AM, Jiangshan Yi wrote:
> When building kselftest-all, the kselftest Makefile passes OUTPUT as a
> command-line variable to each test directory:
>
> tools/testing/selftests/Makefile:
> $(MAKE) OUTPUT=$$BUILD/$$TARGET -C $$TARGET
>
> GNU Make automatically exports command-line variables to all sub-makes.
> This OUTPUT propagates through the entire build chain:
>
> kselftest/mm (OUTPUT=.../selftests/mm)
> -> gen_mods_dir -> page_frag (kernel module build)
> -> tools/bpf/resolve_btfids (host tool dependency)
>
> The resolve_btfids Makefile uses a conditional assignment:
>
> OUTPUT ?= $(srctree)/tools/bpf/resolve_btfids/
>
> However, ?= cannot override a variable inherited from a parent build's
> command line or environment. The inherited OUTPUT points to the wrong
> directory (the mm selftest directory) and lacks a trailing slash.
>
> The tools/build Makefile.build system concatenates $(OUTPUT) with
> filenames without a separating slash in its pattern rules:
>
> $(OUTPUT)%.o: %.c FORCE
>
> When OUTPUT lacks a trailing '/', this produces corrupted paths such
> as ".../selftests/mmmain.o" instead of ".../selftests/mm/main.o".
> Meanwhile, the resolve_btfids Makefile itself uses $(OUTPUT)/filename
> (with an explicit slash), so the HOSTLD step produces the file at a
> different path than where the LINK step looks for it:
>
> HOSTLD produces: .../selftests/mmresolve_btfids-in.o (no slash)
> LINK looks for: .../selftests/mm/resolve_btfids-in.o (with slash)
>
> This results in a linker error:
>
> ld: cannot find .../resolve_btfids-in.o: No such file or directory
>
> Fix this by checking the origin of OUTPUT. When it is "command line"
> or "environment" (indicating leakage from a parent build such as
> kselftest), use 'override' to reset it to the correct directory. When
> built normally via the kernel build system, OUTPUT is set by
> scripts/Makefile.include with origin "file" from the O= parameter,
> which is correct and remains unaffected.
>
> The fix can be reproduced and verified with:
>
> make -C tools/bpf/resolve_btfids clean
> # Before fix: fails with corrupted paths
> make OUTPUT=/path/to/selftests/mm -C tools/bpf/resolve_btfids
> # After fix: succeeds, artifacts in resolve_btfids directory
>
> # Also test environment variable leakage:
> OUTPUT=/path/to/selftests/mm make -C tools/bpf/resolve_btfids
>
> Signed-off-by: Jiangshan Yi <yijiangshan@kylinos.cn>
> ---
> tools/bpf/resolve_btfids/Makefile | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/tools/bpf/resolve_btfids/Makefile b/tools/bpf/resolve_btfids/Makefile
> index 7672208f65e4..eee88c73fd7a 100644
> --- a/tools/bpf/resolve_btfids/Makefile
> +++ b/tools/bpf/resolve_btfids/Makefile
> @@ -26,6 +26,22 @@ HOSTAR ?= ar
> HOSTPKG_CONFIG ?= pkg-config
> CROSS_COMPILE =
>
> +# If OUTPUT was inherited from a parent build's command line (e.g. from
> +# kselftest), it points to the wrong directory and may lack a trailing
> +# slash. The tools/build Makefile.build concatenates $(OUTPUT) with
> +# filenames without a separating slash ($(OUTPUT)%.o), so a missing
> +# trailing '/' produces corrupted paths such as "mmmain.o" instead of
> +# "mm/main.o", and the linker cannot find resolve_btfids-in.o.
> +#
> +# When built via the kernel build system, OUTPUT is set by
> +# scripts/Makefile.include (origin "file") from the O= parameter, which
> +# is correct. Only a command-line origin indicates leakage from a
> +# parent build and needs to be reset. Both "command line" and
> +# "environment" origins indicate leakage; "file" (set by Makefile.include
> +# from O=) and "undefined" are legitimate and must not be overridden.
> +ifneq ($(filter command line environment,$(origin OUTPUT)),)
> +override OUTPUT := $(srctree)/tools/bpf/resolve_btfids/
> +endif
> OUTPUT ?= $(srctree)/tools/bpf/resolve_btfids/
This seems to be a real bug, but the proposed diff is just wrong.
It doesn't even fix the case you target.
The `override` runs in the outer make, but the corruption happens in
the nested sub-make (resolve_btfids/Makefile:105):
$(BINARY_IN): fixdep FORCE prepare | $(OUTPUT)
$(Q)$(MAKE) $(build)=resolve_btfids
Try this:
$ cat parent.mk
ifneq ($(filter command line environment,$(origin OUTPUT)),)
override OUTPUT := /correct/
endif
export OUTPUT
all: ; @$(MAKE) --no-print-directory -f child.mk
$ cat child.mk
all: ; @echo "OUTPUT=[$(OUTPUT)] -> $(OUTPUT)main.o"
$ make -f parent.mk OUTPUT=/leaked/mm
OUTPUT=[/leaked/mm] -> /leaked/mmmain.o # override invisible; still broken
Your standalone repro probably only succeeds on a dirty tree.
Have you tried testing from clean?
Also bpf/Makefile:440 and hid/Makefile:159 deliberately pass
OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/ on the command line.
And so the patch breaks those too:
$ mkdir -p /tmp/o/resolve_btfids && make -C tools/bpf/resolve_btfids clean \
&& make -C tools/bpf/resolve_btfids OUTPUT=/tmp/o/resolve_btfids/
...
make[1]: *** No rule to make target '.../resolve_btfids/fixdep'. Stop.
make: *** [.../tools/build/Makefile.include:15: fixdep] Error 2
I think a proper fix is to figure out a way to avoid generic OUTPUT to
fall through to resolve_btids (somewhere in selftests/lib.mk
probably).
Please make sure to test your change properly before submitting.
pw-bot: cr
>
> LIBBPF_SRC := $(srctree)/tools/lib/bpf/
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Re: [PATCH] tools/resolve_btfids: fix OUTPUT leakage from kselftest causing corrupted build paths
2026-07-16 23:45 ` Ihor Solodrai
@ 2026-07-17 10:14 ` Jiangshan Yi
0 siblings, 0 replies; 3+ messages in thread
From: Jiangshan Yi @ 2026-07-17 10:14 UTC (permalink / raw)
To: ihor.solodrai
Cc: 13667453960, andrii, ast, bpf, daniel, eddyz87, emil, jolsa,
linux-kernel, martin.lau, memxor, paul.chaignon, song,
yijiangshan, yonghong.song
Hi Ihor Solodrai,
Thanks for the review -- you are right on both counts, and v1 is dropped.
On the nested sub-make: the `override OUTPUT :=` only changes the
variable inside the outer resolve_btfids make; it does not touch
MAKEOVERRIDES, so the nested `$(MAKE) $(build)=resolve_btfids`
(resolve_btfids/Makefile:90) still inherits the original command-line
OUTPUT through MAKEFLAGS. The pattern rules that produce the corrupted
`$(OUTPUT)%.o` paths run in that nested sub-make, so they still see the
un-slashed value. Your parent.mk/child.mk repro captures this exactly.
On bpf/hid: selftests/bpf/Makefile:440 and selftests/hid/Makefile:159
build resolve_btfids directly with
`OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/` on the command line. An
origin check cannot tell those deliberate command-line assignments apart
from a leaked one, so v1 clobbered them -- exactly the breakage you
showed. The origin is simply the wrong place to make this decision.
v2 takes the approach you suggested: drop the generic kselftest OUTPUT
at the gen_mods_dir descent in selftests/lib.mk, so it never reaches the
kernel module build (and thus resolve_btfids) as a command-line
variable:
gen_mods_dir: MAKEOVERRIDES := $(filter-out OUTPUT=%,$(MAKEOVERRIDES))
gen_mods_dir:
$(Q)$(MAKE) -C $(TEST_GEN_MODS_DIR)
clean_mods_dir: MAKEOVERRIDES := $(filter-out OUTPUT=%,$(MAKEOVERRIDES))
clean_mods_dir:
$(Q)$(MAKE) -C $(TEST_GEN_MODS_DIR) clean
gen_mods_dir is the only path through which kselftest's per-test OUTPUT
leaks into a kernel build (the TEST_GEN_MODS_DIR module build, which can
the other selftest sub-makes -- and the test programs that rely on
OUTPUT -- are unaffected.
With the leaked command-line OUTPUT gone, resolve_btfids is reached with
only the O= that the kernel build passes on its tools/% descent, so the
`OUTPUT := $(ABSOLUTE_O)/...` assignment in scripts/Makefile.include (a
simple assignment) wins at every make level, including the nested
`$(build)=resolve_btfids` sub-make where the pattern rules run. bpf and
hid invoke resolve_btfids directly with their own OUTPUT= and do not go
through gen_mods_dir, so they are untouched.
Tested from a clean tree:
* kselftest build of a TEST_GEN_MODS_DIR test (mm/page_frag) with
CONFIG_DEBUG_INFO_BTF: resolve_btfids now builds into its
O=-derived directory; no more "mmmain.o" / missing
resolve_btfids-in.o.
* make -C tools/bpf/resolve_btfids
make -C tools/bpf/resolve_btfids OUTPUT=/tmp/o/resolve_btfids/
both still build (bpf/hid-style explicit OUTPUT= preserved).
* make OUTPUT=/tmp/build/kcmp -C tools/testing/selftests/kcmp still
honours OUTPUT for its own programs.
v2 posted as a separate thread.
Thanks,
Jiangshan
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-17 10:14 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-16 8:57 [PATCH] tools/resolve_btfids: fix OUTPUT leakage from kselftest causing corrupted build paths Jiangshan Yi
2026-07-16 23:45 ` Ihor Solodrai
2026-07-17 10:14 ` Jiangshan Yi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox