From 91c6748459855f3782d445f1a6362a20240fc14e Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 16 Sep 2026 11:43:48 -0700 Subject: objtool/klp: Add test for absolute and __ADDRESSABLE symbols A SHN_ABS symbol has no section, so any walk of sym->sec which does not check dereferences NULL, and the kernel has plenty of them -- from linker scripts and from .set in assembly. __ADDRESSABLE() emits a pointer into .discard.addressable purely to keep a symbol referenced; it means nothing to a livepatch and is discarded at link time, but it is a relocation like any other and gets looked at. Neither is what the patch changes. What this guards against is not a wrong answer but a crash or an error on input the kernel produces routinely, which would make every function near one unpatchable. Not isolated to a single line, and the test says so: the absolute symbol here has zero length, so it is excluded before the section check is reached and removing that check alone changes nothing observable. Assisted-by: Claude:claude-opus-4 Based-on-test-by: Joe Lawrence Assisted-by: Claude:claude-opus-5 Signed-off-by: Song Liu Signed-off-by: Josh Poimboeuf Signed-off-by: Ingo Molnar Link: https://patch.msgid.link/20260916184351.2720310-56-song@kernel.org --- .../tests/generic/fixtures/abs_and_addressable.c | 44 +++++++++++++++++++ .../tests/generic/test-abs-and-addressable.sh | 50 ++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 tools/objtool/tests/generic/fixtures/abs_and_addressable.c create mode 100755 tools/objtool/tests/generic/test-abs-and-addressable.sh (limited to 'tools/objtool') diff --git a/tools/objtool/tests/generic/fixtures/abs_and_addressable.c b/tools/objtool/tests/generic/fixtures/abs_and_addressable.c new file mode 100644 index 000000000000..6392ff99af42 --- /dev/null +++ b/tools/objtool/tests/generic/fixtures/abs_and_addressable.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Two constructs which appear all over the kernel and must not upset klp + * checksum or klp diff. + * + * An absolute symbol (SHN_ABS) has no section, so anything walking sym->sec + * without checking dereferences NULL. The kernel makes them with linker + * scripts and with .set in asm; VDSO and the fixed-address per-cpu bases are + * the usual sources. + * + * __ADDRESSABLE() emits a pointer into .discard.addressable purely to keep a + * symbol referenced. It is discarded at link time and means nothing to a + * livepatch, but the pointer is a relocation like any other and has to survive + * being looked at. + * + * Neither is the subject of the patch; the point is that their presence does + * not disturb the function that is. + */ + +static const char __modinfo[] + __attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux"; + +/* SHN_ABS, referenced from code. */ +extern char abs_sym[]; +__asm__(".globl abs_sym\n" + ".set abs_sym, 0x1234\n"); + +int helper(int x); +int helper(int x) { return x + 1; } + +/* The shape of __ADDRESSABLE(helper). */ +__asm__(".pushsection .discard.addressable, \"aw\"\n" + ".balign 8\n" + ".quad helper\n" + ".popsection\n"); + +int target(int x) +{ +#ifdef PATCHED + return helper(x) + (int)(long)abs_sym + 1; +#else + return helper(x) + (int)(long)abs_sym; +#endif +} diff --git a/tools/objtool/tests/generic/test-abs-and-addressable.sh b/tools/objtool/tests/generic/test-abs-and-addressable.sh new file mode 100755 index 000000000000..6adb23ed4b88 --- /dev/null +++ b/tools/objtool/tests/generic/test-abs-and-addressable.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# An absolute symbol and an __ADDRESSABLE() pointer must not disturb the +# function being patched. +# +# A SHN_ABS symbol has no section, so any walk of sym->sec which does not check +# dereferences NULL -- and the kernel has plenty, from linker scripts and from +# .set in assembly. __ADDRESSABLE() emits a pointer into .discard.addressable +# to keep a symbol referenced; it means nothing to a livepatch and is discarded +# at link time, but it is a relocation like any other and gets looked at. +# +# Neither is what the patch changes. The failure this guards against is not a +# wrong answer but a crash or an error on input the kernel produces routinely, +# which would make any function near one unpatchable. +# +# Not isolated to a single guard: the absolute symbol here has zero length, so +# it is excluded before the section check is reached and removing that check +# alone changes nothing observable. This stands as a check on the behaviour +# rather than on the line which produces it. +# +# Covers the same ground as corpus/x86_64/checksum-abs-sym-skip and +# addressable-symbols in Joe Lawrence's klp-build unit test corpus. + +. "$(dirname "$0")/../lib.sh" + +setup +build_pair abs_and_addressable.c + +# The premise: the fixture really did produce both. +in_symbols orig.o | grep -q 'ABS.*abs_sym' || + probe_skip "assembler did not make abs_sym absolute here" +assert_input_section .discard.addressable + +# Checksumming has to survive them, and still see the function that changed. +run_checksum +assert_checksum_differs target +assert_checksum_matches helper + +# So does the diff. +run_diff +assert_patched target +assert_not_patched helper + +# An absolute symbol has no address to record a checksum against, so it gets +# no entry -- the reference to it is what mattered, not the symbol itself. +in_relocs orig.o | awk '/rela\.discard\.sym_checksum/,/^$/' | grep -qw abs_sym && + fail "absolute symbol got a checksum entry" + +pass "absolute and __ADDRESSABLE symbols do not disturb the patched function" -- cgit v1.2.3