From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 91BA035CB87; Mon, 3 Aug 2026 03:24:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727490; cv=none; b=SjHkYjgkl4A1blK+E30xkde89dqALCiham2YBiY0iHKZL7H6XjiVmyDZxIOkUk7J+rSi/bC/wWUxTWdKdeCjkD8wg96tAGV66xBYTJ1UypVwgF4HNBuLkuc+2CYZVvaBZ93POHYuC/HQZfGGturGt+fkIH4ZPDudrqYrJBZUaNA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727490; c=relaxed/simple; bh=U8CEK6XYg42do2MR6KwtUPjR42Wqvg261Hq3tR9ojxs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CD224dsD7N5twBRYB/EOFystQ3Iqe68EDTbKAxQf68gnGr+U6/wDwFloAgfhZf6QokMGdIeJ07LAr70f+eogyIkXeYjasFrX9kmXjIyEU+fcF97GpFU+sL31pWvTDOhXqAqBLdwS9tRJ57JDiJ7BMt/dvIu/F66vI/YThQ/Y0ns= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=EBsQSnKu; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="EBsQSnKu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AE4A51F00A3E; Mon, 3 Aug 2026 03:24:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727489; bh=eYO/LoWPG6DH2eRKJ5hm/XFNO1RSrjFAdgJnmvUBJEc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=EBsQSnKuQfnyCfmqxYi6KNydKG0wC4mHjOU6LJJuz+qPuvsQk0/635+51EWu78H7L oM3GQ07tFi04k4yWioMXTCjP1JUod7MpA3uNMZgiVu+ELHI217czo/XJC3x4wka77V HKPZ5x0tX5/sO75ASDR88duDhJ5Yms7JF50x1dmraAc/fJrRhrATc7taZNqhiAfNT3 0zQqqNW0NuKvGgK0IgSwyhVsr3V7VPHcSmj0s3vPUvu13eHpRdH8Uwq9JeURxhvMSz kZ4ySdpOd3hv3S03CcDsjWB1fBbLYVK/g0404LAj5fImQGuVbcJVaz2jFY84xfE/cz FcwFWJGx+KGwg== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org, Sashiko Subject: [PATCH 01/14] objtool/klp: Fix module name normalization for paths with dots Date: Sun, 2 Aug 2026 20:24:23 -0700 Message-ID: <9017b4609553bed16674e8f924d34691cbc2b2c1.1785727106.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When .modinfo has no "name=3D" tag, __find_modname() falls back to converting the object's build-tree path to a runtime module name by stripping directory components, converting '-' to '_' and truncating the file extension. It does all that in a single pass over the entire path, so the first dot anywhere in the path ends the name. For an object built in a directory whose name contains a dot, e.g. "drivers/foo-1.0/bar.o", the result is a bogus module name. Strip the directory components up front so only the basename is scanned for the extension separator. Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffin= g object files") Reported-by: Sashiko Signed-off-by: Josh Poimboeuf --- tools/objtool/klp-diff.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index f8787d7d1454..aeb99d572300 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -1140,7 +1140,7 @@ static struct export *find_export(struct symbol *sym) static const char *__find_modname(struct elfs *e) { struct section *sec; - char *name; + char *name, *slash; =20 sec =3D find_section_by_name(e->orig, ".modinfo"); if (!sec) { @@ -1158,10 +1158,12 @@ static const char *__find_modname(struct elfs *e) return NULL; } =20 + slash =3D strrchr(name, '/'); + if (slash) + name =3D slash + 1; + for (char *c =3D name; *c; c++) { - if (*c =3D=3D '/') - name =3D c + 1; - else if (*c =3D=3D '-') + if (*c =3D=3D '-') *c =3D '_'; else if (*c =3D=3D '.') { *c =3D '\0'; --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4A40836492A; Mon, 3 Aug 2026 03:24:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727491; cv=none; b=gIRKGXB9AdTp2rHbw7QDw0i8oBMxagq88RaSAxbbntVV27LZeV79BexCXCYiqRDQerW70RHiJFSypRfOJSJm7B0YUTi4zpIK2ykb84J2abGz+GsXB8F14HcvrkTw+DK5THxvOSlT6HYBkILOC1HONKW8J2MgKdtaNotVXC+342g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727491; c=relaxed/simple; bh=hm3D/Xty8MBZM3QfRbUzA8YpbzAJCtUKOyJdYd95Ovo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=I9kN9bSrTZoA/uhTqXtwD3iP4Z0/ncqfGPDgzYh5f8uMjqjmHzP0Yqp9bSxCAFx9+OIRI5R1EsoTZQruLqxB/MIK9zdYjv35fbBYJrP/WOacPE9lwzJBM2WdbLPXttxNd1zfMwF4hc/ASl+cCfw4duA2NcFKsD2BeF4WyWseI2c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iQTPu1Wi; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iQTPu1Wi" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 60DC31F00A3F; Mon, 3 Aug 2026 03:24:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727489; bh=7remyKREYUVeFS3QYdwJSO3fUjTHDVOdeo5ZoWSgbRg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=iQTPu1WiC9tor+Sm1inMIHJPO7FNi+HIpRCyi58OrI0trvey27NJvz/41hc1q6Pi5 oi8FRITIKpGnBsnz5ka9z8wYzvwtk9yDQpdp9apD4NdpJ+2cGjH03hcjKEGlK1tTG0 yhOjI+1DFiu34j3JmgGKC/pq+Z/z6gu8Vs1TILeyHmJeRh/VZHRUt87D0jhC7qXQEW rz6x1joInJZAiEG8u9osnDIJ4dk0YMPUesmbh8hutYlVwKTug19k9/yxLgqvO81fpi dx1er5v2Aks54l/E8oHvinuz2Dit2HxeEamwAN4T60XtQR2ara2W6E9rc/Vbza5SCz Lu4efUw274v1w== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org, Ben Procknow Subject: [PATCH 02/14] objtool/klp: Normalize Module.symvers paths to module names Date: Sun, 2 Aug 2026 20:24:24 -0700 Message-ID: X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Joe Lawrence Module.symvers contains build-tree object paths as module identifiers (e.g., "arch/x86/kvm/kvm") rather than runtime module names ("kvm"). Objtool's clone_reloc_klp() uses this field directly for exported symbols, while unexported symbols correctly go through __find_modname(). This means that exported symbol relocations may land in a .klp.rela section named with the build path rather than the module name. That is a crash waiting to happen: the kernel's livepatch loader silently skips this relocation because it doesn't match the expected klp_object name. The unresolved relocation sits in the newly activated code, crashing when executed. Normalize export->mod at Module.symvers read time using the same logic as __find_modname() (refactored into a shared normalize_modname() helper). Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffin= g object files") Reported-by: Ben Procknow Signed-off-by: Joe Lawrence Reviewed-by: Miroslav Benes Signed-off-by: Josh Poimboeuf --- tools/objtool/klp-diff.c | 49 ++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index aeb99d572300..15d37d955af0 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -83,6 +83,35 @@ static char *escape_str(const char *orig) return new; } =20 +/* + * Convert a build-tree object path to a runtime module name: strip + * directory components, replace '-' with '_', and remove file + * extensions. Examples: + * + * "arch/x86/kvm/kvm" -> "kvm" + * "arch/x86/kvm/kvm-intel" -> "kvm_intel". + * + * Used by read_exports() to normalize Module.symvers entries and by + * __find_modname() as a fallback when .modinfo lacks a "name=3D" tag. + */ +static char *normalize_modname(char *name) +{ + char *slash =3D strrchr(name, '/'); + + if (slash) + name =3D slash + 1; + + for (char *c =3D name; *c; c++) { + if (*c =3D=3D '-') + *c =3D '_'; + else if (*c =3D=3D '.') { + *c =3D '\0'; + break; + } + } + return name; +} + static int read_exports(void) { const char *symvers =3D "Module.symvers"; @@ -150,6 +179,9 @@ static int read_exports(void) return -1; } =20 + if (strcmp(export->mod, "vmlinux")) + export->mod =3D normalize_modname(export->mod); + export->sym =3D strdup(sym); if (!export->sym) { ERROR_GLIBC("strdup"); @@ -1140,7 +1172,7 @@ static struct export *find_export(struct symbol *sym) static const char *__find_modname(struct elfs *e) { struct section *sec; - char *name, *slash; + char *name; =20 sec =3D find_section_by_name(e->orig, ".modinfo"); if (!sec) { @@ -1158,20 +1190,7 @@ static const char *__find_modname(struct elfs *e) return NULL; } =20 - slash =3D strrchr(name, '/'); - if (slash) - name =3D slash + 1; - - for (char *c =3D name; *c; c++) { - if (*c =3D=3D '-') - *c =3D '_'; - else if (*c =3D=3D '.') { - *c =3D '\0'; - break; - } - } - - return name; + return normalize_modname(name); } =20 /* Get the object's module name as defined by the kernel (and klp_object) = */ --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C8EFF36D9E9; Mon, 3 Aug 2026 03:24:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727492; cv=none; b=W8ZVZPTh+Qg11KA1rqekAavFO5bO9hJs17350/+/QRaxYnBmy4sC7GCLhWEAeEVpODbMMPi7bu4ZSUKLuwbWCUHJXwd+pL9De0pcpRKf+bLCmvOjy7Y5r5OAlRldwQw2rJEJS0nbJt9n7VfkRJogkovRDbgaUOS8Rb1A0XwohkY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727492; c=relaxed/simple; bh=7y0GrduXLKZDzurZAP7lv1oZJSopq852CcGlQwj1CEA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PnLZrDghpOAUWEIGoqoW6nblB+pU3VKtKQMOQA4Ciz18aSdFn+0bSe6mi28YsmPnAc2mCoTkLThdoG/gQqPw2VijYh9B1EMDyPArC60VLY9HDmTVZvvjpzT1MbZQJWUGSuQkj9RcYmSd+v8XhgycXNyd5yJ2DhWTuhDTfMfsKJE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=I1j2Idpt; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="I1j2Idpt" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 130FF1F000E9; Mon, 3 Aug 2026 03:24:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727490; bh=p0WYRp2P3qcbTs2R+rOqZR35qVFQPjC9GnzYF8If2ls=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=I1j2IdptB5P9bWV+OSKoiQD1As3wywHTZCC7VxnJ36+a6uQkyv1LmOvWxIr8KBMwr wjO8sTxDleWizj56AZBHJh6FwjzJwNjuOJKPcLrOSV1KPBaqIhQexBtEeZTBPMPQHQ RA6Ef3OSSLfQjMteEYFACaCb5yD4hMbRSGiH8va97M7LefciUpEf1bBMABB1ExDB3q 8/5GffA0Aoc4ktITb2Ae0WX7E600TCIGXomqK0P8sNlyc80cKmBkL37Gfw3mIlgJtZ qsJbB+EF8pA88k0EX7ZWINupfyrkSugA0EmCa+ayR2QMBgj9VNVTCJVIiw1FKmRbM2 us7X09hXMAc7A== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org, Ben Procknow Subject: [PATCH 03/14] objtool/klp: Fix false module dependencies caused by dead relocs Date: Sun, 2 Aug 2026 20:24:25 -0700 Message-ID: <9548393f4d89ec3b498f4f69aa6ef6b9bb7150fe.1785727106.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When creating a klp reloc, klp-diff keeps the original relocation but converts the referenced symbol to an UNDEF/WEAK placeholder tombstone symbol, which gets fully disabled later by klp post-link. The tombstone symbol is only needed to avoid confusing objtool when it does the final run on the patch module. However, for references to exported symbols, modpost sees the reference to the tombstone symbol as a real reference to an exported symbol, resulting in a false module dependency getting created. Further, for a reference to a tombstone symbol which is exported into a module namespace, e.g. via EXPORT_SYMBOL_FOR_KVM_INTERNAL(), modpost can't satisfy the dependency, resulting in a warning like the following: module ... uses symbol kvm_flush_remote_tlbs from namespace module:kvm-amd,kvm-intel, but does not import it. Rename the placeholder tombstone symbols to ".klp.tombstone." so modpost no longer recognizes them. Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffin= g object files") Reported-by: Ben Procknow Reported-by: Joe Lawrence Link: https://lore.kernel.org/20260720145658.1103243-5-joe.lawrence@redhat.= com Signed-off-by: Josh Poimboeuf --- tools/objtool/elf.c | 13 +++++++++++++ tools/objtool/include/objtool/klp.h | 2 ++ tools/objtool/klp-diff.c | 16 ++++++++++++---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 33c95a74a51b..a791f4ea6ec1 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -23,6 +23,7 @@ #include #include #include +#include #include =20 static ssize_t demangled_name_len(const char *name); @@ -626,6 +627,18 @@ static int read_symbols(struct elf *elf) return -1; } =20 + /* + * "klp diff" renames the placeholder symbols of KLP relocs to + * hide them from modpost. Hide the prefix from the rest of + * objtool so its many name-based heuristics (noreturns, + * uaccess safe list, ...) still see the original symbol name. + * + * st_name is left alone, so the renamed symbol is preserved in + * the output file. + */ + if (strstarts(sym->name, KLP_TOMBSTONE_PREFIX)) + sym->name +=3D strlen(KLP_TOMBSTONE_PREFIX); + if ((sym->sym.st_shndx > SHN_UNDEF && sym->sym.st_shndx < SHN_LORESERVE) || (shndx_data && sym->sym.st_shndx =3D=3D SHN_XINDEX)) { diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/ob= jtool/klp.h index 6f60cf05db86..aab6db42052d 100644 --- a/tools/objtool/include/objtool/klp.h +++ b/tools/objtool/include/objtool/klp.h @@ -23,6 +23,8 @@ #define KLP_RELOCS_SEC "__klp_relocs" #define KLP_STRINGS_SEC ".rodata.klp.str1.1" =20 +#define KLP_TOMBSTONE_PREFIX ".klp.tombstone." + struct klp_reloc { void *offset; void *sym; diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index 15d37d955af0..75ba0e060a34 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -1362,6 +1362,7 @@ static int clone_reloc_klp(struct elfs *e, struct rel= oc *patched_reloc, s64 addend =3D reloc_addend(patched_reloc); const char *sym_modname, *sym_orig_name; static struct section *klp_relocs; + char tombstone_name[SYM_NAME_LEN]; struct symbol *sym, *klp_sym; unsigned long klp_reloc_off; char sym_name[SYM_NAME_LEN]; @@ -1376,15 +1377,22 @@ static int clone_reloc_klp(struct elfs *e, struct r= eloc *patched_reloc, /* * Keep the original reloc intact for now to avoid breaking objtool run * which relies on proper relocations for many of its features. This - * will be disabled later by "objtool klp post-link". + * reloc now targets a functionally dead tombstone symbol and will be + * disabled later by "objtool klp post-link". * - * Convert it to UNDEF (and WEAK to avoid modpost warnings). + * Convert the symbol to UNDEF/WEAK and rename to + * .klp.tombstone.sym_name to prevent modpost from printing warnings or + * creating false module dependencies. The prefix is hidden from the + * objtool run itself by read_symbols(). */ =20 sym =3D patched_sym->clone; if (!sym) { - /* STB_WEAK: avoid modpost undefined symbol warnings */ - sym =3D elf_create_symbol(e->out, patched_sym->name, NULL, + if (snprintf_check(tombstone_name, SYM_NAME_LEN, + KLP_TOMBSTONE_PREFIX "%s", patched_sym->name)) + return -1; + + sym =3D elf_create_symbol(e->out, tombstone_name, NULL, STB_WEAK, patched_sym->type, 0, 0); if (!sym) return -1; --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8AAD1371CE9; Mon, 3 Aug 2026 03:24:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727492; cv=none; b=hxXJqxBlXUCXucnsMyvQUYqnpQAhKNSx4Ch7DMsNfHdxmIE6ePPhAW5bGNAOCxeUbN3mWU9qc42QyroQegCADNXMeXm483rNOfbtQS/ac2Lk4e+IBo+KvhL6/rIKIrWrCt9VmGtrYCYtApJGSotSwgHRbFGbPZlrAUDBDYL/ek4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727492; c=relaxed/simple; bh=ZfKdhuQ63JpBsiVElOpGCQjExO5iDWBD+S7OmVWm+xA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Jw1dce/RHcdmkiRstjEhukYgYzMqS52hnaXbeVgpn8aliEuvtj5SHvDYszJj9w6++bW4vFcjy4S7CHs1XQtz+mtlhE9/mcBMJamJaOet7qVXRI1hsaZ7kby+0qDi888VYn4K1mvmEN6+BVM5N5HM91fG/DYyPUnHvavFVVOed1U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OzrkaYa/; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OzrkaYa/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BA12F1F00A3D; Mon, 3 Aug 2026 03:24:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727491; bh=1bdLKP+qYFZbiCIwjRRJtgUZeoEpaDmDYlf6aXshcZo=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=OzrkaYa/n2Gnv1GYkol2GxnCQ/Lr0Yk4WAbExE9TDaPAZF6LiCumBIsXqXH4qFRBY jKAs6YGayrmPlXCPwjHm5AmtEuDxQKn7xhhXN3n6ZuuOZHbAerWjvzYOWekOpNrccq DPoqZoyKjc7NeB3Uot56yIQrxuYJ+4vUfMed0naJfThIBxedHJzl8PsLGnEf/Rzz3W wA4Qt1V8GGnqldYSAC8IPiISWxuRz+6z1B6fsg55ATjldpXBQQ5pK6GPYqfPYJPSCs ZEswH2zwMMXjYJ2m16mlg9koc5XyU+Qd+M9VA4+LP0e+23/e7VbTtSXhqIszyi2E5A DOx51sI6vZ4xw== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org Subject: [PATCH 04/14] objtool/klp: Skip hidden directories when finding objects Date: Sun, 2 Aug 2026 20:24:26 -0700 Message-ID: <6c8eaa9feb17e3811f4ef7733fd7288b7f489183.1785727106.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" klp-build's find_objects() scans the whole tree for vmlinux.o and .ko files, pruning only klp-tmp/ and .git/. Development tools can leave other dot-directories in the tree. Kernel objects never live under hidden directories, so prune them all. Signed-off-by: Josh Poimboeuf --- scripts/livepatch/klp-build | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build index c4a7acf8edc3..a8c103ce7763 100755 --- a/scripts/livepatch/klp-build +++ b/scripts/livepatch/klp-build @@ -575,8 +575,9 @@ find_objects() { local opts=3D("$@") =20 # Find root-level vmlinux.o and non-root-level .ko files, - # excluding klp-tmp/ and .git/ - find "$PWD" \( -path "$TMP_DIR" -o -path "$PWD/.git" -o -regex "$PWD/[^/]= [^/]*\.ko" \) -prune -o \ + # excluding klp-tmp/ and hidden directories. + find "$PWD" -mindepth 1 \ + \( -path "$TMP_DIR" -o -name ".*" -o -regex "$PWD/[^/][^/]*\.ko" \) = -prune -o \ -type f "${opts[@]}" \ \( -name "*.ko" -o -path "$PWD/vmlinux.o" \) \ -printf '%P\n' --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EF36A38F64C; Mon, 3 Aug 2026 03:24:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727493; cv=none; b=YtPArBGBxNCuBZ5SIwTmMYaLO5zYwOrUgA67Xxze3yLo8BO4ZqQ01ebaDW7zIJTndW6/mVX2VGXJrXRxcCh6eZuinByKvo/+kCq7qBwYa+l7kk6RiWe3h96JDP3/xa4E8fqokulniHNM00tarAmhIpgFGg3Yb+FG4iFrszSQvuA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727493; c=relaxed/simple; bh=W4wO4L2SaAJEsHszjhStRI1k4X2ySnkaNcQsbJZ8ZW8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Mid95LAFCQwUl/3/9iTsTqyMIwLMYB1sQ2ocqWc7g/+RPw70glDS2NmGNEBoM1qldZx1kMz+YxwlNsjFCEs6KDFwea/5lnMzYW7o8fi6Rz3t6ow5mtqEPDe2GlvEuh1bRaS77EZEYtXke4KU4vHHY3d4uqp6Xq1ptHbpsnzI6jQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=V/zjbL8C; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="V/zjbL8C" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 615A31F00A3A; Mon, 3 Aug 2026 03:24:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727491; bh=U+FHei45N946Wh+aw6fEo/doxqF/olqKe92EL2KuFaU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=V/zjbL8CDtcrxq8cf/+SRIFPsSdQi5XhNTs1Hax2caYAMoVlWzvbncQd9PdDjp/Gk eF49HZCpbDfhg8RIkyWp708Jz6bgzyqnaoRAjY/TqtA6x+tYhTLGuE1O9DtEsFmHsZ jxr+R1cQsanDw4mn8h5aGUEw3hkE9OboCJschfiiuznuyRRj1qchSsThdsic9Pk2Fr 5rPmUg4LAuqpfx9de2dNrYy6daichEwwsvi9xYrBnIPhFddd3MMEWWsHqP0Uo85Gtx FyRuYMXIunBGg9zNZ0ieFsZKRuUETLvEeD7nCNFm8zZ9HzCuUTwiQ0rx+a7IPmiUR3 nZMrHs+z59n4A== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org Subject: [PATCH 05/14] objtool/klp: Add .klp.symid for sympos disambiguation Date: Sun, 2 Aug 2026 20:24:27 -0700 Message-ID: <64d50f077b569f47883c015cdb7079edb068efe8.1785727106.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Livepatch identifies a duplicate-named symbol by its position (sympos) among same-named kallsyms entries, which for vmlinux are counted in ascending address order in the final linked kernel. That order can't be reliably derived from vmlinux.o: the final link reorders sub-sections (.text.unlikely*, .data..*, etc). Bridge the gap with a new .klp.symid section which can be used to correlate symbols between vmlinux.o and vmlinux so that klp-diff can reliably determine the sympos. The table can't survive --gc-sections: keeping it alive would keep every duplicate-named symbol's section alive, so the reference kernel would stop matching the one which ships. klp-build rejects CONFIG_LD_DEAD_CODE_DATA_ELIMINATION instead. Nothing is lost today: x86_64 is the only HAVE_KLP_BUILD arch and doesn't select HAVE_LD_DEAD_CODE_DATA_ELIMINATION, arm64 and s390 have never selected it either, and on powerpc, it's still EXPERIMENTAL and disabled by every distro kernel. This is the build-time half of reliable vmlinux sympos computation; "objtool klp diff" will consume the table in a subsequent commit. Signed-off-by: Josh Poimboeuf --- include/asm-generic/vmlinux.lds.h | 10 +- scripts/Makefile.vmlinux_o | 3 + scripts/livepatch/klp-build | 5 + scripts/mod/modpost.c | 1 + tools/objtool/Build | 1 + tools/objtool/builtin-check.c | 7 ++ tools/objtool/check.c | 7 ++ tools/objtool/include/objtool/builtin.h | 1 + tools/objtool/include/objtool/klp.h | 15 +++ tools/objtool/klp-symid.c | 117 ++++++++++++++++++++++++ 10 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 tools/objtool/klp-symid.c diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinu= x.lds.h index 5659f4b5a125..ee9c5d354a85 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -839,12 +839,20 @@ .stab.index 0 : { *(.stab.index) } \ .stab.indexstr 0 : { *(.stab.indexstr) } =20 +#ifdef CONFIG_KLP_BUILD +#define KLP_SYMID \ + .klp.symid 0 : { *(.klp.symid) } +#else +#define KLP_SYMID +#endif + /* Required sections not related to debugging. */ #define ELF_DETAILS \ .comment 0 : { *(.comment) } \ .symtab 0 : { *(.symtab) } \ .strtab 0 : { *(.strtab) } \ - .shstrtab 0 : { *(.shstrtab) } + .shstrtab 0 : { *(.shstrtab) } \ + KLP_SYMID =20 #define MODINFO \ .modinfo : { *(.modinfo) . =3D ALIGN(8); } diff --git a/scripts/Makefile.vmlinux_o b/scripts/Makefile.vmlinux_o index 527352c222ff..24a3a4fd271c 100644 --- a/scripts/Makefile.vmlinux_o +++ b/scripts/Makefile.vmlinux_o @@ -47,6 +47,9 @@ endif vmlinux-objtool-args-$(CONFIG_NOINSTR_VALIDATION) +=3D --noinstr \ $(if $(or $(CONFIG_MITIGATION_UNRET_ENTRY),$(CONFIG_MITIGATION_S= RSO)), --unret) =20 +# Only used for builds initiated by klp-build +vmlinux-objtool-args-$(if $(KLP_SYMIDS),y) +=3D --klp-symids + objtool-args =3D $(vmlinux-objtool-args-y) --link =20 # Link of vmlinux.o used for section mismatch analysis diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build index a8c103ce7763..f94e324ff53c 100755 --- a/scripts/livepatch/klp-build +++ b/scripts/livepatch/klp-build @@ -271,6 +271,9 @@ validate_config() { [[ -v CONFIG_GCC_PLUGIN_RANDSTRUCT ]] && \ die "kernel option 'CONFIG_GCC_PLUGIN_RANDSTRUCT' not supported" =20 + [[ -v CONFIG_LD_DEAD_CODE_DATA_ELIMINATION ]] && \ + die "kernel option 'CONFIG_LD_DEAD_CODE_DATA_ELIMINATION' not supported" + [[ -v CONFIG_AS_IS_LLVM ]] && \ [[ "$CONFIG_AS_VERSION" -lt 200000 ]] && \ die "Clang assembler version < 20 not supported" @@ -555,6 +558,8 @@ build_kernel() { # cmd+=3D("KBUILD_MODPOST_WARN=3D1") =20 + cmd+=3D("KLP_SYMIDS=3D1") + if [[ -v VERBOSE ]]; then cmd+=3D("V=3D1") else diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index a7b72a81d248..027944fe35b4 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -767,6 +767,7 @@ static const char *const section_white_list[] =3D ".llvm.call-graph-profile", /* call graph */ "__llvm_covfun", "__llvm_covmap", + ".klp.symid", /* objtool --klp-symids */ NULL }; =20 diff --git a/tools/objtool/Build b/tools/objtool/Build index 93a37b0dfd31..506f89bed808 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -6,6 +6,7 @@ objtool-y +=3D check.o objtool-y +=3D special.o objtool-y +=3D builtin-check.o objtool-y +=3D elf.o +objtool-y +=3D klp-symid.o objtool-y +=3D objtool.o =20 objtool-$(BUILD_DISAS) +=3D disas.o diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 118c3de2f293..75b11dc85010 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -76,6 +76,7 @@ static const struct option check_options[] =3D { OPT_STRING_OPTARG('d', "disas", &opts.disas, "function-pattern", "disass= emble functions", "*"), OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake= ", "patch toolchain bugs/limitations", parse_hacks), OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"), + OPT_BOOLEAN(0, "klp-symids", &opts.klp_symids, "generate .klp.symids fo= r duplicate symbol disambiguation"), OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls f= or ftrace"), OPT_BOOLEAN(0, "noabs", &opts.noabs, "reject absolute references in all= ocatable sections"), OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"), @@ -174,10 +175,16 @@ static bool opts_valid(void) return false; } =20 + if (opts.klp_symids && !opts.link) { + ERROR("--klp-symids requires --link"); + return false; + } + if (opts.disas || opts.hack_jump_label || opts.hack_noinstr || opts.ibt || + opts.klp_symids || opts.mcount || opts.noabs || opts.noinstr || diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 10b18cf9c360..4e6366663be1 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -4922,6 +4923,12 @@ int check(struct objtool_file *file) goto out; } =20 + if (opts.klp_symids) { + ret =3D klp_create_symid_sections(file); + if (ret) + goto out; + } + if (opts.noabs) warnings +=3D check_abs_references(file); =20 diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/includ= e/objtool/builtin.h index e844e9c82b7b..349690bb1c50 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -16,6 +16,7 @@ struct opts { bool hack_noinstr; bool hack_skylake; bool ibt; + bool klp_symids; bool mcount; bool noabs; bool noinstr; diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/ob= jtool/klp.h index aab6db42052d..4d3c3bd462aa 100644 --- a/tools/objtool/include/objtool/klp.h +++ b/tools/objtool/include/objtool/klp.h @@ -31,6 +31,21 @@ struct klp_reloc { u32 type; }; =20 +/* + * .klp.symid is used to correlate symbols between vmlinux.o and vmlinux, = for + * calculating sympos to disambiguate duplicately-named symbols. + */ +#define KLP_SYMID_SEC ".klp.symid" + +struct klp_symid { + u64 id; + u64 addr; +}; + +struct objtool_file; + +int klp_create_symid_sections(struct objtool_file *file); + int cmd_klp_checksum(int argc, const char **argv); int cmd_klp_diff(int argc, const char **argv); int cmd_klp_post_link(int argc, const char **argv); diff --git a/tools/objtool/klp-symid.c b/tools/objtool/klp-symid.c new file mode 100644 index 000000000000..cf188cdfa607 --- /dev/null +++ b/tools/objtool/klp-symid.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Emit the .klp.symid table which allows "objtool klp diff" to reliably + * disambiguate duplicate-named local symbols in vmlinux. + * + * Livepatch identifies a duplicate-named symbol by its position (sympos) + * among the same-named kallsyms entries, counted in ascending address ord= er + * in the final linked vmlinux. That order can't be derived from vmlinux.o + * alone: the final link reorders sub-sections (.text.unlikely*, .data..*, + * etc). + * + * Bridge the gap with a table which survives the final link: a single + * non-alloc section containing an array of { id, addr } entries, where + * 'id' is a unique counter identifier and 'addr' has a relocation to the + * symbol. The linker copies 'id' verbatim and resolves 'addr' to the sym= bol's + * final address. + * + * The table is only emitted for vmlinux.o, and only when klp-build asks f= or it + * with KLP_SYMIDS=3D1, which adds --klp-symids to the vmlinux.o objtool r= un. + * + * It can't survive --gc-sections, which sweeps the whole section; klp-bui= ld + * rejects CONFIG_LD_DEAD_CODE_DATA_ELIMINATION. + */ +#include + +#include +#include +#include +#include + +static const char * const discarded_secs[] =3D { + ".discard", + ".modinfo", + "__tracepoint_check", +}; + +static bool discarded_sec(struct section *sec) +{ + if (!(sec->sh.sh_flags & SHF_ALLOC)) + return true; + + for (int i =3D 0; i < ARRAY_SIZE(discarded_secs); i++) + if (strstarts(sec->name, discarded_secs[i])) + return true; + + return false; +} + +static bool symid_needed(struct elf *elf, struct symbol *sym) +{ + struct symbol *s; + + if (!is_local_sym(sym) || is_undef_sym(sym)) + return false; + + if (!is_func_sym(sym) && !is_object_sym(sym)) + return false; + + if (is_prefix_func(sym)) + return false; + + if (discarded_sec(sym->sec)) + return false; + + for_each_sym_by_name(elf, sym->name, s) { + if (s =3D=3D sym || is_sec_sym(s) || is_file_sym(s) || is_undef_sym(s)) + continue; + return true; + } + + return false; +} + +int klp_create_symid_sections(struct objtool_file *file) +{ + struct elf *elf =3D file->elf; + struct klp_symid *symids; + struct section *sec; + struct symbol *sym; + u64 nr =3D 0, i =3D 0; + + if (!str_ends_with(objname, "vmlinux.o")) + return 0; + + for_each_sym(elf, sym) + if (symid_needed(elf, sym)) + nr++; + + if (!nr) + return 0; + + sec =3D elf_create_section(elf, KLP_SYMID_SEC, 0, sizeof(struct klp_symid= ), + SHT_PROGBITS, 8, 0); + if (!sec) + return -1; + + symids =3D elf_add_data(elf, sec, NULL, nr * sizeof(struct klp_symid)); + if (!symids) + return -1; + + for_each_sym(elf, sym) { + if (!symid_needed(elf, sym)) + continue; + + symids[i].id =3D bswap_if_needed(elf, i); + + if (!elf_create_reloc(elf, sec, + i * sizeof(struct klp_symid) + + offsetof(struct klp_symid, addr), + sym, 0, R_ABS64)) + return -1; + + i++; + } + + return 0; +} --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D787839023A; Mon, 3 Aug 2026 03:24:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727494; cv=none; b=G5nUcZf2yZUh3iRJCsFS/aIc3/cLM2K2kezVBcn1layz3RpOKaELzGS18bGcFKnR9ucAbDCU5mHulUACrGC+8UXuLjPMvILb3eU0nmL5xPHWRD2uqD8vnzvR0wamGWVZ0G9l/OjgVVH4Cqsohk+xL+RWyGbqo94Eb12GrNddgFI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727494; c=relaxed/simple; bh=oA9f7bxwNxOoy6P80UEF0cXiqYrypwijWnbw8RZI4qQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RdDs7aGdDx57xwpFOGrKJl/3zAgA06EZ84rvOCKpY8oYmdAPcsXcBgAWDNz6gknE1O9RAPp7H+exB13I9iqEj/aitl+5AM4MxP0BqZGlJvZvKDn8HRRCtMErbPyNYhw8ElXbOJgD2r+GY/i7x2yVDkKZXjXXgMsWObVcwSKpvdA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fwmNdnxT; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fwmNdnxT" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0D9DD1F00A3E; Mon, 3 Aug 2026 03:24:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727492; bh=a8sLyW2mz/hNWPDiEAkdg/YAmqss08QGzlB7RXCIJqc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=fwmNdnxTVFfgtTXmJLdqgFghTC37vRzkHuecVgPeqbclBkKnd2F+pf9kFRf9csv5a ekDLkYQDIitt2v1a1A9McZaAG/1/BjFOFFKI3N+Z3X615xgcnm2nh/vyNddu4EgAX4 xvegfHx+t9iit3qy6JABOi2lQ30O8AKQjO+4JtkUstLZJ+DWAN4z2BvQdI9I4KXkMq QaUym+/fkpIBWpV4KdLcAHZQtCEvJBzT5pFHXsxuvb5cOnNYLiMT6d7I/VEGWyBBki mU0DEDZIiijPu1MPvrActOv0JK8iIzUCKwtPSwenrGQCh2I+9Np6bgRyVPS7RD8t6e ZnRWFKV6ztNfA== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org, Ben Procknow Subject: [PATCH 06/14] objtool/klp: Fix symbol resolution for duplicate data symbols Date: Sun, 2 Aug 2026 20:24:28 -0700 Message-ID: <919785e3bf2245db02ff6391e735d9cb139170b1.1785727106.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" find_sympos() calculates a sympos used by livepatch to disambiguate duplicately-named symbols. For function symbols, there's a hack which counts .text.unlikely symbols before other .text symbols, matching the linker script's section ordering. Not only is the hack fragile, data symbols can have the same problem. So for example, adding a reference to pwq_cache in ep_unregister_pollwait() can trigger a corrupt sympos and a relocation to the wrong pwq_cache symbol in the livepatch module, resulting in a crash or undefined behavior. Remove the existing hack in favor of a fully deterministic solution, using the new .klp.symid table to derive the symbol-to-id mapping from the original vmlinux.o and the id-to-address mapping from the corresponding vmlinux, which can then be used to determine the exact sympos associated with the original vmlinux. Modules don't need any special treatment: the .ko has the same section/symbol ordering as the original whole-archive symbol table. Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffin= g object files") Reported-by: Ben Procknow Reported-by: Joe Lawrence Link: https://lore.kernel.org/20260710153042.3156788-1-joe.lawrence@redhat.= com Link: https://lore.kernel.org/20260724221730.3126529-1-joe.lawrence@redhat.= com Signed-off-by: Josh Poimboeuf --- scripts/livepatch/klp-build | 4 + tools/objtool/Build | 3 +- tools/objtool/include/objtool/klp.h | 5 + tools/objtool/klp-diff.c | 66 +---- tools/objtool/klp-sympos.c | 411 ++++++++++++++++++++++++++++ 5 files changed, 427 insertions(+), 62 deletions(-) create mode 100644 tools/objtool/klp-sympos.c diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build index f94e324ff53c..b52a8489d9f6 100755 --- a/scripts/livepatch/klp-build +++ b/scripts/livepatch/klp-build @@ -611,6 +611,8 @@ copy_orig_objects() { done xtrace_restore =20 + cp -f "$PWD/vmlinux" "$ORIG_DIR" || die "missing vmlinux" + mv -f "$TMP_DIR/build.log" "$ORIG_DIR" touch "$TIMESTAMP" touch "$ORIG_DIR/.complete" @@ -681,6 +683,8 @@ generate_checksums() { "$OBJTOOL" klp checksum "$dest" done =20 + [[ -f "$src_dir/vmlinux" ]] && cp -f "$src_dir/vmlinux" "$dest_dir" + touch "$dest_dir/.complete" } =20 diff --git a/tools/objtool/Build b/tools/objtool/Build index 506f89bed808..59f948628098 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -13,7 +13,8 @@ objtool-$(BUILD_DISAS) +=3D disas.o objtool-$(BUILD_DISAS) +=3D trace.o =20 objtool-$(BUILD_ORC) +=3D orc_gen.o orc_dump.o -objtool-$(BUILD_KLP) +=3D builtin-klp.o klp-checksum.o klp-diff.o klp-post= -link.o +objtool-$(BUILD_KLP) +=3D builtin-klp.o klp-checksum.o klp-diff.o \ + klp-post-link.o klp-sympos.o =20 objtool-y +=3D libstring.o objtool-y +=3D libctype.o diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/ob= jtool/klp.h index 4d3c3bd462aa..0118c2c170c3 100644 --- a/tools/objtool/include/objtool/klp.h +++ b/tools/objtool/include/objtool/klp.h @@ -43,9 +43,14 @@ struct klp_symid { }; =20 struct objtool_file; +struct elf; +struct symbol; =20 int klp_create_symid_sections(struct objtool_file *file); =20 +int klp_sympos_init(struct elf *orig); +unsigned long klp_find_sympos(struct elf *elf, struct symbol *sym); + int cmd_klp_checksum(int argc, const char **argv); int cmd_klp_diff(int argc, const char **argv); int cmd_klp_post_link(int argc, const char **argv); diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index 75ba0e060a34..c5284d275207 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -898,65 +898,6 @@ static int correlate_symbols(struct elfs *e) return 0; } =20 -/* "sympos" is used by livepatch to disambiguate duplicate symbol names */ -static unsigned long find_sympos(struct elf *elf, struct symbol *sym) -{ - bool vmlinux =3D str_ends_with(objname, "vmlinux.o"); - unsigned long sympos =3D 0, nr_matches =3D 0; - bool has_dup =3D false; - struct symbol *s; - - if (sym->bind !=3D STB_LOCAL) - return 0; - - if (vmlinux && is_func_sym(sym)) { - /* - * HACK: Unfortunately, symbol ordering can differ between - * vmlinux.o and vmlinux due to the linker script emitting - * .text.unlikely* before .text*. Count .text.unlikely* first. - * - * TODO: Disambiguate symbols more reliably (checksums?) - */ - for_each_sym(elf, s) { - if (strstarts(s->sec->name, ".text.unlikely") && - !strcmp(s->name, sym->name)) { - nr_matches++; - if (s =3D=3D sym) - sympos =3D nr_matches; - else - has_dup =3D true; - } - } - for_each_sym(elf, s) { - if (!strstarts(s->sec->name, ".text.unlikely") && - !strcmp(s->name, sym->name)) { - nr_matches++; - if (s =3D=3D sym) - sympos =3D nr_matches; - else - has_dup =3D true; - } - } - } else { - for_each_sym(elf, s) { - if (!strcmp(s->name, sym->name)) { - nr_matches++; - if (s =3D=3D sym) - sympos =3D nr_matches; - else - has_dup =3D true; - } - } - } - - if (!sympos) { - ERROR("can't find sympos for %s", sym->name); - return ULONG_MAX; - } - - return has_dup ? sympos : 0; -} - static int clone_sym_relocs(struct elfs *e, struct symbol *patched_sym); =20 static struct symbol *__clone_symbol(struct elf *elf, struct symbol *patch= ed_sym, @@ -1418,7 +1359,7 @@ static int clone_reloc_klp(struct elfs *e, struct rel= oc *patched_reloc, return -1; =20 sym_orig_name =3D patched_sym->twin->name; - sympos =3D find_sympos(e->orig, patched_sym->twin); + sympos =3D klp_find_sympos(e->orig, patched_sym->twin); if (sympos =3D=3D ULONG_MAX) return -1; } @@ -2036,7 +1977,7 @@ static int create_klp_sections(struct elfs *e) =20 /* klp_func_ext.sympos */ BUILD_BUG_ON(sizeof(sympos) !=3D sizeof_field(struct klp_func_ext, sympo= s)); - sympos =3D find_sympos(e->orig, sym->clone->twin); + sympos =3D klp_find_sympos(e->orig, sym->clone->twin); if (sympos =3D=3D ULONG_MAX) return -1; memcpy(func_data + offsetof(struct klp_func_ext, sympos), &sympos, @@ -2190,6 +2131,9 @@ int cmd_klp_diff(int argc, const char **argv) if (!e.orig || !e.patched) return -1; =20 + if (klp_sympos_init(e.orig)) + return -1; + if (read_exports()) return -1; =20 diff --git a/tools/objtool/klp-sympos.c b/tools/objtool/klp-sympos.c new file mode 100644 index 000000000000..bbfae516d339 --- /dev/null +++ b/tools/objtool/klp-sympos.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Compute "sympos", the position used by livepatch to disambiguate + * duplicate symbol names in the patched object. + */ +#include +#include +#include + +#include +#include +#include +#include + +#include + +struct vmlinux_sym { + struct hlist_node hash; + const char *name; + u64 addr; +}; + +struct vmlinux_symid { + struct hlist_node hash; + u64 id; + u64 addr; +}; + +struct vmlinux_o_symid { + struct hlist_node hash; + u64 id; + unsigned int sym_idx; +}; + +static DEFINE_HASHTABLE(vmlinux_o_symids, 16); + +/* + * The original linked kernel, found next to the orig vmlinux.o. Read wit= h raw + * libelf rather than elf_open_read(): only the symbol table and the resol= ved + * .klp.symid table are needed, not the (huge) instruction/reloc machinery. + * + * Both tables are built once by read_orig_vmlinux(). The Elf handle stays + * open because the hashed names point into its mmapped string table. + */ +static struct { + Elf *elf; + DECLARE_HASHTABLE(syms, 16); /* name -> address */ + DECLARE_HASHTABLE(symids, 16); /* .klp.symid id -> address */ +} vmlinux; + +/* + * Would the symbol be visible to the runtime's kallsyms-based symbol look= up? + */ +static bool vmlinux_sym_in_kallsyms(Elf *elf, GElf_Sym *sym) +{ + unsigned int type =3D GELF_ST_TYPE(sym->st_info); + GElf_Shdr shdr; + Elf_Scn *scn; + + if (sym->st_shndx =3D=3D SHN_UNDEF || sym->st_shndx >=3D SHN_LORESERVE) + return false; + + if (type =3D=3D STT_SECTION || type =3D=3D STT_FILE) + return false; + + scn =3D elf_getscn(elf, sym->st_shndx); + if (!scn || !gelf_getshdr(scn, &shdr)) + return false; + + return shdr.sh_flags & SHF_ALLOC; +} + +static int read_orig_vmlinux(const char *filename) +{ + size_t shstrndx, nr_syms =3D 0, nr_symids =3D 0, strtab_idx =3D 0; + Elf_Data *symtab_data =3D NULL, *symid_data =3D NULL; + struct klp_symid *symids; + Elf_Scn *scn =3D NULL; + GElf_Ehdr ehdr; + int fd; + + fd =3D open(filename, O_RDONLY); + if (fd =3D=3D -1) { + ERROR_GLIBC("can't open '%s'", filename); + return -1; + } + + if (elf_version(EV_CURRENT) =3D=3D EV_NONE) { + ERROR_ELF("elf_version"); + return -1; + } + + vmlinux.elf =3D elf_begin(fd, ELF_C_READ_MMAP, NULL); + if (!vmlinux.elf) { + ERROR_ELF("elf_begin"); + return -1; + } + + if (!gelf_getehdr(vmlinux.elf, &ehdr)) { + ERROR_ELF("gelf_getehdr"); + return -1; + } + + if (elf_getshdrstrndx(vmlinux.elf, &shstrndx)) { + ERROR_ELF("elf_getshdrstrndx"); + return -1; + } + + while ((scn =3D elf_nextscn(vmlinux.elf, scn))) { + const char *name; + GElf_Shdr shdr; + + if (!gelf_getshdr(scn, &shdr)) { + ERROR_ELF("gelf_getshdr"); + return -1; + } + + if (shdr.sh_type =3D=3D SHT_SYMTAB) { + symtab_data =3D elf_getdata(scn, NULL); + if (!symtab_data) { + ERROR_ELF("elf_getdata"); + return -1; + } + nr_syms =3D shdr.sh_size / shdr.sh_entsize; + strtab_idx =3D shdr.sh_link; + continue; + } + + name =3D elf_strptr(vmlinux.elf, shstrndx, shdr.sh_name); + if (name && !strcmp(name, KLP_SYMID_SEC)) { + if (shdr.sh_size % sizeof(struct klp_symid)) { + ERROR("%s: %s: struct klp_symid size mismatch", + filename, KLP_SYMID_SEC); + return -1; + } + symid_data =3D elf_getdata(scn, NULL); + if (!symid_data) { + ERROR_ELF("elf_getdata"); + return -1; + } + nr_symids =3D shdr.sh_size / sizeof(struct klp_symid); + } + } + + if (!symtab_data) { + ERROR("%s: missing symbol table", filename); + return -1; + } + + if (!symid_data) { + ERROR("%s: missing %s section, kernel not built with CONFIG_KLP_BUILD?", + filename, KLP_SYMID_SEC); + return -1; + } + + for (size_t i =3D 0; i < nr_syms; i++) { + struct vmlinux_sym *vsym; + const char *name; + GElf_Sym s; + + if (!gelf_getsym(symtab_data, i, &s)) { + ERROR_ELF("gelf_getsym"); + return -1; + } + + if (!vmlinux_sym_in_kallsyms(vmlinux.elf, &s)) + continue; + + name =3D elf_strptr(vmlinux.elf, strtab_idx, s.st_name); + if (!name) + continue; + + vsym =3D calloc(1, sizeof(*vsym)); + if (!vsym) { + ERROR_GLIBC("calloc"); + return -1; + } + + vsym->name =3D name; + vsym->addr =3D s.st_value; + hash_add(vmlinux.syms, &vsym->hash, str_hash(name)); + } + + symids =3D symid_data->d_buf; + + for (size_t i =3D 0; i < nr_symids; i++) { + struct vmlinux_symid *vsymid; + + vsymid =3D calloc(1, sizeof(*vsymid)); + if (!vsymid) { + ERROR_GLIBC("calloc"); + return -1; + } + + vsymid->id =3D __bswap_if_needed(&ehdr, symids[i].id); + vsymid->addr =3D __bswap_if_needed(&ehdr, symids[i].addr); + hash_add(vmlinux.symids, &vsymid->hash, vsymid->id); + } + + /* the fd and Elf handle stay open, the hashed names live in the mmap */ + return 0; +} + +/* + * Read the orig vmlinux.o's .klp.symid table, an array of entries whose '= addr' + * fields have relocs to the symbols they describe. + */ +static int read_vmlinux_o_symids(struct elf *vmlinux_o) +{ + struct section *sec; + + for_each_sec(vmlinux_o, sec) { + unsigned long nr; + + if (strcmp(sec->name, KLP_SYMID_SEC)) + continue; + + if (sec_size(sec) % sizeof(struct klp_symid)) { + ERROR("%s: %s: struct klp_symid size mismatch", + vmlinux_o->name, KLP_SYMID_SEC); + return -1; + } + + nr =3D sec_size(sec) / sizeof(struct klp_symid); + + for (unsigned long i =3D 0; i < nr; i++) { + unsigned long offset =3D i * sizeof(struct klp_symid); + struct vmlinux_o_symid *entry; + struct klp_symid *symid; + struct reloc *reloc; + + entry =3D calloc(1, sizeof(*entry)); + if (!entry) { + ERROR_GLIBC("calloc"); + return -1; + } + + symid =3D sec->data->d_buf + offset; + entry->id =3D bswap_if_needed(vmlinux_o, symid->id); + + reloc =3D find_reloc_by_dest(vmlinux_o, sec, + offset + offsetof(struct klp_symid, addr)); + if (!reloc) { + ERROR("%s: missing reloc for %s entry", + vmlinux_o->name, KLP_SYMID_SEC); + return -1; + } + entry->sym_idx =3D reloc->sym->idx; + + hash_add(vmlinux_o_symids, &entry->hash, entry->sym_idx); + } + } + + return 0; +} + +int klp_sympos_init(struct elf *orig) +{ + char *filename; + int ret; + + if (!str_ends_with(objname, "vmlinux.o")) + return 0; + + if (read_vmlinux_o_symids(orig)) + return -1; + + filename =3D strndup(objname, strlen(objname) - 2); + if (!filename) { + ERROR_GLIBC("strndup"); + return -1; + } + + ret =3D read_orig_vmlinux(filename); + free(filename); + + return ret; +} + +/* Find the symbol's id in the orig vmlinux.o's .klp.symid table */ +static int find_vmlinux_o_symid(struct symbol *sym, u64 *id) +{ + struct vmlinux_o_symid *entry; + + hash_for_each_possible(vmlinux_o_symids, entry, hash, sym->idx) { + if (entry->sym_idx =3D=3D sym->idx) { + *id =3D entry->id; + return 0; + } + } + + ERROR("no %s entry for symbol %s in orig vmlinux.o", KLP_SYMID_SEC, + sym->name); + return -1; +} + +/* Find the symbol's final address in the orig vmlinux's .klp.symid table = */ +static int find_vmlinux_symid_addr(u64 id, u64 *addr) +{ + struct vmlinux_symid *symid; + + hash_for_each_possible(vmlinux.symids, symid, hash, id) { + if (symid->id =3D=3D id) { + *addr =3D symid->addr; + return 0; + } + } + + return -1; +} + +/* + * Find the sympos of a vmlinux-local symbol by ranking its final address + * among the duplicately named symbols in the linked orig vmlinux, replica= ting + * the order in which kallsyms_on_each_match_symbol() counts them. + */ +static unsigned long find_vmlinux_sympos(struct symbol *sym) +{ + unsigned long nr_matches =3D 0, sympos =3D 1; + u32 key =3D str_hash(sym->name); + struct vmlinux_sym *vsym; + bool found =3D false; + u64 id, addr; + + hash_for_each_possible(vmlinux.syms, vsym, hash, key) + if (!strcmp(vsym->name, sym->name)) + nr_matches++; + + if (!nr_matches) { + ERROR("can't find symbol %s in orig vmlinux", sym->name); + return ULONG_MAX; + } + + /* + * Unique symbols don't need disambiguating. They also have no + * .klp.symid entry, which is only emitted for names duplicated in + * vmlinux.o, so the lookups below would fail. + */ + if (nr_matches =3D=3D 1) + return 0; + + if (find_vmlinux_o_symid(sym, &id)) + return ULONG_MAX; + + if (find_vmlinux_symid_addr(id, &addr)) { + ERROR("no %s entry for symbol %s in orig vmlinux", KLP_SYMID_SEC, + sym->name); + return ULONG_MAX; + } + + hash_for_each_possible(vmlinux.syms, vsym, hash, key) { + if (strcmp(vsym->name, sym->name)) + continue; + + if (vsym->addr < addr) + sympos++; + else if (vsym->addr =3D=3D addr) + found =3D true; + } + + if (!found) { + ERROR("%s address mismatch for symbol %s, stale orig vmlinux?", + KLP_SYMID_SEC, sym->name); + return ULONG_MAX; + } + + return sympos; +} + +/* + * "sympos" is used by livepatch to disambiguate duplicate symbol names. + */ +unsigned long klp_find_sympos(struct elf *elf, struct symbol *sym) +{ + unsigned long sympos =3D 0, nr_matches =3D 0; + bool has_dup =3D false; + struct symbol *s; + + if (sym->bind !=3D STB_LOCAL) + return 0; + + /* + * vmlinux: the final link reorders symbols relative to vmlinux.o, + * so the position needs to be derived from the linked orig vmlinux via + * the .klp.symid table. + */ + if (vmlinux.elf) + return find_vmlinux_sympos(sym); + + /* + * modules: the final .ko preserves symbol table order, so a + * symtab-order count here matches the runtime count done by + * module_kallsyms_on_each_symbol(). + */ + for_each_sym(elf, s) { + if (!strcmp(s->name, sym->name)) { + nr_matches++; + if (s =3D=3D sym) + sympos =3D nr_matches; + else + has_dup =3D true; + } + } + + if (!sympos) { + ERROR("can't find sympos for %s", sym->name); + return ULONG_MAX; + } + + return has_dup ? sympos : 0; +} --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7EC80373C1D; Mon, 3 Aug 2026 03:24:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727494; cv=none; b=M1yddcLSzLdF1/HCIQGrIrq0SRLKsnSMpZQkhAQnsnKsNdnvHjnkZntMNoBCXMmIrnw6MZkZL/HnOjDxJSzLh3/kHR9luDG6oSQonjUq1Aok43pD5e24OwRw4XLrdmf7zUgcWln8eBsQ58lSsru4iIOlXb1DLMHhA8WoK5n5wgM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727494; c=relaxed/simple; bh=bUEz3yqIl8iuF01MWVluUFvE0Y6OJbyCUpjOZrRlAgs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WZRuQhjmoh4+A2zN9iINugL1o6dUIZi0haPsp9s0vvLM9ng0QrAvI/ACzVFKrjsGvOafUdJBgNs8Vp3zfRUScE1Q2UoMTawsdqkTLsGRCTXRRRoLcoR3PG41Q9Hr5GOTUneOYv59EVWc9CkrROWHmwrprygyI4JfHqogs2JIY+E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nxouAoRE; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nxouAoRE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E8C751F00A3D; Mon, 3 Aug 2026 03:24:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727493; bh=bXyObPR/zEH+klDXuuVkfmL3pol8wEVXP2QY5Sl8GMw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=nxouAoREg35Py8dGTbDj8nMQEKyVej5fchUKvtO9+pRF/XCuSARVlotnpzr/Ky4EY nQ2sA0h9pxn2c9YVFzeJn3B5jtg0pIs8JoTbN6MzVhgnDZ9rgw2opatJITyFmAf6L6 9w6u7YRsPOx9qgW3oKhQVA6nzmFZUlcUsxy+/QEJXEk9kFxEQoIzC3d4t9Uyj14I3Q 9P9lRv2owUtrdNxTvFzM0oseYrYotslpD2jNyKdOcq64rACA7D96BHsmsj6/yp1IMl 2Bcw++mSfukemqwlxpaF+jvAev0PVztkQfSK5rfFG4J/wCRlZnA7crvCn/BFG8iXbm Edwk84gQcy/5Q== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org Subject: [PATCH 07/14] module: Add module_kallsyms_on_each_core_symbol() Date: Sun, 2 Aug 2026 20:24:29 -0700 Message-ID: <9ff8d9f0ad20a9a5cdbab3fe650d3532688065d4.1785727106.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" module_kallsyms_on_each_symbol() iterates mod->kallsyms, which points at the full init symbol table until do_init_module() swaps it out. The set of symbols it reports thus differs based on whether init memory has been freed yet. Add module_kallsyms_on_each_core_symbol() for callers which need a symbol's position to be the same before and after that swap. core_kallsyms is fully populated by add_kallsyms() before the module leaves MODULE_STATE_UNFORMED, so it's readable on both paths. Signed-off-by: Josh Poimboeuf --- include/linux/module.h | 11 ++++++++++ kernel/module/kallsyms.c | 46 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/include/linux/module.h b/include/linux/module.h index 7566815fabbe..4ea4522a5fc5 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -947,6 +947,9 @@ static inline bool module_sig_ok(struct module *module) int module_kallsyms_on_each_symbol(const char *modname, int (*fn)(void *, const char *, unsigned long), void *data); +int module_kallsyms_on_each_core_symbol(const char *modname, + int (*fn)(void *, const char *, unsigned long), + void *data); =20 /* For kallsyms to ask for address resolution. namebuf should be at * least KSYM_NAME_LEN long: a pointer to namebuf is returned if @@ -984,6 +987,14 @@ static inline int module_kallsyms_on_each_symbol(const= char *modname, return -EOPNOTSUPP; } =20 +static inline int +module_kallsyms_on_each_core_symbol(const char *modname, + int (*fn)(void *, const char *, unsigned long), + void *data) +{ + return -EOPNOTSUPP; +} + /* For kallsyms to ask for address resolution. NULL means not found. */ static inline int module_address_lookup(unsigned long addr, unsigned long *symbolsize, diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c index 0fc11e45df9b..3a959c3c9f9b 100644 --- a/kernel/module/kallsyms.c +++ b/kernel/module/kallsyms.c @@ -494,3 +494,49 @@ int module_kallsyms_on_each_symbol(const char *modname, mutex_unlock(&module_mutex); return ret; } + +/* + * Iterate @modname's cut-down core symbol table, rather than mod->kallsyms + * which points at the full init symbol table until do_init_module() swaps= it + * out. For callers which need a symbol's position to be the same before = and + * after that swap. + * + * core_kallsyms is populated by add_kallsyms(), which runs before the mod= ule + * leaves MODULE_STATE_UNFORMED. + * + * Unlike module_kallsyms_on_each_symbol(), @modname is required. + */ +int module_kallsyms_on_each_core_symbol(const char *modname, + int (*fn)(void *, const char *, unsigned long), + void *data) +{ + struct mod_kallsyms *kallsyms; + struct module *mod; + unsigned int i; + int ret =3D 0; + + if (!modname) + return -EINVAL; + + guard(mutex)(&module_mutex); + + mod =3D find_module_all(modname, strlen(modname), false); + if (!mod) + return -ENOENT; + + kallsyms =3D &mod->core_kallsyms; + + for (i =3D 0; i < kallsyms->num_symtab; i++) { + const Elf_Sym *sym =3D &kallsyms->symtab[i]; + + if (sym->st_shndx =3D=3D SHN_UNDEF) + continue; + + ret =3D fn(data, kallsyms_symbol_name(kallsyms, i), + kallsyms_symbol_value(sym)); + if (ret) + break; + } + + return ret; +} --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 27D3B391E43; Mon, 3 Aug 2026 03:24:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727495; cv=none; b=To8nIFpDOg2gzBJW56mKcousr5v4PBqT7w8QPXNTNN9elohAiWZlL7ahvTUYZihNPJWxo+fm90tcubk4EfvkqBr9EROz4suWK9oeeNCslbl7xU8IwnTzgeST7NrPk6GwkB4ChPMb5G6bStAYDDF4aTraDnZdas+e6D5MI9hYrtM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727495; c=relaxed/simple; bh=7UdaWpnVIE736Mk7BnSI2ZSkJ80xsg646MFdfbDpSgs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NT014lf67mKdyqTqpWaZTlPrDH85lgETd/LZ8BiV2pVmUUoCaP/xs96tgUcWQ9noFKZV9OsRk60IMSWZLt4DH0ghi6GmBOUkzwpJPYHEIxVAwtqWyJBVd+xn0gVjqKMMAqiLNZI8Mp0+sHNVU4jZemZkF8vPOZDemz2B4ud24+c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=oyIllUND; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="oyIllUND" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 90FFE1F00A3A; Mon, 3 Aug 2026 03:24:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727494; bh=6JCZVECoVabjRcONCFF8XMvs1d1PU2OtlptWsM4DRsc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=oyIllUND6NpMlZ8jQ6auVdQyxkQ8ByItEj2ENepga4Ljis2JFDe3Qjo25cpswS7ue j4Yvp0RiexEf1Tfov6naJppkoPuLi5xizYwXE2/qyQbJ/1jhO9rTBYtYIH7bvHnUBK TM6mDlUEse1gheC7CPQdSx8O5v4aSvo/ThIhjeUSTGNqApvOEOGVpBHMuBaTiKViiK 0e8q1MkXtmAFg9+ftfyO4WB2KuP9WIO4LQFPZwchj5jx6CrvXc6NUyzht8W3xFeA3d sB+zkS4M/2qsSehpmjdr50/soUHrltOCm4flbRn5o02DLuKO4i6HKx/tdWneFsNnuy fUhVs1kxHZg+Q== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org Subject: [PATCH 08/14] objtool/klp,livepatch: Resolve module symbols against core kallsyms Date: Sun, 2 Aug 2026 20:24:30 -0700 Message-ID: <5f7b6798592b20c6b4accb725ba87849f3224f2c.1785727106.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" For patching a module, klp_find_sympos() counts every symbol table entry whose name matches. However, the module loader only includes symbols matched by is_core_symbol(). The runtime count is inconsistent as well. It's done by module_kallsyms_on_each_symbol(), which iterates the full init symbol table until do_init_module() swaps in the cut-down core table, so the same symbol can have different positions depending on whether init memory has been freed yet. Define a module's sympos as its position in the core symbol table, which is what sympos already means for a live module and what users see in /proc/kallsyms. Enforce that on both ends: count with module_kallsyms_on_each_core_symbol() at runtime, and mirror the is_core_symbol() filter in objtool with a new mod_sym_in_kallsyms() helper. The init-layout half of the filter is only correct if .exit sections are core sections, which requires CONFIG_MODULE_UNLOAD, otherwise .exit code is laid out as part of init memory and freed after module init. Enforce CONFIG_MODULE_UNLOAD to ensure that behavior is deterministic. Symbols which exist only in init sections are no longer resolvable, but they never were once the module went live, and init memory is freed after module init anyway. Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffin= g object files") Fixes: b2b018ef4867 ("livepatch: add old_sympos as disambiguator field to k= lp_func") Signed-off-by: Josh Poimboeuf --- kernel/livepatch/core.c | 2 +- scripts/livepatch/klp-build | 3 +++ tools/objtool/klp-sympos.c | 22 +++++++++++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 28d15ba58a26..a05cd2c38caa 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -168,7 +168,7 @@ static int klp_find_object_symbol(const char *objname, = const char *name, }; =20 if (objname) - module_kallsyms_on_each_symbol(objname, klp_find_callback, &args); + module_kallsyms_on_each_core_symbol(objname, klp_find_callback, &args); else kallsyms_on_each_match_symbol(klp_match_callback, name, &args); =20 diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build index b52a8489d9f6..9b375e018d76 100755 --- a/scripts/livepatch/klp-build +++ b/scripts/livepatch/klp-build @@ -265,6 +265,9 @@ validate_config() { [[ -v CONFIG_KLP_BUILD ]] || \ die "CONFIG_KLP_BUILD not enabled" =20 + [[ -v CONFIG_MODULE_UNLOAD ]] || \ + die "kernel option 'CONFIG_MODULE_UNLOAD' required" + [[ -v CONFIG_GCC_PLUGIN_LATENT_ENTROPY ]] && \ die "kernel option 'CONFIG_GCC_PLUGIN_LATENT_ENTROPY' not supported" =20 diff --git a/tools/objtool/klp-sympos.c b/tools/objtool/klp-sympos.c index bbfae516d339..34bb8d1971bd 100644 --- a/tools/objtool/klp-sympos.c +++ b/tools/objtool/klp-sympos.c @@ -367,6 +367,17 @@ static unsigned long find_vmlinux_sympos(struct symbol= *sym) return sympos; } =20 +static bool mod_sym_in_kallsyms(struct symbol *sym) +{ + if (is_undef_sym(sym)) + return false; + + if (!(sym->sec->sh.sh_flags & SHF_ALLOC)) + return false; + + return !strstarts(sym->sec->name, ".init"); +} + /* * "sympos" is used by livepatch to disambiguate duplicate symbol names. */ @@ -387,12 +398,21 @@ unsigned long klp_find_sympos(struct elf *elf, struct= symbol *sym) if (vmlinux.elf) return find_vmlinux_sympos(sym); =20 + if (!mod_sym_in_kallsyms(sym)) { + ERROR("symbol %s is not visible to module kallsyms, can't compute sympos= ", + sym->name); + return ULONG_MAX; + } + /* * modules: the final .ko preserves symbol table order, so a * symtab-order count here matches the runtime count done by - * module_kallsyms_on_each_symbol(). + * module_kallsyms_on_each_core_symbol(). */ for_each_sym(elf, s) { + if (!mod_sym_in_kallsyms(s)) + continue; + if (!strcmp(s->name, sym->name)) { nr_matches++; if (s =3D=3D sym) --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C37C5392814; Mon, 3 Aug 2026 03:24:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727496; cv=none; b=FeELwEQlHQPBjoimMDxnhIoUbhV7XoMsRl+7UrvyRQhSTd7rDsq2t2SVwtNlnFOeJd8DfcHKVYeLG2MYpIUZWFgyzYEiebOjhJ6oon/5zYQ0gFi+rv24nXljO2I3E8ujHMKM/o6s6Q7eiQBUeFJe9kI4vgQzJ1R52r9etz3mC+Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727496; c=relaxed/simple; bh=PuGIeosLNrzN5dfJ1oAkMZpQui+o3DA7pVKICpEQZhY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RkfxggUNR8sOTc2o6cLFaiUUtGKDdB8Od9YZOb/AJZNTGfhjswR/8MeaFT/C5tvAFWbSyMJL7oNNrB0ytANUK5gWViv2Qn/9F+XNH6fYAXl4bNqVq0IjwTzzpxl+OwENzPnD2fppsh9ODp6BmvBHNZxp9OIZHN7gqH8xwwCdJh8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NeDxU+VF; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NeDxU+VF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 38DC91F00A3F; Mon, 3 Aug 2026 03:24:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727494; bh=c0QHyf3cRfjHH7dzTa7UwEKGKmVjGoKvql1dFCIHago=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=NeDxU+VFw7ofIsTFqcyVmGDeOrX0ovoSZbGbRZP128WZ+5TEr7S9tmjg0VO4P+woH BKN+Shk7DFWlJWjKDv6JlEABD/xWKUjfoxmt2lbUbDvkzn+v5vgZbcuzuUqlxw3H5c 5hVeka9oqd8AB0cRAvGsZUx9q5VhuC3ucWtz0d4pfLU6974BUMsJJSRKHnvAZfrfVJ WZwNKAIWgcFKEsCv+C2z5UbMrLHACTFxco+JgPsL89CnnvcYrkF6Wi7Y75wB5rQ+MT 6Of+aM108lbbU7g18GAeNze0827kWnvNS5peAEuf6avXJAvlH6Sv2ahzgjSKzBPRAs eh0jMXI/7SL1A== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org Subject: [PATCH 09/14] objtool/klp: Fix size of empty special section entries Date: Sun, 2 Aug 2026 20:24:31 -0700 Message-ID: X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" create_fake_symbols() sizes each ANNOTATE_DATA_SPECIAL entry from the offset of the next annotation, falling back to the end of the section for the last entry. But the last entry is detected by a zero size, which also happens for an *empty* entry: ALTERNATIVE(oldinstr, "", ft) still annotates its zero-length replacement, at the same offset as the next entry's annotation. So every empty replacement gets a fake symbol spanning the entire rest of .altinstr_replacement. That's harmless today only because find_symbol_containing() picks the smaller of two overlapping symbols. Track whether a next annotation was found rather than inferring it from the size. A zero-length fake symbol is fine: find_symbol_containing() skips those, so the properly sized symbol at the same offset still wins. Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffin= g object files") Signed-off-by: Josh Poimboeuf --- tools/objtool/klp-diff.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index c5284d275207..257e7f924928 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -1628,6 +1628,7 @@ static int create_fake_symbols(struct elf *elf) for_each_reloc(sec->rsec, reloc) { unsigned long offset, size; struct reloc *next_reloc; + bool last =3D true; =20 if (annotype(elf, sec, reloc) !=3D ANNOTYPE_DATA_SPECIAL) continue; @@ -1642,10 +1643,11 @@ static int create_fake_symbols(struct elf *elf) continue; =20 size =3D reloc_addend(next_reloc) - offset; + last =3D false; break; } =20 - if (!size) + if (last) size =3D sec_size(reloc->sym->sec) - offset; =20 if (create_fake_symbol(elf, reloc->sym->sec, offset, size)) --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6933D36D9E9; Mon, 3 Aug 2026 03:24:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727497; cv=none; b=O6jehoyT4uw/OoxRa86cAW7fijv7+pBi1eshqM4vO12Kn+L6YiLhjHExRELXbFAdaXubkh/b1lkHztHNIbJE5d+K2qHo1LgmtIb60j46DzVw10dcCqVguqW8x2LryZrVfgEQPnaDPP8mvlvlw4u9LPP5wz7cCLyi6jBJCpi+LVU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727497; c=relaxed/simple; bh=+i6d5aIZoP6EZsiI43w/o9faePszHVo7G+PuVfaNO7A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oUPBFs/UTRjeca3ZZ37yhOo6+xYpVyyF0xP3oYzxwCs23i1TuZSW1+Nuch+RHJaALZ1iV3mZeZTdZy3BkvqbqlmP8sFZlVVsUF4aq3qNVURAwSjc56zAfA5KDd0QVHfR5y29cFOmdubloOKIBvcb4ZnuvODuX+ORzlrOzWIEFAQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YZCrFjjw; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YZCrFjjw" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D41571F000E9; Mon, 3 Aug 2026 03:24:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727495; bh=4oZotfaHgciDLlJjYrspLV8HQAzomvenh71Q/xI58mY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=YZCrFjjwaCyM+erXNydkp1U8xJjKUXuxcfxQ1NIa7AgD47NlVWeNuLYAxrlRUfb3T ig5P1UyzElF2x1ybRFm5KHCfkPltdM1Mv3HhCSUoxgh/vNLk5jfYFQkxNhmVgy1770 Ck3ZUiMRcafJvFc5Lxg5RK7BKdg9nPhOjEjsqHkg2Ma4i3v/X/+8mdAXLA3nxhR5h0 VHoMyOUWdRDRrZDfb1ApjnCN7HFmo1vfsyE7MacvI9O0PYl1D1oOJBvMr0Deb2s1Gm zLBtRa0LkIjPNAs8DqNzxLWQs3hre5NeK7TVpCcVNBLH0v0PcdaRJaEn4qr5i+pSjE QqJ5zPtNrSLMw== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org Subject: [PATCH 10/14] objtool/klp: Ignore replacement offset of empty x86 alternatives Date: Sun, 2 Aug 2026 20:24:32 -0700 Message-ID: X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" An x86 alternative with an empty replacement, e.g. the second entry of ALTERNATIVE_2("orig", "repl", ft1, "", ft2) has a replacementlen of zero. Its replacement offset still gets a relocation, but the label it points at is the end of the previous replacement, which is also the beginning of the *next* alternative's replacement. The value is meaningless; get_alt_entry() already ignores it for that reason. klp diff doesn't ignore it. When such an alternative belongs to a changed function, cloning its relocations drags in the unrelated neighboring replacement, along with everything that replacement references. On an x86 clang/lto build an empty alternative in meminfo_proc_show() pulled in the replacement of an alternative in proc_kcore_init(), silently emitting a klp relocation against init text which has long since been freed by the time the patch is applied. Add arch_alt_ignore_new_reloc() and skip such relocations when cloning. This has to be arch specific: on arm64 a zero-length replacement instead identifies an alternative callback, whose replacement offset points at the callback function and must be preserved. Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffin= g object files") Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/x86/special.c | 27 +++++++++++++++++++++++++ tools/objtool/include/objtool/special.h | 7 +++++++ tools/objtool/klp-diff.c | 6 +++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/tools/objtool/arch/x86/special.c b/tools/objtool/arch/x86/spec= ial.c index e817a3fff449..1e84c81bfcd8 100644 --- a/tools/objtool/arch/x86/special.c +++ b/tools/objtool/arch/x86/special.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include =20 +#include #include #include #include @@ -9,6 +10,32 @@ /* cpu feature name array generated from cpufeatures.h */ #include "cpu-feature-names.c" =20 +/* + * An alternative with an empty replacement, e.g. the second entry of + * + * ALTERNATIVE_2("orig", "repl", ft1, "", ft2) + * + * still gets a relocation for its replacement offset. But the label it p= oints + * at is the end of the previous entry's replacement, which is also the + * beginning of the *next* entry's replacement. The value is meaningless:= it's + * only ever used with a length of zero. + */ +bool arch_alt_ignore_new_reloc(struct section *sec, unsigned long offset) +{ + unsigned long entry_off; + + if (strcmp(sec->name, ".altinstructions")) + return false; + + entry_off =3D offset - (offset % ALT_ENTRY_SIZE); + + if (offset - entry_off !=3D ALT_NEW_OFFSET) + return false; + + return !*(unsigned char *)(sec->data->d_buf + entry_off + + ALT_NEW_LEN_OFFSET); +} + void arch_handle_alternative(struct special_alt *alt) { static struct special_alt *group, *prev; diff --git a/tools/objtool/include/objtool/special.h b/tools/objtool/includ= e/objtool/special.h index 121c3761899c..620dbf6cb0e5 100644 --- a/tools/objtool/include/objtool/special.h +++ b/tools/objtool/include/objtool/special.h @@ -32,6 +32,13 @@ int special_get_alts(struct elf *elf, struct list_head *= alts); =20 void arch_handle_alternative(struct special_alt *alt); =20 +/* + * Should the reloc at @offset -- the "new" (replacement) field of a speci= al + * section group entry -- be ignored? The meaning of a zero-length replac= ement + * is arch specific, so the arch decides. + */ +bool arch_alt_ignore_new_reloc(struct section *sec, unsigned long offset); + bool arch_support_alt_relocation(struct special_alt *special_alt, struct instruction *insn, struct reloc *reloc); diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index 257e7f924928..cf6fc88bc979 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include =20 #include #include @@ -1538,6 +1538,10 @@ static int clone_sym_relocs(struct elfs *e, struct s= ymbol *patched_sym) !strcmp(patched_reloc->sym->sec->name, ".altinstr_aux")) continue; =20 + if (arch_alt_ignore_new_reloc(patched_sym->sec, + reloc_offset(patched_reloc))) + continue; + ret =3D convert_reloc_sym(e->patched, patched_reloc); if (ret < 0) { ERROR_FUNC(patched_rsec->base, reloc_offset(patched_reloc), --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1020F3955EA; Mon, 3 Aug 2026 03:24:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727497; cv=none; b=NMUmkp0sO+DnbAZ5JJp2pPKF9vvesaVC+p/QEy9aVrIoMfQm5DZvS7m8ilfzI4VRm3raTRtCKjfaV6XomWmVb+FBtWNNFpF1/qFdY51Uiz9TEkh37dPt78uQzYyAPfLzkvkDD2LuhbqueVdnN7MHHS7oHWiwu+uvW4MS8aaYSmw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727497; c=relaxed/simple; bh=b0sitHEDJCrx7PwDglHA6q7PhKYS+wmgi4ZdRtViPgE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gC42SjxTzWcCl48U12WBeuVZ3j9cV1K+ElfXKdqFPzgIEfIriN4Sw5Dd5uLa0R85UbDrVBjjAOiH8k3Wk+SrFwd5bXmhzvhnM2IunVSlSWAXMOg4TVwVlaa1lvRpJu70/r/f/e160BHsqyymEUkuEBjGJpQ6KaBn/gniBu6OVy4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dCdLmmIm; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dCdLmmIm" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 79ADC1F00AC4; Mon, 3 Aug 2026 03:24:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727496; bh=BbrA5q9AP0CghmcFrzT+3c7jTk5wM+gvdhHzAOQna00=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=dCdLmmImKzjrSYXcWCjYq4qHD5iVxQgrhNAluSgmjy+Cxxw5sGrlceWnlg3icmS46 eKAPb8+MP+bR5eOpkeGw34hxsLceRv/DSjXEU1xpQlviePQQfgA937DNS+hjyPB1wg RfEvHttGD3WHLsIFda+Ni6orBFZBldtWtpNCK4IK609DX5Kyf/pRaVzsqZqueVFEGf uXOXJhLS/FsLxYqBniIqm5Ib4VSkw94ZMdzi5yOHKW5PCswKDyTOYS/pAVdSM1hOnh d9NgPs9qLpSfo2NC3qjzE8iX+OFrxB0ArhCmZlfv1Mau7b4z8HL4VqrLk4cFny+Xl1 D6w/e2ngz/G1g== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org Subject: [PATCH 11/14] objtool/klp: Explicitly disallow patching or referencing init code/data Date: Sun, 2 Aug 2026 20:24:33 -0700 Message-ID: X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Explicitly disallow the patching and referencing of init code/data. Otherwise it could potentially introduce some odd edge cases depending on whether the target object's init section has been freed yet (note that the init code still exists in the target module when doing late module patching). Such edge cases include sympos calculation and the patching and/or referencing of non-existent (init-freed) code/data. Not to mention the inherent differences in behavior that occur when the init code is only patched *some* of the time depending on module loading order or kernel config. Signed-off-by: Josh Poimboeuf --- tools/objtool/klp-sympos.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/objtool/klp-sympos.c b/tools/objtool/klp-sympos.c index 34bb8d1971bd..822ac53cfa47 100644 --- a/tools/objtool/klp-sympos.c +++ b/tools/objtool/klp-sympos.c @@ -378,6 +378,11 @@ static bool mod_sym_in_kallsyms(struct symbol *sym) return !strstarts(sym->sec->name, ".init"); } =20 +static bool is_init_sym(struct symbol *sym) +{ + return strstarts(sym->sec->name, ".init"); +} + /* * "sympos" is used by livepatch to disambiguate duplicate symbol names. */ @@ -387,6 +392,11 @@ unsigned long klp_find_sympos(struct elf *elf, struct = symbol *sym) bool has_dup =3D false; struct symbol *s; =20 + if (is_init_sym(sym)) { + ERROR("%s: can't patch or reference init code/data", sym->name); + return ULONG_MAX; + } + if (sym->bind !=3D STB_LOCAL) return 0; =20 --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AA259395D8E; Mon, 3 Aug 2026 03:24:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727498; cv=none; b=Ysn9p6IwkzXBbeRXl9WTznnnA88NIXpv7usDzn4hu8NGUly4CC/E/QjOAY788pBaFagAhMx6xBWfsFTw6qRquzYnOx3d0yQ71MeXTVo7H0OQAIm5NNGyIlzfakdhKxzvzEaj8oZQObQ6MLsLNwyJOcJF5ClXeicjLK2d9q2yd0o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727498; c=relaxed/simple; bh=xPMENNhQBL6lFPj1d9G+D34RBjCYE6XR0+W9ewH4IU0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LkqbQXS6EhJznWOiukSp9DwUldzmN78O/VJFdaPpH9DP8HapcwDaXKwX4ccnZyLztOICJt254vKAUz+brA9XSYkwzblORdu29q3d9Wo9cG1Inm1WoWLBqCuedjyAXYeynZ/gcT9gW9R9ZqtP9h4oXjJ0zJ7fPIOF6mJ8C291FKs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lcs4TPVb; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="lcs4TPVb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1FFDF1F00A3A; Mon, 3 Aug 2026 03:24:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727496; bh=UCXceDpiSjckCGGNo0/VCNE3Q9AtPYJCsZMAg9+B+uM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=lcs4TPVbvy8piF5FBbZywkBq+nfA6zcr2k38UFyhPfKpwg83PUydoTQNgiZvXc4yz 77YURzss+0KFq5KzTHQqGuKs7MtxjHXjQTEsEOYDipFQFHBorHAncILragHINxpfoG 9VI2mQBi0EQ++HwiH+XlKr938MOR1l5BfBGy89s7x1JUS/+DW/z/xm3SKBbmvD+BoI sOQnOSFkfSyOVnUJNJkHP0JPdUqBsAJ0q9Hv83SBXYQIFEaej5ELFETdCuEXLClJSe JvnlIwk3Dvq26R7sBBvqGp4MDHFLd0hnjmikakaxCbK8HHNr/34989zRZgFrqMRmn2 l+d2SnCqedMbg== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org Subject: [PATCH 12/14] objtool/klp: Fix cross-module klp relocation section naming Date: Sun, 2 Aug 2026 20:24:34 -0700 Message-ID: X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" A klp relocation section is .klp.rela.., where objname is the object being patched. klp-build wrongly derives objname from where the referenced symbol lives, not where it's referenced. For a cross-module reference like patched can_isotp code calling can.ko's can_rx_unregister(), that gives .klp.rela.can..text rather than .klp.rela.can_isotp..text. Unless the patch happens to patch can.ko as well, the relocation never gets applied and the call goes off into the weeds. Name the intermediate section __klp_relocs. so post-link can read the patched object's name from there. Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffin= g object files") Reported-by: Joe Lawrence Link: https://lore.kernel.org/20260720145658.1103243-2-joe.lawrence@redhat.= com Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/klp.h | 10 ++++-- tools/objtool/klp-diff.c | 17 +++++++-- tools/objtool/klp-post-link.c | 53 +++++++++++++++++------------ 3 files changed, 52 insertions(+), 28 deletions(-) diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/ob= jtool/klp.h index 0118c2c170c3..646d8e1f12ef 100644 --- a/tools/objtool/include/objtool/klp.h +++ b/tools/objtool/include/objtool/klp.h @@ -14,11 +14,15 @@ #define KLP_FUNCS_SEC ".init.klp_funcs" =20 /* - * __klp_relocs is an intermediate section which are created by klp diff a= nd - * converted into KLP symbols/relas by "objtool klp post-link". This is n= eeded - * to work around the linker, which doesn't preserve SHN_LIVEPATCH or + * __klp_relocs. are intermediate sections which are created by k= lp + * diff and converted into KLP symbols/relas by "objtool klp post-link". = This + * is needed to work around the linker, which doesn't preserve SHN_LIVEPAT= CH or * SHF_RELA_LIVEPATCH, nor does it support having two RELA sections for a * single PROGBITS section. + * + * "objname" is the name of the object being patched ("vmlinux" or a module + * name). post-link uses it to name the resulting + * .klp.rela.objname.section_name sections. */ #define KLP_RELOCS_SEC "__klp_relocs" #define KLP_STRINGS_SEC ".rodata.klp.str1.1" diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index cf6fc88bc979..e00dbe053a6e 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -1381,8 +1381,8 @@ static int clone_reloc_klp(struct elfs *e, struct rel= oc *patched_reloc, } =20 /* - * Create the __klp_relocs entry. This will be converted to an actual - * KLP rela by "objtool klp post-link". + * Create the __klp_relocs. entry. This will be converted to + * an actual KLP rela by "objtool klp post-link". * * This intermediate step is necessary to prevent corruption by the * linker, which doesn't know how to properly handle two rela sections @@ -1390,7 +1390,18 @@ static int clone_reloc_klp(struct elfs *e, struct re= loc *patched_reloc, */ =20 if (!klp_relocs) { - klp_relocs =3D elf_create_section(e->out, KLP_RELOCS_SEC, 0, + const char *objname =3D find_modname(e); + char sec_name[SEC_NAME_LEN]; + + if (!objname) + return -1; + + /* section format: __klp_relocs.objname */ + if (snprintf_check(sec_name, SEC_NAME_LEN, + KLP_RELOCS_SEC ".%s", objname)) + return -1; + + klp_relocs =3D elf_create_section(e->out, sec_name, 0, 0, SHT_PROGBITS, 8, SHF_ALLOC); if (!klp_relocs) return -1; diff --git a/tools/objtool/klp-post-link.c b/tools/objtool/klp-post-link.c index c013e39957b1..350d20495897 100644 --- a/tools/objtool/klp-post-link.c +++ b/tools/objtool/klp-post-link.c @@ -19,19 +19,11 @@ #include #include =20 -static int fix_klp_relocs(struct elf *elf) +static int fix_klp_reloc_sec(struct elf *elf, struct section *symtab, + struct section *klp_relocs) { - struct section *symtab, *klp_relocs; - - klp_relocs =3D find_section_by_name(elf, KLP_RELOCS_SEC); - if (!klp_relocs) - return 0; - - symtab =3D find_section_by_name(elf, ".symtab"); - if (!symtab) { - ERROR("missing .symtab"); - return -1; - } + /* section format: __klp_relocs.sec_objname */ + const char *sec_objname =3D klp_relocs->name + strlen(KLP_RELOCS_SEC "."); =20 for (int i =3D 0; i < sec_size(klp_relocs) / sizeof(struct klp_reloc); i+= +) { struct klp_reloc *klp_reloc; @@ -39,7 +31,6 @@ static int fix_klp_relocs(struct elf *elf) struct section *sec, *tmp, *klp_rsec; unsigned long offset; struct reloc *reloc; - char sym_modname[64]; char rsec_name[SEC_NAME_LEN]; u64 addend; struct symbol *sym, *klp_sym; @@ -55,7 +46,7 @@ static int fix_klp_relocs(struct elf *elf) reloc =3D find_reloc_by_dest(elf, klp_relocs, klp_reloc_off + offsetof(struct klp_reloc, offset)); if (!reloc) { - ERROR("malformed " KLP_RELOCS_SEC " section"); + ERROR("malformed %s section", klp_relocs->name); return -1; } =20 @@ -66,17 +57,13 @@ static int fix_klp_relocs(struct elf *elf) reloc =3D find_reloc_by_dest(elf, klp_relocs, klp_reloc_off + offsetof(struct klp_reloc, sym)); if (!reloc) { - ERROR("malformed " KLP_RELOCS_SEC " section"); + ERROR("malformed %s section", klp_relocs->name); return -1; } =20 klp_sym =3D reloc->sym; addend =3D reloc_addend(reloc); =20 - /* symbol format: .klp.sym.modname.sym_name,sympos */ - if (sscanf(klp_sym->name + strlen(KLP_SYM_PREFIX), "%55[^.]", sym_modnam= e) !=3D 1) - ERROR("can't find modname in klp symbol '%s'", klp_sym->name); - /* * Create the KLP rela: */ @@ -84,7 +71,7 @@ static int fix_klp_relocs(struct elf *elf) /* section format: .klp.rela.sec_objname.section_name */ if (snprintf_check(rsec_name, SEC_NAME_LEN, KLP_RELOC_SEC_PREFIX "%s.%s", - sym_modname, sec->name)) + sec_objname, sec->name)) return -1; =20 klp_rsec =3D find_section_by_name(elf, rsec_name); @@ -134,10 +121,32 @@ static int fix_klp_relocs(struct elf *elf) return 0; } =20 +static int fix_klp_relocs(struct elf *elf) +{ + struct section *symtab, *sec; + + symtab =3D find_section_by_name(elf, ".symtab"); + if (!symtab) { + ERROR("missing .symtab"); + return -1; + } + + for_each_sec(elf, sec) { + if (strncmp(sec->name, KLP_RELOCS_SEC ".", + strlen(KLP_RELOCS_SEC "."))) + continue; + + if (fix_klp_reloc_sec(elf, symtab, sec)) + return -1; + } + + return 0; +} + /* * This runs on the livepatch module after all other linking has been done= . It - * converts the intermediate __klp_relocs section into proper KLP relocs t= o be - * processed by livepatch. This needs to run last to avoid linker wreckag= e. + * converts the intermediate __klp_relocs.* sections into proper KLP reloc= s to + * be processed by livepatch. This needs to run last to avoid linker wrec= kage. * Linkers don't tend to handle the "two rela sections for a single base * section" case very well, nor do they appreciate SHN_LIVEPATCH. */ --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB4B739A05D; Mon, 3 Aug 2026 03:24:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727499; cv=none; b=syHjj8QH7vFSkPFmeC7G3ck0y3g7ksUOCvmYnKvAt4cmaoWvAWyt+43HpwEc5dHhXGYDBWLZxEvlBzrFO7H9024i/E1/lkRQO7Hkoi3CXGTsjzYpFtRkCgWMRksUHPbltJOk5ANce3lwiLo/aGAvFjEp4kwTUIs8mseOVBfTQDc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727499; c=relaxed/simple; bh=L/hTNykbptfx0H+zY2cUmrueHsOfsVbVLsNT9q/U/us=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=j5N14gD6M/Y08EGIPDNA5Jturs8IqhI7pk8+E05hQ9WMOsE2Q9eB308Xw1+u9fT09qMQjErO37Kl1mJ2NSWUgP0KqyaT3HADoAgmGcyF9qZxfq6Rj6WkJiBWusrbPrEfgsj5y4J+Z8w3hLIryhns7NEI5jZzx6zPZs74k1mkkuI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YjJ2R+NO; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YjJ2R+NO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D2DE61F00ACF; Mon, 3 Aug 2026 03:24:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727497; bh=6no+nNQlBtcmRkmVefZUiRJpZdR7owkbYwDomyok6cQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=YjJ2R+NOFtGTr834AIMhT2sc3tNi1zkqtpAupU9tA2VCryF28wCHF+I47cjCl21Pp JKzdjCcrNGVRoRKBAZj+PTLZOT3kd94O8C2YSFY/T9IVJ8y4NfkckelfUGoSIF/ANG Tc5aCW/tsUG+CbDPL644KA9LOWRu/55TQtT008acZIpVuq0MKcLvGUGA2QhkDeNPwG DH2AcNwFsHbfr9jLf62RM/nzyvQgbNcUhbr/qrO79+BuptObXs53jIFCS92jisSLz/ +cAj+HsEoYHh0HzjnaeuLF0EG5QZpEUh99VgVul/AW3beG00PewximwmZzNGe0XBqz 4bv5UQr1YF8Ag== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org Subject: [PATCH 13/14] objtool/klp: Don't match local symbols against exports Date: Sun, 2 Aug 2026 20:24:35 -0700 Message-ID: X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" While cloning a reloc, klp diff calls find_export() to determine whether the referenced symbol is exported. That decides whether the reference needs a klp reloc, which object the klp symbol belongs to, and whether the symbol's data needs to be copied into the patch module. But find_export() matches purely on symbol name, so a static function or variable which happens to share its name with an export is mistaken for a reference to that export: - klp_reloc_needed() creates a klp reloc pointing at the exporting module's symbol rather than the local one. For a vmlinux export it skips the klp reloc altogether, leaving a normal reloc which the module loader resolves to the vmlinux symbol. - clone_reloc() treats the symbol as external and clones it without its data, leaving a dangling reference. - validate_special_section_klp_reloc() attributes a static branch or call key to the wrong module, and for a vmlinux export skips the unsupported-key check entirely. Exports are always global, so ignore local symbols in find_export(). Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffin= g object files") Signed-off-by: Josh Poimboeuf --- tools/objtool/klp-diff.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index e00dbe053a6e..e0dc22cef2c3 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -1102,6 +1102,9 @@ static struct export *find_export(struct symbol *sym) { struct export *export; =20 + if (is_local_sym(sym)) + return NULL; + hash_for_each_possible(exports, export, hash, str_hash(sym->name)) { if (!strcmp(export->sym, sym->name)) return export; --=20 2.54.0 From nobody Fri Oct 2 09:21:36 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8261F39B956; Mon, 3 Aug 2026 03:24:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727500; cv=none; b=a5tfwHCviLD7I+KrGR41Wt5vAJ5E0a21ABfxTFbrptzq2z4WLw8DgTjZewmfPWqpi2/gm1KSestymWO6CKO4hEKeKq23Ou9hKClSdMR4lomIKp5x4zsFY54oIMRRgb1Qz84nPKGpviKHUDUQXBCtrjFnssZx6RTcrsV1Qurq/ME= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785727500; c=relaxed/simple; bh=QUx6wchJN4Hl6eWMl5CKdGrUcSL3kOTde+E6rwAcB/w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EQ2QyKBL9Z2+KrVcGqvzp+EF/smcTXNAE/24MctDOWgPl0E8mTkRnqIEbPprdQcxlmwcdXt3LMI7gSYu9nALplJjrogCWBjxx/uST7h/96KYt7/iCIxe5P626ZEs02x17HMpQF71JbqPsKpSmjf22jtRzSSG0lQ528vrqS/4oX0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lwrFIUWI; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="lwrFIUWI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EBCA21F000E9; Mon, 3 Aug 2026 03:24:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785727498; bh=+WKufg9eSEaRNm0MCodUsNa/KDoTTSQQZMyrlWd3a1g=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=lwrFIUWIk8/3iBP54i1FULAgXTejfI+Y70/gR6RPGWEvZircCdmbrY4NfhzEjIh9/ 60iw2bfZIV0DpPjlvV4AZ6QWQkpPSoRheTHVDeiIExzDW3K3zDKEPUtQLLJJ8PUpH7 hLxIhFJeTj9i7Z7UKw27AHFlffEmKv4LwTpCmc2CJqPqGUPNhxCkBMJNimtN7kHZiq 9IWtt+Ekc/SE9Kes5FY4rVG17aKrIUo0kbU+CXryOXtdtM3ak27+O/zinafdRND9fk fL9DD80kYcHvZfdM7bDo3GQ++ogQAEmsxOKJnzSihMmXDEulWY9YXN3dsylIv0cjcv DmtUV69nGEIgQ== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Peter Zijlstra , Joe Lawrence , Miroslav Benes , Petr Mladek , Song Liu , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , linux-modules@vger.kernel.org Subject: [PATCH 14/14] objtool/klp: Allow new references to module exports Date: Sun, 2 Aug 2026 20:24:36 -0700 Message-ID: X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Joe Lawrence klp_reloc_needed() returns true for module exports to support late-module patching. However, clone_reloc_klp() unconditionally rejects symbols without a twin (i.e., new references added by the patch), even when the symbol is a known export from Module.symvers. Relax the check: allow new references to exported symbols by only erroring on !twin when there is no export. The export metadata from Module.symvers provides sufficient context to emit the klp-relocation without a twin. For a module export that isn't sufficient on its own though, as the resulting klp relocation will only be resolved at patch-enable time if the exporting module is loaded. If the original (unpatched) module already depends on the exporting module, the dependency is safe: the module loader ensures the dependency is satisfied before the patched module can be loaded, so the klp relocation target will exist. However, if the patch introduces a reference to a module that the original doesn't depend on, there is no such guarantee. The exporting module could be absent or could be unloaded at any time, leading to a relocation failure or use-after-free. So also add a build-time check: when a new symbol reference (no twin) targets a module export, verify that the original module already has at least one UNDEF symbol resolving to that same exporting module. If not, error out with a diagnostic message. Signed-off-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/klp-diff.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index e0dc22cef2c3..abda2e5c17f7 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -1295,6 +1295,28 @@ static int convert_reloc_sym(struct elf *elf, struct= reloc *reloc) return convert_reloc_secsym_to_sym(elf, reloc); } =20 +/* + * Check if the original module already has a dependency on dep_mod, i.e. = it + * already references at least one export from that module. + */ +static bool has_module_dep(struct elfs *e, const char *dep_mod) +{ + struct symbol *sym; + + for_each_sym(e->orig, sym) { + struct export *exp; + + if (!is_undef_sym(sym) || is_weak_sym(sym)) + continue; + + exp =3D find_export(sym); + if (exp && !strcmp(exp->mod, dep_mod)) + return true; + } + + return false; +} + /* * Convert a regular relocation to a klp relocation (sort of). */ @@ -1314,8 +1336,17 @@ static int clone_reloc_klp(struct elfs *e, struct re= loc *patched_reloc, unsigned long sympos; =20 if (!patched_sym->twin) { - ERROR("unexpected klp reloc for new symbol %s", patched_sym->name); - return -1; + if (!export) { + ERROR("unexpected klp reloc for new symbol %s", patched_sym->name); + return -1; + } + + if (strcmp(export->mod, "vmlinux") && + !has_module_dep(e, export->mod)) { + ERROR("%s: new reference to %s (exported by %s) would create an undecla= red module dependency", + patched_sym->name, export->sym, export->mod); + return -1; + } } =20 /* --=20 2.54.0