[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220209185752.1226407-3-alexandr.lobakin@intel.com>
Date: Wed, 9 Feb 2022 19:57:39 +0100
From: Alexander Lobakin <alexandr.lobakin@...el.com>
To: linux-hardening@...r.kernel.org, x86@...nel.org
Cc: Alexander Lobakin <alexandr.lobakin@...el.com>,
Borislav Petkov <bp@...en8.de>,
Jesse Brandeburg <jesse.brandeburg@...el.com>,
Kristen Carlson Accardi <kristen@...ux.intel.com>,
Kees Cook <keescook@...omium.org>,
Miklos Szeredi <miklos@...redi.hu>,
Ard Biesheuvel <ardb@...nel.org>,
Tony Luck <tony.luck@...el.com>,
Bruce Schlobohm <bruce.schlobohm@...el.com>,
Jessica Yu <jeyu@...nel.org>,
kernel test robot <lkp@...el.com>,
Miroslav Benes <mbenes@...e.cz>,
Evgenii Shatokhin <eshatokhin@...tuozzo.com>,
Jonathan Corbet <corbet@....net>,
Masahiro Yamada <masahiroy@...nel.org>,
Michal Marek <michal.lkml@...kovi.net>,
Nick Desaulniers <ndesaulniers@...gle.com>,
Herbert Xu <herbert@...dor.apana.org.au>,
"David S. Miller" <davem@...emloft.net>,
Thomas Gleixner <tglx@...utronix.de>,
Will Deacon <will@...nel.org>, Ingo Molnar <mingo@...hat.com>,
Christoph Hellwig <hch@....de>,
Dave Hansen <dave.hansen@...ux.intel.com>,
"H. Peter Anvin" <hpa@...or.com>,
Andy Lutomirski <luto@...nel.org>,
Peter Zijlstra <peterz@...radead.org>,
Arnd Bergmann <arnd@...db.de>,
Josh Poimboeuf <jpoimboe@...hat.com>,
Nathan Chancellor <nathan@...nel.org>,
Masami Hiramatsu <mhiramat@...nel.org>,
Marios Pomonis <pomonis@...gle.com>,
Sami Tolvanen <samitolvanen@...gle.com>,
"H.J. Lu" <hjl.tools@...il.com>, Nicolas Pitre <nico@...xnic.net>,
linux-kernel@...r.kernel.org, linux-kbuild@...r.kernel.org,
linux-arch@...r.kernel.org, live-patching@...r.kernel.org,
llvm@...ts.linux.dev
Subject: [PATCH v10 02/15] livepatch: avoid position-based search if `-z unique-symbol` is available
Position-based search, which means that if there are several symbols
with the same name, the user needs to additionally provide the
"index" of a desired symbol, is fragile. For example, it breaks
when two symbols with the same name are located in different
sections.
Since a while, LD has a flag `-z unique-symbol` which appends
numeric suffixes to the functions with the same name (in symtab
and strtab). It can be used to effectively prevent from having
any ambiguity when referring to a symbol by its name.
Check for its availability and always prefer when the livepatching
is on. It can be used unconditionally later on after broader testing
on a wide variety of machines, but for now let's stick to the actual
CONFIG_LIVEPATCH=y case, which is true for most of distro configs
anyways.
This needs a little adjustment to the modpost to make it strip
suffixes before adding exports. depmod needs some treatment as well,
tho its false-positive warnings about unknown symbols are harmless
and don't alter the return code.
There is probably a bunch more livepatch code to optimize-out after
introducing this, leave it for later as well.
Suggested-by: H.J. Lu <hjl.tools@...il.com>
Suggested-by: Peter Zijlstra <peterz@...radead.org>
Suggested-by: Josh Poimboeuf <jpoimboe@...hat.com>
Suggested-by: Miroslav Benes <mbenes@...e.cz>
Signed-off-by: Alexander Lobakin <alexandr.lobakin@...el.com>
---
Makefile | 6 ++++++
init/Kconfig | 3 +++
kernel/livepatch/core.c | 17 +++++++++++++----
scripts/mod/modpost.c | 42 ++++++++++++++++++++++-------------------
4 files changed, 45 insertions(+), 23 deletions(-)
diff --git a/Makefile b/Makefile
index ceb987e5c87b..fa9f947c9839 100644
--- a/Makefile
+++ b/Makefile
@@ -871,6 +871,12 @@ ifdef CONFIG_DEBUG_SECTION_MISMATCH
KBUILD_CFLAGS += -fno-inline-functions-called-once
endif
+# Prefer linking with the `-z unique-symbol` if available, this eliminates
+# position-based search
+ifeq ($(CONFIG_LD_HAS_Z_UNIQUE_SYMBOL)$(CONFIG_LIVEPATCH),yy)
+KBUILD_LDFLAGS += -z unique-symbol
+endif
+
ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
LDFLAGS_vmlinux += --gc-sections
diff --git a/init/Kconfig b/init/Kconfig
index e9119bf54b1f..8e900d17d42b 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -86,6 +86,9 @@ config CC_HAS_ASM_INLINE
config CC_HAS_NO_PROFILE_FN_ATTR
def_bool $(success,echo '__attribute__((no_profile_instrument_function)) int x();' | $(CC) -x c - -c -o /dev/null -Werror)
+config LD_HAS_Z_UNIQUE_SYMBOL
+ def_bool $(ld-option,-z unique-symbol)
+
config CONSTRUCTORS
bool
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 585494ec464f..7a330465a8c7 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -143,11 +143,13 @@ static int klp_find_callback(void *data, const char *name,
args->count++;
/*
- * Finish the search when the symbol is found for the desired position
- * or the position is not defined for a non-unique symbol.
+ * Finish the search when unique symbol names are enabled
+ * or the symbol is found for the desired position or the
+ * position is not defined for a non-unique symbol.
*/
- if ((args->pos && (args->count == args->pos)) ||
- (!args->pos && (args->count > 1)))
+ if (IS_ENABLED(CONFIG_LD_HAS_Z_UNIQUE_SYMBOL) ||
+ (args->pos && args->count == args->pos) ||
+ (!args->pos && args->count > 1))
return 1;
return 0;
@@ -169,6 +171,13 @@ static int klp_find_object_symbol(const char *objname, const char *name,
else
kallsyms_on_each_symbol(klp_find_callback, &args);
+ /*
+ * If the LD's `-z unique-symbol` flag is available and enabled,
+ * sympos checks are not relevant.
+ */
+ if (IS_ENABLED(CONFIG_LD_HAS_Z_UNIQUE_SYMBOL))
+ sympos = 0;
+
/*
* Ensure an address was found. If sympos is 0, ensure symbol is unique;
* otherwise ensure the symbol position count matches sympos.
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 4648b7afe5cc..ec521ccebea6 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -689,11 +689,28 @@ static void handle_modversion(const struct module *mod,
sym_set_crc(symname, crc);
}
+static char *remove_dot(char *s)
+{
+ size_t n = strcspn(s, ".");
+
+ if (n && s[n]) {
+ size_t m = strspn(s + n + 1, "0123456789");
+
+ if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0))
+ s[n] = 0;
+
+ /* strip trailing .lto */
+ if (strends(s, ".lto"))
+ s[strlen(s) - 4] = '\0';
+ }
+
+ return s;
+}
+
static void handle_symbol(struct module *mod, struct elf_info *info,
const Elf_Sym *sym, const char *symname)
{
enum export export;
- const char *name;
if (strstarts(symname, "__ksymtab"))
export = export_from_secname(info, get_secindex(info, sym));
@@ -734,8 +751,11 @@ static void handle_symbol(struct module *mod, struct elf_info *info,
default:
/* All exported symbols */
if (strstarts(symname, "__ksymtab_")) {
- name = symname + strlen("__ksymtab_");
- sym_add_exported(name, mod, export);
+ char *name;
+
+ name = NOFAIL(strdup(symname + strlen("__ksymtab_")));
+ sym_add_exported(remove_dot(name), mod, export);
+ free(name);
}
if (strcmp(symname, "init_module") == 0)
mod->has_init = 1;
@@ -1980,22 +2000,6 @@ static void check_sec_ref(struct module *mod, const char *modname,
}
}
-static char *remove_dot(char *s)
-{
- size_t n = strcspn(s, ".");
-
- if (n && s[n]) {
- size_t m = strspn(s + n + 1, "0123456789");
- if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0))
- s[n] = 0;
-
- /* strip trailing .lto */
- if (strends(s, ".lto"))
- s[strlen(s) - 4] = '\0';
- }
- return s;
-}
-
static void read_symbols(const char *modname)
{
const char *symname;
--
2.34.1
Powered by blists - more mailing lists