| Age | Commit message (Collapse) | Author |
|
A file-local symbol which ThinLTO has to make visible is renamed
helper.llvm.<hash>. With two such helpers in one link, the original and
the patched object hold two each, all four spelled differently, and
demangling gives "helper" for every one of them -- so the name alone cannot
say which corresponds to which.
Three translation units, two with a static helper of the same name and a
third calling into both, which is what forces the promotion. Only one
helper changes: paired correctly that means exactly one is cloned, and
paired the wrong way round the other is, or both are. Had both bodies
changed, both would be cloned either way and the test would prove nothing
-- which is how the first version of this was written.
The outcome is asserted, not the machinery. With the clang tested here the
pairing survives disabling the .llvm.<hash> suffix map and stubbing out
llvm_suffix() entirely, so no single-line sabotage distinguishes it; the
tiered matcher this case was written for is not needed for this shape. The
test says so rather than implying otherwise.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-59-song@kernel.org
|
|
For a dense enough switch Clang emits the targets as a table in
.rodata..Lswitch.table.<function> -- named after the function but not part
of it. The patched function indexes into that table, so a clone which does
not bring it along jumps through whatever the kernel's copy holds, which
after a patch that changed the switch is the wrong set of targets. An
indirect jump to a stale address reports nothing at build or load time.
The fixture asserts its own premise twice over, since both halves depend on
what this Clang chose to do: that a table was built rather than a chain of
comparisons, and that the added case actually changed it.
objtool has no switch-specific code -- the table is carried by the general
mechanism for data a cloned function references -- so this guards that
mechanism reaching an easily-mishandled shape rather than a particular
line, and the test says so. Making the table uncorrelated, the nearest
available sabotage, does not change the outcome.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-58-song@kernel.org
|
|
Every instrumented operation gets a per-callsite metadata object in an
anonymous data section -- .data..Lubsan_data and .data..Lubsan_type from
GCC, .data..L__unnamed_ from Clang -- whose names are compiler-generated
and mean nothing across a rebuild. is_uncorrelated_section() exists so klp
diff does not try to pair them up, and nothing tested it.
The failure it prevents is a false positive, which is the direction this
suite has least coverage of. Metadata belonging to a function nobody
touched compares as different and drags that function into the patch. That
is not a build failure: it is a larger livepatch than intended, pulling in
dependencies with it, and every extra function is one more that can fail to
correlate or to apply.
The fixture is built with -fsanitize=shift, which both compilers
instrument; neither emits a bounds check for an index it can prove in
range. One function changes, the other is byte-identical and carries
instrumentation of its own, and the test asserts the second is left alone.
Verified by removing each rule from is_uncorrelated_section() in turn,
which splits neatly by toolchain: dropping the .data..Lubsan rule fails the
test under gcc, dropping .data..L__unnamed_ fails it under clang. One
test, two code paths, each checked by the compiler that reaches it.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-57-song@kernel.org
|
|
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 <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-56-song@kernel.org
|
|
klp diff needs entry boundaries for a special section: either an entsize,
or ANNOTATE_DATA_SPECIAL annotations naming where each entry starts.
.static_call_sites has no entsize, so the annotations are all there is --
and a patch can remove the last one in a translation unit while leaving the
section itself in place, so that only the patched side has lost them.
The section still has to be handled. Dropping it leaves the patched
function's static call unregistered; misreading its boundaries attaches the
entry to the wrong code. Neither is reported at build time.
Give the fixture a NO_ANNOTATE knob and assert the premise -- annotation
present in the original, absent in the patched object, section present in
both -- before asserting the result.
Fixed by commit 3de711fba73a ("objtool/klp: Fix create_fake_symbols()
skipping entsize-based sections"). Verified by making klp diff skip
.static_call_sites when cloning special sections: the test fails.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-55-song@kernel.org
|
|
A cloned data section has to keep its sh_addralign. Plenty of kernel data
is aligned for correctness rather than speed -- per-CPU variables, anything
touched by an aligned vector move, structures padded to own a cacheline --
and a clone that lands under-aligned either faults on first use or silently
shares a line it was laid out to avoid. Neither shows up until the patch
is loaded on hardware that cares.
The fixture's data is new in the patched build, so klp diff has to clone it
rather than reference the kernel's copy, and it asserts that premise before
asserting the result.
Commit 2f2600decb30 ("objtool/klp: fix data alignment in __clone_symbol()")
cannot be reverted to check this -- the revert is a no-op against the
current code, which has been rewritten since. Verified instead by forcing
the clone's alignment to 1, which the test reports as "alignment 1,
expected 64".
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-54-song@kernel.org
|
|
checksum_update_insn() hashes an instruction's bytes and then what any
relocation on it refers to: a string section contributes the string's
contents, anything else the target symbol's name and adjusted addend, with
a reference to a static resolved through its section symbol first.
None of that shows up in the bytes. A rel32 operand is zero in the object
and supplied by the relocation, so calling a different function, editing a
literal the code passes, or reading a different index of an array all leave
the encoded instruction byte-identical. A checksum stopping at the bytes
reports the function unchanged and the patch silently does not contain the
fix.
test-checksum-position is the other half: what must *not* change the
checksum when a function merely moves.
Each of the four is verified by sabotaging the line it covers. The static
case needed a writer the compiler cannot see through -- without one it
proves the array is never written, folds every read to zero, and emits no
relocation at all, so the reference under test does not exist and the
variant passes having compared two identical objects.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-52-song@kernel.org
|
|
The counterpart to the static branch case: a patch may add a static call to
a function which had none, so the .static_call_sites entry is new and there
is nothing in the original to correlate it against.
Where the key lives still decides whether that is allowed. A vmlinux key
is reachable; a module-owned one is not, for the same reason an existing
module key is not -- late module patching lets the livepatch load first and
the unresolved entry is dereferenced when the module arrives. Both halves
are here because they fail in opposite directions: dropping the new entry
leaves a static call the kernel never patches, and accepting a new
module-owned one is the corruption the check exists to prevent.
Both halves are one test over one fixture: built with -DNEW_CALL the key is
vmlinux's and the new entry has to be carried in; built with -DMODNAME as
well the key belongs to a module, klp diff has to reject it, and no output
object may be left behind. The premise is asserted first -- the original
must have no .static_call_sites at all -- since otherwise this is a second
copy of test-static-call-module-key.
Covers the same ground as corpus/x86_64/static-call-vmlinux-new and
corpus/x86_64/static-call-module-new in Joe Lawrence's klp-build unit test
corpus.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-51-song@kernel.org
|
|
A module-owned static branch key is normally fatal, because late module
patching lets the livepatch load before the module it depends on and
jump_label_add_module() then dereferences an unresolved entry.
Tracepoints and pr_debug() generate such keys everywhere, so refusing them
outright would make any function containing a trace_*() call or a
pr_debug() unpatchable. klp diff drops the entry, warns, and carries on:
the patched code works with that one tracepoint or debug print permanently
off.
Both halves matter, and the test asserts both. A build which fails is a
function nobody can patch; an entry left in place is the corruption the
rejection exists to prevent.
Give the fixture a KEY_NAME knob so the same static branch can be built
with either special name. Verified by removing each exemption in turn --
the test fails for both. That the entry is then dropped is asserted but
not isolated, and the test says so.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-50-song@kernel.org
|
|
Patching a function which already has a static branch and adding one to a
function which had none are different cases. In the second the
__jump_table entry is itself new, so there is nothing in the original to
correlate it against: klp diff has to carry the entry into the patch from
scratch and reach the key the way it reaches any other vmlinux symbol.
Dropping it is silent. The patched function keeps a static branch the
kernel never patches, so it takes the same arm forever whatever the key is
set to.
Give the fixture a NEW_KEY knob which puts the whole branch behind PATCHED,
and assert the premise -- that the original really has no __jump_table --
before asserting the result, since otherwise this is just a second copy of
test-jump-label-key.
Verified by making klp diff skip __jump_table when cloning special
sections: the test fails.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-49-song@kernel.org
|
|
.discard.sym_checksum is an array of { address, checksum } looked up by the
address a relocation points at, so the invariant is one entry per address.
calculate_checksums() skips zero-length symbols, aliases and cold parts to
keep it, and nothing checked that it does.
A duplicate entry is not a build failure. It makes the lookup ambiguous,
and whichever checksum loses is never consulted again -- so a function
whose code changed can be read as unchanged and dropped from the patch.
The alias skip is verified the usual way: remove it and the test fails.
The other two are not isolated, and the test says so rather than implying
otherwise. A zero-length symbol is excluded by several of the guards at
once -- its section has no data either -- so removing any one of them
changes nothing observable; the assertion stands as a check on the
behaviour, not on the line that produces it. The cold-part skip needs a
compiler that splits functions and is not reached here at all.
Which of an aliased pair keeps the entry falls out of symbol table order,
so the test requires exactly one of the two rather than naming a winner --
as written first it named real_function and failed, because gcc kept the
alias.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-48-song@kernel.org
|
|
klp checksum hashes a data symbol's length, its bytes, and every relocation
it carries -- as the target's name and adjusted addend, except a reference
into a string section, which contributes the string's contents instead.
Nothing covered any of it.
Each is load-bearing, and the failure is always the same shape: a checksum
which ignores one calls a changed object unchanged, klp diff leaves it out
of the patch, and the patched code goes on reading the kernel's old copy.
The string case cannot be caught by hashing bytes: the pointer is
identical, same section and same offset, and only the text it refers to
moved.
One fixture, six variants applied to the patched build alone. Each was
verified by sabotaging the line it covers and watching the test fail:
raw bytes initialiser change
length a .bss object grows; its bytes are never hashed
string contents literal edited in place, pointer untouched
reloc target name pointer moved to another function
reloc addend same array, different index
section-symbol path the same, via a static's section symbol
Two of those needed the fixture rebuilding. An initialised array does not
isolate the length, because growing one changes the hashed bytes too --
hence .bss, where there are none. And a named char[] does not reach the
contents-hashing path at all: that keys on SHF_STRINGS, which the compiler
sets on the mergeable section a literal lands in and not on an array given
a section of its own.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-47-song@kernel.org
|
|
A static branch key owned by a module cannot be reached with a klp reloc:
late module patching allows the livepatch module to load first, leaving the
__jump_table entry unresolved for jump_label_add_module() to dereference.
validate_special_section_klp_reloc() rejects it at build time.
test-jump-label-module-key covers that for a global key. A file-local one
takes a different route to the same check: the compiler references a static
through its section symbol plus an addend, so the key has to be resolved
from the section before it can be recognised as STT_OBJECT at all. Until
commit f9fb44b0ecef ("objtool/klp: Fix detection of corrupt static
branch/call entries") it was not, and the reference was silently emitted.
Give the fixture a STATIC_KEY knob and cover it. The test checks that the
input really does reference the key through its section, since without that
it is only a second copy of the existing test.
Verified by reverting commit f9fb44b0ecef ("objtool/klp: Fix detection of
corrupt static branch/call entries"): klp diff accepts the input and the
test fails, under both gcc and clang.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-44-song@kernel.org
|
|
A patch can move a symbol between static and global without renaming it:
dropping "static" from a helper so something else can call it, or adding it
to one that is no longer shared. Correlation keys off more than the name,
so a symbol whose binding moved has to still pair with itself.
Failing to is not a build failure. The symbol looks new, and a new data
symbol is either rejected or cloned as a second copy -- at which point the
patched code updates its own private variable while the rest of the kernel
keeps reading the original.
The test covers both directions in one fixture, a function going global and
a variable going static, and asserts the outcome rather than the absence of
a warning: each symbol resolves back to the kernel's copy through a klp
symbol, and neither is cloned into the patch.
An earlier version asserted only that no "no correlation" or "changed data"
message appeared, and passed with correlation deliberately broken. What
the messages say and what the patch contains are not the same question.
Verified to fail with correlation made to require matching symbol bindings.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-43-song@kernel.org
|
|
Most static locals have to be correlated so the patched code keeps using
the running kernel's copy. Two kinds must not: anything in .data..once,
the flag behind WARN_ONCE and friends, and the well-known names the kernel
generates for per-instance things (__warned, __key, __func__).
Sharing a .data..once flag means a patch inherits "already warned" from
before it was applied, and the warning it was meant to surface never fires.
The fixture deliberately does not name its .data..once variable __warned:
the name rule would then catch it and the section rule would go untested.
gcc spells these <var>.<id> and Clang <func>.<var>, so both are covered.
This tests the behavior of commit ff529864e738 ("objtool/klp: Fix
.data..once static local non-correlation") and commit 84c304a534b8
("objtool/klp: Fix is_uncorrelated_static_local() for Clang").
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-40-song@kernel.org
|
|
vmlinux is not like a module: the final link reorders sub-sections, so a
symbol's position has to come from the linked image rather than from symbol
table order. klp diff bridges that with .klp.symid, and looks for it only
when the object it was handed is called vmlinux.o with a vmlinux beside it.
This was assigned to an end-to-end test on the assumption that it needs a
real kernel build. It needs "ld -r" and "ld -e 0", and takes a fraction of
a second.
The fixture places the static appearing first in the symbol table at the
higher address, and the link passes --sort-section=name to force the
reordering the kernel's linker script performs. Without that the two ways
of computing sympos agree, and a first version passed with the vmlinux path
disabled.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-39-song@kernel.org
|
|
klp-sympos.c had no coverage at all. sympos disambiguates same-named
symbols for livepatch, counting from 1, with 0 meaning the name is unique.
Resolving to the wrong one is not a load failure -- it is a patch quietly
wired to the wrong object.
Covers the module path, where the position is a count in symbol table order
and klp diff can work it out from the object alone.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-38-song@kernel.org
|
|
A function that only moves has not changed, and its checksum must not move
with it. Otherwise every patch reports as changed everything that shifted
because something ahead of it grew.
The fixture is built with -fno-function-sections, overriding the harness
default: with per-function sections every function sits at offset 0 of its
own section and nothing ever moves, so the test would prove nothing. It
also calls across to another function rather than looping within itself --
a loop branch keeps the same displacement wherever the function goes, so it
is not position-dependent to begin with.
This tests the behavior of commit cca84cb12908 ("objtool/klp: Fix
position-dependent checksums for non-relocated jumps/calls").
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-37-song@kernel.org
|
|
Whether klp diff treats a function as changed is decided by its checksum,
and until now nothing looked at one. A test asserting only that the right
functions were cloned cannot tell a correct checksum from one that happens
to differ.
Asserts both directions -- the changed function's checksum moves, the
untouched one's does not -- and that checksumming identical input twice
gives the same answer, since otherwise every rebuild reports spurious
changes.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-36-song@kernel.org
|
|
A patch may introduce a reference the original object did not have. That
is fine when the export belongs to vmlinux, and not fine when it belongs to
a module: the livepatch would gain a module dependency nobody declared, and
late module patching lets the patch load first.
This tests the behavior of commit 72d76d0c18eb ("objtool/klp: Allow new
references to module exports").
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-34-song@kernel.org
|
|
A symbol exported with EXPORT_SYMBOL_FOR_MODULES() is reachable only by the
modules named in its namespace, and a livepatch module is never one of
them. So a reference to it cannot be an ordinary relocation resolved by the
module loader; it has to be a klp relocation applied at patch time.
Getting this wrong is silent. The module links, loads, and reads the wrong
thing, or fails to load for a reason that does not name the cause.
This tests the behavior of commit 4cd3cfb8b54f ("objtool/klp: Fix
relocations for EXPORT_SYMBOL_FOR_MODULES() symbols"). Which object the
resulting relocation is filed under is a separate question, and one this
test cannot ask: the patched object here is vmlinux, so the vmlinux section
is the one produced either way. That is covered by the module case, in
"objtool/klp: Add test for vmlinux relocs in a patched module".
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-33-song@kernel.org
|
|
The patch list is what livepatch acts on, and asserting only that it exists
does not say it is right. A function that should have been patched and is
missing leaves the bug in place; one that should not be there patches code
nobody changed.
The fixture changes two of three functions and asserts on all three: the
two by name, and the third by its absence. It checks the strings in
.rodata.klp.str1.1 as well as the relocations, since the names the kernel
matches on are real strings.
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-32-song@kernel.org
|
|
Module.symvers names an export's owner by build path, and the kernel knows
modules by their runtime name. Without normalizing one to the other, an
export owned by a module is not recognised as owned by anything, and a
reference that should become a klp relocation stays an ordinary one.
This tests the behavior of commit 8668bf91e050 ("objtool/klp: Normalize
Module.symvers paths to module names").
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-31-song@kernel.org
|
|
The kernel refuses a module-targeted klp relocation which names a vmlinux
symbol. An EXPORT_SYMBOL_FOR_MODULES() symbol needs a klp relocation, so
patching a module function that references one only loads if klp diff files
that relocation under vmlinux rather than under the patched module.
This fails at load, not at build: klp-build produces a module and static
checks of it find nothing wrong. Hence the assertion on which object the
relocation is filed against.
Reported by Dylan Hatch, whose mod-ns-lp branch carries the kernel-side
half of this case.
Co-developed-by: Dylan Hatch <dylanbhatch@google.com>
Signed-off-by: Dylan Hatch <dylanbhatch@google.com>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-30-song@kernel.org
|
|
klp diff names the intermediate __klp_relocs section after the object the
relocation belongs to, and post-link turns that into
.klp.rela.<object>.<sec>. Name it after the wrong object and the kernel
applies the relocation when the wrong module loads, or never.
The fixture is the first here to honour MODNAME: most hardcode
name=vmlinux, so passing -DMODNAME to them silently does nothing and the
test quietly becomes a vmlinux test.
This tests the behavior of commit 07f14d6af9d7 ("objtool/klp: Fix
cross-module klp relocation section naming").
Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@redhat.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/20260916184351.2720310-29-song@kernel.org
|
|
Five tests covering behaviour the harness could reach but nothing
exercised. Each was verified to fail against the code it guards, by
reverting the fix or sabotaging the exact line; where a first attempt
passed against broken code, the fixture was wrong and was rebuilt.
post-link first coverage of the subcommand at all
local-vs-export local symbols must not match exports
symvers-parse-error Module.symvers parse error line numbers
checksum-debug the --debug-checksum format klp-build reads
function-removal the "no correlation" path
local-vs-export tests the behavior of commit 86a697572c62 ("objtool/klp:
Don't match local symbols against exports"), and symvers-parse-error that
of commit 51c1de134863 ("objtool/klp: Fix line numbers in Module.symvers
parse errors").
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-28-song@kernel.org
|
|
klp diff decides what changed by comparing the per-function checksums klp
checksum records in .discard.sym_checksum. Handed an object which was
never checksummed it has to say so; silently concluding that nothing
changed would be the worst available answer.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-27-song@kernel.org
|
|
The module name recorded in .modinfo ends up in the livepatch's klp_object,
and also decides whether a static branch key counts as belonging to vmlinux
or to a module. An object without one cannot be diffed.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-26-song@kernel.org
|
|
ThinLTO promotes the file-local symbols an imported function touches,
renaming them name.llvm.<hash>. The hash is content derived, so it changes
whenever the module does:
original: counter.llvm.13663304415433785070
patched: counter.llvm.10543383937958011340
Correlating the two objects therefore requires demangling the suffix;
matching raw names would see two unrelated symbols and treat the variable
as new.
The resulting klp relocation also has to name the original symbol, since
that is the one in the running kernel's kallsyms. Naming the patched
build's symbol produces a relocation which can never be resolved.
ThinLTO is a clang feature, so the test declares itself clang-only. It
also needs an lld from the same LLVM release as $CC; a mismatched pair
fails with "Invalid summary version", which reads like a broken test rather
than a broken environment, so probe for a working lld and skip if there is
none.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-25-song@kernel.org
|
|
Init code and data are freed once boot finishes, so a klp relocation
against them can never resolve.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-24-song@kernel.org
|
|
.klp.symid records duplicate-named locals so klp diff can work out their
sympos. Symbols in sections the vmlinux link throws away have to be left
out, or the table references symbols which no longer exist and the link
fails:
`__exitcall_foo' referenced in section `.klp.symid' of vmlinux.o:
defined in discarded section `.exitcall.exit' of vmlinux.o
Two translation units are compiled from one fixture and partially linked so
the result has duplicate locals, which symid_needed() requires. One
duplicate is in a live section and one in .exitcall.exit.
Checking the live duplicate as well keeps the test honest: it would
otherwise pass just as happily if symid generation stopped working
entirely.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-23-song@kernel.org
|
|
Static calls carry the same constraint as static branches. Check that a
vmlinux-owned key is accepted and a module-owned one is refused.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-22-song@kernel.org
|
|
A static branch key belonging to a module cannot be reached with a klp
relocation: the patch may be applied after that module's static branch init
has run, which corrupts the code. Emitting one anyway produces a module
which loads and then BUG()s the first time the key changes state, so klp
diff has to refuse it.
The fixture differs from the accepted case only in the module name recorded
in .modinfo.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-21-song@kernel.org
|
|
A cloned __jump_table entry must keep a relocation in its key slot.
objtool parses the table again after klp diff to convert the static
branch's scaffold instruction, and an empty slot leaves it unable to do so.
The scaffold then stays as emitted and the module trips BUG() in
__jump_label_patch() once the key's state differs from its compile-time
default.
Check both halves for a vmlinux-owned key: unexported gives a tombstone
plus a klp relocation, exported gives an ordinary relocation and no klp
machinery.
The fixture defines the key as an STT_OBJECT, which is what the kernel
emits. validate_special_section_klp_reloc() ignores anything else, so a
fixture using an undefined extern would skip the interesting paths.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-20-song@kernel.org
|
|
Two functions contribute entries to one special section but only one is
patched. Cloning the neighbouring entry drags in whatever it points at,
which is how a livepatch ends up holding relocations against unrelated
code.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-19-song@kernel.org
|
|
create_fake_symbols() gives each special section entry a symbol so entries
can be extracted individually. Entries with ANNOTATE_DATA_SPECIAL are
handled first; the rest have their boundaries derived from the entry or
relocation size.
The second pass has to key off whether the first one created symbols, not
off whether the section already has something at offset 0. Clang puts an
assembler-local label at the start of .kcfi_traps, and treating that as
already handled means nothing is extracted: klp diff still reports the
changed function and succeeds, but the special section is missing from the
module.
The fixture reproduces the shape without needing CFI or x86.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-18-song@kernel.org
|
|
The compiler splits unlikely code into a separate foo.cold symbol. Both
halves are the same function and both belong in the livepatch: carrying
only the hot part leaves the cold path branching into unpatched code.
GCC needs -freorder-blocks-and-partition to split reliably. The flag is
probed rather than assumed, and the test skips when the compiler declines
to split at all.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-17-song@kernel.org
|
|
A static local must be correlated with its original rather than duplicated.
The replacement has to reach the existing variable through a klp
relocation; a fresh definition would discard whatever state the running
kernel accumulated.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-16-song@kernel.org
|
|
A function added by the patch has no original to correlate against, and
still has to be carried into the livepatch or the changed caller ends up
referencing something which does not exist.
The helper is noinline so the case survives the optimiser; otherwise the
compiler folds it into its only caller and the test covers nothing.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-15-song@kernel.org
|
|
Adding data differs from changing it: nothing in the running kernel refers
to a new variable, so it is safe and has to travel into the livepatch with
the function using it.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-14-song@kernel.org
|
|
Livepatching replaces functions. Nothing can swap a variable which live
code already refers to, so a patch which changes one has to be refused
rather than applied with the old value left in place.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-13-song@kernel.org
|
|
Which architecture a test is for is expressed by where it lives: tests are
in generic/ or in a directory named for their architecture, each carrying
its own fixtures, and the runner executes generic/ plus the one that
matches. A test which cannot apply here is then not run at all, rather
than running in order to announce that it did not.
Layout does this better than a declaration would. There is no x86_only(),
and no lookup letting a fixtures/<arch>/ file shadow a generic one of the
same name -- an arch-specific test simply carries its own fixtures.
Compilers cannot work the same way: CI varies CC over the same tree, so a
compiler requirement stays a declaration in the test.
What a run leaves out is reported once:
# not run: 5 tests in x86/ (this run is arm64)
Silence would have been cheaper and wrong. A run covering less than the
tree holds must not look like a run that covered all of it.
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Assisted-by: Claude:claude-opus-5
Link: https://patch.msgid.link/20260916184351.2720310-4-song@kernel.org
|