mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Longjun Luo <luolongjuna@gmail.com>
To: jpoimboe@kernel.org, peterz@infradead.org
Cc: mbenes@suse.cz, pmladek@suse.com, joe.lawrence@redhat.com,
	song@kernel.org, puranjay@kernel.org, nathan@kernel.org,
	ndesaulniers@google.com, morbo@google.com,
	justinstitt@google.com, live-patching@vger.kernel.org,
	llvm@lists.linux.dev, linux-kernel@vger.kernel.org,
	Longjun Luo <luolongjuna@gmail.com>
Subject: [RFC PATCH v2 10/11] objtool/klp: Check unmatched data references
Date: Wed,  4 Nov 2026 21:31:56 +0800	[thread overview]
Message-ID: <20261104133158.3187525-11-luolongjuna@gmail.com> (raw)
In-Reply-To: <20261104133158.3187525-1-luolongjuna@gmail.com>

An unmatched data reference can still refer to existing state. Treating
it as new can give old and patched code separate copies of that state.

For ordinary data, allow new storage only when no original identity
candidate exists. For compound literals, reuse a unique unchanged object
in both functions' references. Reject ambiguous or changed compounds;
without a source identity, additions cannot be distinguished from changes.

Report the referencing function and offset for unresolved ordinary data.
Exclude fake special-section symbols created by objtool after correlation.

Validated the available objtool tests with GCC 16.2.1 and Clang
22.1.8. Only local-to-global-flip, sympos and sympos-vmlinux fail,
reflecting the linkage and duplicate-identity policies.

Assisted-by: LLM
Signed-off-by: Longjun Luo <luolongjuna@gmail.com>
---
 tools/objtool/klp-diff.c | 134 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 134 insertions(+)

diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index e8252e586260..19f5161420cd 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1426,6 +1426,135 @@ static int extend_twins_by_relocations(struct elfs *e)
 	return 0;
 }
 
+static int find_unique_compound_reference(struct elf *elf, struct reloc *relocs,
+					  unsigned int nr, struct symbol *sym,
+					  struct symbol **match)
+{
+	unsigned int i;
+
+	*match = NULL;
+	for (i = 0; i < nr; i++) {
+		struct reloc *reloc = &relocs[i];
+		struct symbol *target;
+
+		if (reloc_type(reloc) == R_NONE || convert_reloc_secsym_to_sym(elf, reloc))
+			continue;
+		target = reloc->sym;
+		if (!is_compound_constant(target) || target->len != sym->len ||
+		    target->csum.checksum != sym->csum.checksum)
+			continue;
+		if (*match && *match != target) {
+			ERROR("unresolved compound reference: %s matches %s[%u] and %s[%u]",
+			      sym->name, (*match)->name, (*match)->idx, target->name, target->idx);
+			return -1;
+		}
+		*match = target;
+	}
+	return 0;
+}
+
+static int resolve_compound_reference(struct elfs *e, struct symbol *sym,
+				      struct reloc *orig_relocs, unsigned int nr_orig,
+				      struct reloc *patched_relocs, unsigned int nr_patched)
+{
+	struct symbol *orig_sym, *patched_sym;
+
+	if (!sym->csum.checksum) {
+		ERROR("%s: missing compound checksum", sym->name);
+		return -1;
+	}
+
+	if (find_unique_compound_reference(e->orig, orig_relocs, nr_orig, sym, &orig_sym))
+		return -1;
+	if (!orig_sym) {
+		/*
+		 * Data changes are unsupported. With no source identity, new and
+		 * changed compound literals cannot be distinguished here.
+		 */
+		ERROR("unresolved compound reference: %s has no unchanged match", sym->name);
+		return -1;
+	}
+
+	if (find_unique_compound_reference(e->patched, patched_relocs, nr_patched,
+					   sym, &patched_sym))
+		return -1;
+	if (patched_sym != sym) {
+		ERROR("unresolved compound reference: %s is not a unique reference in its function",
+		      sym->name);
+		return -1;
+	}
+	if (orig_sym->twin) {
+		ERROR("compound twin conflict: %s[%u] paired with %s[%u]",
+		      orig_sym->name, orig_sym->idx,
+		      orig_sym->twin->name, orig_sym->twin->idx);
+		return -1;
+	}
+	sym->twin = orig_sym;
+	orig_sym->twin = sym;
+	dbg_correlate("%s(): %s[%u] -> %s[%u]", __func__,
+		      orig_sym->name, orig_sym->idx, sym->name, sym->idx);
+	return 0;
+}
+
+/*
+ * Check references to symbols without twins for ambiguity:
+ *
+ * 1. Ordinary data: allow as new only if no original identity candidates exist.
+ *    We assume DWARF identity information is stable across builds with the
+ *    same compiler.
+ * 2. Compound literals (anonymous data with static storage duration):
+ *    - delete: allowed.
+ *    - same: require a unique unchanged match in both functions' references.
+ *    - change: unsupported, to keep old and patched code's data views consistent.
+ *    - new: reject for now; it cannot be distinguished from change.
+ *      Supporting additions requires an explicit mechanism.
+ */
+static int check_unmatched_reference(struct elfs *e, struct reloc *reloc)
+{
+	struct symbol *patched_sym = reloc->sym, *orig_sym, *func;
+	struct reloc *orig_relocs = NULL, *patched_relocs = NULL;
+	unsigned int nr_orig = 0, nr_patched = 0;
+	u32 key;
+
+	if (reference_twin(patched_sym) || patched_sym->dont_correlate ||
+	    !is_object_sym(patched_sym) || is_undef_sym(patched_sym) || !patched_sym->len)
+		return 0;
+
+	if (!is_compound_constant(patched_sym)) {
+		if (!has_dwarf_identity(patched_sym)) {
+			ERROR_FUNC(reloc->sec->base, reloc_offset(reloc),
+				   "unresolved data reference: %s has no DWARF identity",
+				   patched_sym->name);
+			return -1;
+		}
+		key = identity_hash(&patched_sym->identity);
+		/*
+		 * With one old count.N and two patched candidates, the unmatched one
+		 * may still refer to old state, even if the original already has a twin.
+		 */
+		elf_hash_for_each_possible(e->orig, symbol_identity, orig_sym, identity_hash, key) {
+			if (!same_identity(&patched_sym->identity, &orig_sym->identity))
+				continue;
+			ERROR_FUNC(reloc->sec->base, reloc_offset(reloc),
+				   "unresolved data reference: %s (%s, %s, %s), old candidate %s[%u]",
+				   patched_sym->name, patched_sym->identity.source,
+				   patched_sym->identity.scope,
+				   patched_sym->identity.demangled_name,
+				   orig_sym->name, orig_sym->idx);
+			return -1;
+		}
+		return 0;
+	}
+
+	func = find_func_containing(reloc->sec->base, reloc_offset(reloc));
+	if (func && func->included && func->twin && !same_function_checksum(func)) {
+		orig_relocs = get_func_relocs(e->orig, func->twin, &nr_orig);
+		patched_relocs = get_func_relocs(e->patched, func, &nr_patched);
+	}
+	return resolve_compound_reference(e, patched_sym, orig_relocs, nr_orig,
+					  patched_relocs, nr_patched);
+}
+
 /*
  * Check if the original module already has a dependency on dep_mod, i.e. it
  * already references at least one export from that module.
@@ -1629,6 +1758,9 @@ static int clone_reloc(struct elfs *e, struct reloc *patched_reloc,
 	bool klp;
 
 	/* Reject ambiguous data references before treating them as new. */
+	if (check_unmatched_reference(e, patched_reloc))
+		return -1;
+
 	klp = klp_reloc_needed(patched_reloc);
 
 	dbg_clone_reloc(sec, offset, patched_sym, addend, export, klp);
@@ -1781,6 +1913,8 @@ static int create_fake_symbol(struct elf *elf, struct section *sec,
 		return -1;
 
 	sym->fake = 1;
+	/* Special-section entries are copied with the patched code. */
+	sym->dont_correlate = 1;
 	return 0;
 }
 
-- 
2.55.0


  parent reply	other threads:[~2026-11-04 13:33 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-04 13:31 [RFC PATCH v2 00/11] objtool/klp: DWARF-based cross-build symbol correlation Longjun Luo
2026-11-04 13:31 ` [RFC PATCH v2 01/11] objtool/klp: Fix checksums and copying of wide strings Longjun Luo
2026-11-04 13:31 ` [RFC PATCH v2 02/11] objtool/klp: Hash compound literals by content Longjun Luo
2026-11-04 13:31 ` [RFC PATCH v2 03/11] objtool/klp: Preserve identifier digits when stripping suffixes Longjun Luo
2026-11-04 13:31 ` [RFC PATCH v2 04/11] objtool/klp: Read symbol identities from DWARF Longjun Luo
2026-11-04 13:31 ` [RFC PATCH v2 05/11] objtool/klp: Support reduced and split DWARF Longjun Luo
2026-11-04 13:31 ` [RFC PATCH v2 06/11] klp-build: Require CONFIG_DEBUG_INFO Longjun Luo
2026-11-04 13:31 ` [RFC PATCH v2 07/11] objtool/klp: Correlate symbols using DWARF identities Longjun Luo
2026-11-04 13:31 ` [RFC PATCH v2 08/11] objtool/klp: Include symbol identities in reference checksums Longjun Luo
2026-11-04 13:31 ` [RFC PATCH v2 09/11] objtool/klp: Extend twins through unchanged function references Longjun Luo
2026-11-04 13:31 ` Longjun Luo [this message]
2026-11-04 13:31 ` [RFC PATCH v2 11/11] objtool/klp: Test symbol identity and state preservation Longjun Luo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261104133158.3187525-11-luolongjuna@gmail.com \
    --to=luolongjuna@gmail.com \
    --cc=joe.lawrence@redhat.com \
    --cc=jpoimboe@kernel.org \
    --cc=justinstitt@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=live-patching@vger.kernel.org \
    --cc=llvm@lists.linux.dev \
    --cc=mbenes@suse.cz \
    --cc=morbo@google.com \
    --cc=nathan@kernel.org \
    --cc=ndesaulniers@google.com \
    --cc=peterz@infradead.org \
    --cc=pmladek@suse.com \
    --cc=puranjay@kernel.org \
    --cc=song@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®