With CONFIG_LTO_CLANG=y, the compiler may add .llvm.<hash> suffix to
function names to avoid duplication. APIs like kallsyms_lookup_name()
and kallsyms_on_each_match_symbol() tries to match these symbol names
without the .llvm.<hash> suffix, e.g., match "c_stop" with symbol
c_stop.llvm.17132674095431275852. This turned out to be problematic
for use cases that require exact match, for example, livepatch.

Fix this by making the APIs to match symbols exactly.

Also cleanup kallsyms_selftests accordingly.

Signed-off-by: Song Liu <s...@kernel.org>
---
 kernel/kallsyms.c          | 55 +++++---------------------------------
 kernel/kallsyms_selftest.c | 22 +--------------
 2 files changed, 7 insertions(+), 70 deletions(-)

diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index fb2c77368d18..a9a0ca605d4a 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -160,38 +160,6 @@ unsigned long kallsyms_sym_address(int idx)
        return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
 }
 
-static void cleanup_symbol_name(char *s)
-{
-       char *res;
-
-       if (!IS_ENABLED(CONFIG_LTO_CLANG))
-               return;
-
-       /*
-        * LLVM appends various suffixes for local functions and variables that
-        * must be promoted to global scope as part of LTO.  This can break
-        * hooking of static functions with kprobes. '.' is not a valid
-        * character in an identifier in C. Suffixes only in LLVM LTO observed:
-        * - foo.llvm.[0-9a-f]+
-        */
-       res = strstr(s, ".llvm.");
-       if (res)
-               *res = '\0';
-
-       return;
-}
-
-static int compare_symbol_name(const char *name, char *namebuf)
-{
-       /* The kallsyms_seqs_of_names is sorted based on names after
-        * cleanup_symbol_name() (see scripts/kallsyms.c) if clang lto is 
enabled.
-        * To ensure correct bisection in kallsyms_lookup_names(), do
-        * cleanup_symbol_name(namebuf) before comparing name and namebuf.
-        */
-       cleanup_symbol_name(namebuf);
-       return strcmp(name, namebuf);
-}
-
 static unsigned int get_symbol_seq(int index)
 {
        unsigned int i, seq = 0;
@@ -219,7 +187,7 @@ static int kallsyms_lookup_names(const char *name,
                seq = get_symbol_seq(mid);
                off = get_symbol_offset(seq);
                kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
-               ret = compare_symbol_name(name, namebuf);
+               ret = strcmp(name, namebuf);
                if (ret > 0)
                        low = mid + 1;
                else if (ret < 0)
@@ -236,7 +204,7 @@ static int kallsyms_lookup_names(const char *name,
                seq = get_symbol_seq(low - 1);
                off = get_symbol_offset(seq);
                kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
-               if (compare_symbol_name(name, namebuf))
+               if (strcmp(name, namebuf))
                        break;
                low--;
        }
@@ -248,7 +216,7 @@ static int kallsyms_lookup_names(const char *name,
                        seq = get_symbol_seq(high + 1);
                        off = get_symbol_offset(seq);
                        kallsyms_expand_symbol(off, namebuf, 
ARRAY_SIZE(namebuf));
-                       if (compare_symbol_name(name, namebuf))
+                       if (strcmp(name, namebuf))
                                break;
                        high++;
                }
@@ -407,8 +375,7 @@ static int kallsyms_lookup_buildid(unsigned long addr,
                if (modbuildid)
                        *modbuildid = NULL;
 
-               ret = strlen(namebuf);
-               goto found;
+               return strlen(namebuf);
        }
 
        /* See if it's in a module or a BPF JITed image. */
@@ -422,8 +389,6 @@ static int kallsyms_lookup_buildid(unsigned long addr,
                ret = ftrace_mod_address_lookup(addr, symbolsize,
                                                offset, modname, namebuf);
 
-found:
-       cleanup_symbol_name(namebuf);
        return ret;
 }
 
@@ -450,8 +415,6 @@ const char *kallsyms_lookup(unsigned long addr,
 
 int lookup_symbol_name(unsigned long addr, char *symname)
 {
-       int res;
-
        symname[0] = '\0';
        symname[KSYM_NAME_LEN - 1] = '\0';
 
@@ -462,16 +425,10 @@ int lookup_symbol_name(unsigned long addr, char *symname)
                /* Grab name */
                kallsyms_expand_symbol(get_symbol_offset(pos),
                                       symname, KSYM_NAME_LEN);
-               goto found;
+               return 0;
        }
        /* See if it's in a module. */
-       res = lookup_module_symbol_name(addr, symname);
-       if (res)
-               return res;
-
-found:
-       cleanup_symbol_name(symname);
-       return 0;
+       return lookup_module_symbol_name(addr, symname);
 }
 
 /* Look up a kernel symbol and return it in a text buffer. */
diff --git a/kernel/kallsyms_selftest.c b/kernel/kallsyms_selftest.c
index 2f84896a7bcb..873f7c445488 100644
--- a/kernel/kallsyms_selftest.c
+++ b/kernel/kallsyms_selftest.c
@@ -187,31 +187,11 @@ static void test_perf_kallsyms_lookup_name(void)
                stat.min, stat.max, div_u64(stat.sum, stat.real_cnt));
 }
 
-static bool match_cleanup_name(const char *s, const char *name)
-{
-       char *p;
-       int len;
-
-       if (!IS_ENABLED(CONFIG_LTO_CLANG))
-               return false;
-
-       p = strstr(s, ".llvm.");
-       if (!p)
-               return false;
-
-       len = strlen(name);
-       if (p - s != len)
-               return false;
-
-       return !strncmp(s, name, len);
-}
-
 static int find_symbol(void *data, const char *name, unsigned long addr)
 {
        struct test_stat *stat = (struct test_stat *)data;
 
-       if (strcmp(name, stat->name) == 0 ||
-           (!stat->perf && match_cleanup_name(name, stat->name))) {
+       if (!strcmp(name, stat->name)) {
                stat->real_cnt++;
                stat->addr = addr;
 
-- 
2.43.5


Reply via email to