diff options
| author | Ulises Mendez Martinez <umendez@google.com> | 2026-09-04 15:07:09 +0000 |
|---|---|---|
| committer | Josh Poimboeuf <jpoimboe@kernel.org> | 2026-09-13 18:15:43 -0700 |
| commit | 7e61560628d17ea6b1d8ee370f6d42694cff8758 (patch) | |
| tree | e6080164b2f4c4c419894bdb3ce4d956ca9a98c5 /lib/test_fortify | |
| download | linux-stable-7e61560628d17ea6b1d8ee370f6d42694cff8758.tar.gz linux-stable-7e61560628d17ea6b1d8ee370f6d42694cff8758.zip | |
objtool: Validate disassembler headers in libopcodes probegrafted
commit 3f2de814c059 ("objtool: Fix libopcodes linking with static libraries")
tested for libopcodes availability by linking a test snippet with a forward
declaration of disassemble_init_for_target().
However, testing symbol linkage with an extern declaration only verifies
the presence of the library (.so/.a) and bypasses checking for development
headers (binutils-dev). On systems where libopcodes is present without
development headers installed, the probe succeeds, enabling BUILD_DISAS.
Subsequent compilation of objtool then fails:
fatal error: 'bfd.h' file not found
113 | #include <bfd.h>
Additionally, the probe invokes $(HOSTCC) without $(HOSTCFLAGS), ignoring
any sysroot or include flags specified for the host compiler.
Fix this by including <bfd.h> and <dis-asm.h> directly in the test snippet,
passing $(HOSTCFLAGS) so host compiler options are respected, and defining
PACKAGE="objtool" to satisfy the configuration check in <bfd.h>.
Fixes: 3f2de814c059 ("objtool: Fix libopcodes linking with static libraries")
Fixes: 436326bc525d ("objtool: fix build failure due to missing libopcodes check")
Reported-by: Alice Ryhl <aliceryhl@google.com>
Assisted-by: Antigravity:Gemini-Next
Signed-off-by: Ulises Mendez Martinez <umendez@google.com>
Link: https://patch.msgid.link/20260904150710.2997558-1-umendez@google.com
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Diffstat (limited to 'lib/test_fortify')
22 files changed, 219 insertions, 0 deletions
diff --git a/lib/test_fortify/.gitignore b/lib/test_fortify/.gitignore new file mode 100644 index 000000000..c1ba37d14 --- /dev/null +++ b/lib/test_fortify/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +/*.log diff --git a/lib/test_fortify/Makefile b/lib/test_fortify/Makefile new file mode 100644 index 000000000..44cd5df41 --- /dev/null +++ b/lib/test_fortify/Makefile @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0 + +ccflags-y := $(call cc-disable-warning,fortify-source) +ccflags-y += $(call cc-disable-warning,stringop-overread) + +quiet_cmd_test_fortify = TEST $@ + cmd_test_fortify = $(CONFIG_SHELL) $(src)/test_fortify.sh \ + $< $@ "$(NM)" $(CC) $(c_flags) -DKBUILD_EXTRA_WARN1 + +$(obj)/%.log: $(src)/%.c $(src)/test_fortify.sh FORCE + $(call if_changed_dep,test_fortify) + +logs = $(patsubst $(src)/%.c, %.log, $(wildcard $(src)/*-*.c)) +targets += $(logs) + +quiet_cmd_gen_fortify_log = CAT $@ + cmd_gen_fortify_log = cat $(or $(real-prereqs),/dev/null) > $@ + +$(obj)/test_fortify.log: $(addprefix $(obj)/, $(logs)) FORCE + $(call if_changed,gen_fortify_log) + +always-y += test_fortify.log + +# Some architectures define __NO_FORTIFY if __SANITIZE_ADDRESS__ is undefined. +# Pass CFLAGS_KASAN to avoid warnings. +KASAN_SANITIZE := y diff --git a/lib/test_fortify/read_overflow-memchr.c b/lib/test_fortify/read_overflow-memchr.c new file mode 100644 index 000000000..2743084b3 --- /dev/null +++ b/lib/test_fortify/read_overflow-memchr.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memchr(small, 0x7A, sizeof(small) + 1) + +#include "test_fortify.h" diff --git a/lib/test_fortify/read_overflow-memchr_inv.c b/lib/test_fortify/read_overflow-memchr_inv.c new file mode 100644 index 000000000..b26e1f1bc --- /dev/null +++ b/lib/test_fortify/read_overflow-memchr_inv.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memchr_inv(small, 0x7A, sizeof(small) + 1) + +#include "test_fortify.h" diff --git a/lib/test_fortify/read_overflow-memcmp.c b/lib/test_fortify/read_overflow-memcmp.c new file mode 100644 index 000000000..d5d301ff6 --- /dev/null +++ b/lib/test_fortify/read_overflow-memcmp.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcmp(small, large, sizeof(small) + 1) + +#include "test_fortify.h" diff --git a/lib/test_fortify/read_overflow-memscan.c b/lib/test_fortify/read_overflow-memscan.c new file mode 100644 index 000000000..c1a97f2df --- /dev/null +++ b/lib/test_fortify/read_overflow-memscan.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memscan(small, 0x7A, sizeof(small) + 1) + +#include "test_fortify.h" diff --git a/lib/test_fortify/read_overflow2-memcmp.c b/lib/test_fortify/read_overflow2-memcmp.c new file mode 100644 index 000000000..c6091e640 --- /dev/null +++ b/lib/test_fortify/read_overflow2-memcmp.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcmp(large, small, sizeof(small) + 1) + +#include "test_fortify.h" diff --git a/lib/test_fortify/read_overflow2-memcpy.c b/lib/test_fortify/read_overflow2-memcpy.c new file mode 100644 index 000000000..07b62e56c --- /dev/null +++ b/lib/test_fortify/read_overflow2-memcpy.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcpy(large, instance.buf, sizeof(large)) + +#include "test_fortify.h" diff --git a/lib/test_fortify/read_overflow2-memmove.c b/lib/test_fortify/read_overflow2-memmove.c new file mode 100644 index 000000000..34edfab04 --- /dev/null +++ b/lib/test_fortify/read_overflow2-memmove.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memmove(large, instance.buf, sizeof(large)) + +#include "test_fortify.h" diff --git a/lib/test_fortify/read_overflow2_field-memcpy.c b/lib/test_fortify/read_overflow2_field-memcpy.c new file mode 100644 index 000000000..de9569266 --- /dev/null +++ b/lib/test_fortify/read_overflow2_field-memcpy.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcpy(large, instance.buf, sizeof(instance.buf) + 1) + +#include "test_fortify.h" diff --git a/lib/test_fortify/read_overflow2_field-memmove.c b/lib/test_fortify/read_overflow2_field-memmove.c new file mode 100644 index 000000000..6cc2724c8 --- /dev/null +++ b/lib/test_fortify/read_overflow2_field-memmove.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memmove(large, instance.buf, sizeof(instance.buf) + 1) + +#include "test_fortify.h" diff --git a/lib/test_fortify/test_fortify.h b/lib/test_fortify/test_fortify.h new file mode 100644 index 000000000..d22664fff --- /dev/null +++ b/lib/test_fortify/test_fortify.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <linux/kernel.h> +#include <linux/printk.h> +#include <linux/slab.h> +#include <linux/string.h> + +void do_fortify_tests(void); + +#define __BUF_SMALL 16 +#define __BUF_LARGE 32 +struct fortify_object { + int a; + char buf[__BUF_SMALL]; + int c; +}; + +#define LITERAL_SMALL "AAAAAAAAAAAAAAA" +#define LITERAL_LARGE "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +const char small_src[__BUF_SMALL] = LITERAL_SMALL; +const char large_src[__BUF_LARGE] = LITERAL_LARGE; + +char small[__BUF_SMALL]; +char large[__BUF_LARGE]; +struct fortify_object instance; +size_t size; + +void do_fortify_tests(void) +{ + /* Normal initializations. */ + memset(&instance, 0x32, sizeof(instance)); + memset(small, 0xA5, sizeof(small)); + memset(large, 0x5A, sizeof(large)); + + TEST; +} diff --git a/lib/test_fortify/test_fortify.sh b/lib/test_fortify/test_fortify.sh new file mode 100644 index 000000000..ad6dd44fa --- /dev/null +++ b/lib/test_fortify/test_fortify.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +set -e + +# Argument 1: Source file to build. +IN="$1" +shift +# Extract just the filename for error messages below. +FILE="${IN##*/}" +# Extract the function name for error messages below. +FUNC="${FILE#*-}" +FUNC="${FUNC%%-*}" +FUNC="${FUNC%%.*}" +# Extract the symbol to test for in build/symbol test below. +WANT="__${FILE%%-*}" + +# Argument 2: Where to write the build log. +OUT="$1" +shift +TMP="${OUT%/*}/.${OUT##*/}.tmp" + +# Argument 3: Path to "nm" tool. +NM="$1" +shift + +# Remaining arguments are: $(CC) $(c_flags) + +# Clean up temporary file at exit. +__cleanup() { + rm -f "$TMP" +} +trap __cleanup EXIT HUP INT QUIT TERM + +# Function names in warnings are wrapped in backticks under UTF-8 locales. +# Run the commands with LANG=C so that grep output will not change. +export LANG=C + +status= +# Attempt to build a source that is expected to fail with a specific warning. +if "$@" -Werror -c "$IN" -o "$OUT".o 2> "$TMP" ; then + # If the build succeeds, either the test has failed or the + # warning may only happen at link time (Clang). In that case, + # make sure the expected symbol is unresolved in the symbol list. + # If so, FORTIFY is working for this case. + if ! $NM -A "$OUT".o | grep -m1 "\bU ${WANT}$" >>"$TMP" ; then + status="warning: unsafe ${FUNC}() usage lacked '$WANT' symbol in $IN" + fi +else + # If the build failed, check for the warning in the stderr. + # GCC: + # ./include/linux/fortify-string.h:316:25: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] + # Clang 14: + # ./include/linux/fortify-string.h:316:4: error: call to __write_overflow_field declared with 'warning' attribute: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror,-Wattribute-warning] + if ! grep -Eq -m1 "error: call to .?\b${WANT}\b.?" "$TMP" ; then + status="warning: unsafe ${FUNC}() usage lacked '$WANT' warning in $IN" + fi +fi + +if [ -n "$status" ]; then + # Report on failure results, including compilation warnings. + echo "$status" | tee "$OUT" >&2 +else + # Report on good results, and save any compilation output to log. + echo "ok: unsafe ${FUNC}() usage correctly detected with '$WANT' in $IN" >"$OUT" +fi +cat "$TMP" >>"$OUT" diff --git a/lib/test_fortify/write_overflow-memcpy.c b/lib/test_fortify/write_overflow-memcpy.c new file mode 100644 index 000000000..3b3984e42 --- /dev/null +++ b/lib/test_fortify/write_overflow-memcpy.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcpy(instance.buf, large_src, sizeof(large_src)) + +#include "test_fortify.h" diff --git a/lib/test_fortify/write_overflow-memmove.c b/lib/test_fortify/write_overflow-memmove.c new file mode 100644 index 000000000..640437c3b --- /dev/null +++ b/lib/test_fortify/write_overflow-memmove.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memmove(instance.buf, large_src, sizeof(large_src)) + +#include "test_fortify.h" diff --git a/lib/test_fortify/write_overflow-memset.c b/lib/test_fortify/write_overflow-memset.c new file mode 100644 index 000000000..36e34908c --- /dev/null +++ b/lib/test_fortify/write_overflow-memset.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memset(instance.buf, 0x5A, sizeof(large_src)) + +#include "test_fortify.h" diff --git a/lib/test_fortify/write_overflow-strcpy-lit.c b/lib/test_fortify/write_overflow-strcpy-lit.c new file mode 100644 index 000000000..51effb3e5 --- /dev/null +++ b/lib/test_fortify/write_overflow-strcpy-lit.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + strcpy(small, LITERAL_LARGE) + +#include "test_fortify.h" diff --git a/lib/test_fortify/write_overflow-strcpy.c b/lib/test_fortify/write_overflow-strcpy.c new file mode 100644 index 000000000..84f1c56a6 --- /dev/null +++ b/lib/test_fortify/write_overflow-strcpy.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + strcpy(small, large_src) + +#include "test_fortify.h" diff --git a/lib/test_fortify/write_overflow-strscpy.c b/lib/test_fortify/write_overflow-strscpy.c new file mode 100644 index 000000000..38feddf37 --- /dev/null +++ b/lib/test_fortify/write_overflow-strscpy.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + strscpy(instance.buf, large_src, sizeof(instance.buf) + 1) + +#include "test_fortify.h" diff --git a/lib/test_fortify/write_overflow_field-memcpy.c b/lib/test_fortify/write_overflow_field-memcpy.c new file mode 100644 index 000000000..28cc81058 --- /dev/null +++ b/lib/test_fortify/write_overflow_field-memcpy.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcpy(instance.buf, large, sizeof(instance.buf) + 1) + +#include "test_fortify.h" diff --git a/lib/test_fortify/write_overflow_field-memmove.c b/lib/test_fortify/write_overflow_field-memmove.c new file mode 100644 index 000000000..377fcf9bb --- /dev/null +++ b/lib/test_fortify/write_overflow_field-memmove.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memmove(instance.buf, large, sizeof(instance.buf) + 1) + +#include "test_fortify.h" diff --git a/lib/test_fortify/write_overflow_field-memset.c b/lib/test_fortify/write_overflow_field-memset.c new file mode 100644 index 000000000..2331da269 --- /dev/null +++ b/lib/test_fortify/write_overflow_field-memset.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memset(instance.buf, 0x42, sizeof(instance.buf) + 1) + +#include "test_fortify.h" |
