mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [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