Skip to content

create-diff-object: correlate renumbered/uncorrelatable static local data and CSWTCH sections as a last resort - #1518

Open
benjamindonnachie wants to merge 1 commit into
dynup:masterfrom
benjamindonnachie:fix-cswtch-section-correlation
Open

create-diff-object: correlate renumbered/uncorrelatable static local data and CSWTCH sections as a last resort#1518
benjamindonnachie wants to merge 1 commit into
dynup:masterfrom
benjamindonnachie:fix-cswtch-section-correlation

Conversation

@benjamindonnachie

Copy link
Copy Markdown

Fixes #1514 (the deepest of the four fixes tracked there).

gcc's numbering of some compiler-synthesized read-only data —
CSWTCH.N switch-dispatch tables, __compound_literal.N — is not
stable between two compilations of byte-identical source when the
build context differs (a from-scratch build vs. an incremental,
Kbuild-triggered rebuild of the same file later in the process,
which is exactly what kpatch-build's two-pass original/patched flow
does). Verified empirically: compiling the same unmodified file
twice in a row, standalone, is byte-for-byte reproducible; it's
specifically kpatch-build's from-scratch-then-incremental sequence
that exposes the drift. kpatch_find_static_twin() correlates these
by name and reference within the referencing function's section,
and fails closed when the renumbering defeats that — even when the
file is provably unchanged.

This is long-standing and still open upstream: #767 (the exact file
and symptom class reproduced here, cx2341x.c/CSWTCH.N), #519,
#532, #545. #534 (merged 2015, "CSWTCH fix, take 2") addressed a
different angle of the same general problem and is already folded
into the more general is_special_static() mechanism — it doesn't
cover this case, since these are ordinary driver-defined static
arrays (e.g. alc663_ssids, t4_reg_ranges) referenced from a
CSWTCH section, not CSWTCH symbols themselves.

The fix

Two last-resort fallbacks, both used only when the existing
name/reference-based correlation already failed:

  1. kpatch_find_static_twin_by_content(): correlate a static
    local by exact byte-for-byte section content, requiring the same
    base name (numeric suffix aside), type, and size. Content
    equality is the safety property here — it can only let through
    cases the reference-based match would otherwise (safely) reject,
    never weaken the "no functional change" guarantee, since any
    genuine content difference still fails the comparison. The
    base-name requirement guards against unrelated tables
    coincidentally sharing identical bytes (e.g.
    short/terminator-only arrays).

  2. kpatch_find_section_twin_by_symbol_ref(): CSWTCH.N sections
    can't be correlated by name at all — every such section in a
    translation unit shares the same gcc-assigned base name, so
    name-based correlation is ambiguous by construction, not just
    numerically unstable. When a symbol referenced from such a
    section has already been correlated via the normal path (e.g. via
    some other, ordinarily-named function that also references it),
    use that as an anchor: the patched section whose relocations
    reference the symbol's twin is the section's twin.

Testing

Reproduced and fixed while building a real cumulative EL9 5.14
kernel livepatch (11 CVEs, base 5.14.0-687.25.1.el9_8 → target
5.14.0-687.38.1.el9_8). This, together with #1516 and #1517, took a
build that previously failed deterministically on every attempt
through to a working, loaded kpatch module — confirmed via kpatch list after installing the built RPM, covering all 11 target CVEs.

Co-authored-by: Claude noreply@anthropic.com

data and CSWTCH sections as a last resort

gcc's numbering of some compiler-synthesized read-only data --
CSWTCH.N switch-dispatch tables, __compound_literal.N -- is not
stable between two compilations of byte-identical source when the
build *context* differs (a from-scratch build vs. an incremental,
Kbuild-triggered rebuild of the same file later in the process, which
is exactly what kpatch-build's two-pass original/patched flow does).
Verified empirically: compiling the same unmodified file twice in a
row, standalone, is byte-for-byte reproducible; it's specifically
kpatch-build's from-scratch-then-incremental sequence that exposes
the drift. kpatch_find_static_twin() correlates these by name and
reference within the referencing function's section, and fails
closed when the renumbering defeats that -- even when the file is
provably unchanged.

This is long-standing and still open upstream: dynup#767 (the exact file
and symptom class reproduced here, cx2341x.c/CSWTCH.N), dynup#519, dynup#532,
dynup#545. dynup#534 (merged 2015, "CSWTCH fix, take 2") addressed a different
angle of the same general problem and is already folded into the
more general is_special_static() mechanism -- it doesn't cover this
case, since these are ordinary driver-defined static arrays (e.g.
alc663_ssids, t4_reg_ranges) referenced *from* a CSWTCH section, not
CSWTCH symbols themselves.

Two last-resort fallbacks, both used only when the existing
name/reference-based correlation already failed:

1. kpatch_find_static_twin_by_content(): correlate a static local by
   exact byte-for-byte section content, requiring the same base name
   (numeric suffix aside), type, and size. Content equality is the
   safety property here -- it can only let through cases the
   reference-based match would otherwise (safely) reject, never
   weaken the "no functional change" guarantee, since any genuine
   content difference still fails the comparison. The base-name
   requirement guards against unrelated tables coincidentally
   sharing identical bytes (e.g. short/terminator-only arrays).

2. kpatch_find_section_twin_by_symbol_ref(): CSWTCH.N sections can't
   be correlated by name at all -- every such section in a
   translation unit shares the same gcc-assigned base name, so
   name-based correlation is ambiguous by construction, not just
   numerically unstable. When a symbol referenced *from* such a
   section has already been correlated via the normal path (e.g. via
   some other, ordinarily-named function that also references it),
   use that as an anchor: the patched section whose relocations
   reference the symbol's twin is the section's twin.

Reproduced and fixed while building a real cumulative EL9 5.14
kernel livepatch: this, together with the R_X86_64_32 and deferred
find_local_syms fixes, took a build that previously failed
deterministically on every attempt through to a working, loaded
kpatch module.

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cumulative EL9 kernel livepatch build fails on unrelated files: CSWTCH renumbering, gcc inlining drift, missing R_X86_64_32, PVH boot code

1 participant