Skip to content

Commit 5fc8ce3

Browse files
liu-song-6Sasha Levin
authored andcommitted
kallsyms: Match symbols exactly with CONFIG_LTO_CLANG
[ Upstream commit fb6a421 ] 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 <[email protected]> Fixes: 8cc32a9 ("kallsyms: strip LTO-only suffixes from promoted global functions") Tested-by: Masami Hiramatsu (Google) <[email protected]> Reviewed-by: Masami Hiramatsu (Google) <[email protected]> Acked-by: Petr Mladek <[email protected]> Reviewed-by: Sami Tolvanen <[email protected]> Reviewed-by: Luis Chamberlain <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kees Cook <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 5dd909c commit 5fc8ce3

File tree

2 files changed

+7
-70
lines changed

2 files changed

+7
-70
lines changed

kernel/kallsyms.c

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -160,38 +160,6 @@ unsigned long kallsyms_sym_address(int idx)
160160
return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
161161
}
162162

163-
static void cleanup_symbol_name(char *s)
164-
{
165-
char *res;
166-
167-
if (!IS_ENABLED(CONFIG_LTO_CLANG))
168-
return;
169-
170-
/*
171-
* LLVM appends various suffixes for local functions and variables that
172-
* must be promoted to global scope as part of LTO. This can break
173-
* hooking of static functions with kprobes. '.' is not a valid
174-
* character in an identifier in C. Suffixes only in LLVM LTO observed:
175-
* - foo.llvm.[0-9a-f]+
176-
*/
177-
res = strstr(s, ".llvm.");
178-
if (res)
179-
*res = '\0';
180-
181-
return;
182-
}
183-
184-
static int compare_symbol_name(const char *name, char *namebuf)
185-
{
186-
/* The kallsyms_seqs_of_names is sorted based on names after
187-
* cleanup_symbol_name() (see scripts/kallsyms.c) if clang lto is enabled.
188-
* To ensure correct bisection in kallsyms_lookup_names(), do
189-
* cleanup_symbol_name(namebuf) before comparing name and namebuf.
190-
*/
191-
cleanup_symbol_name(namebuf);
192-
return strcmp(name, namebuf);
193-
}
194-
195163
static unsigned int get_symbol_seq(int index)
196164
{
197165
unsigned int i, seq = 0;
@@ -219,7 +187,7 @@ static int kallsyms_lookup_names(const char *name,
219187
seq = get_symbol_seq(mid);
220188
off = get_symbol_offset(seq);
221189
kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
222-
ret = compare_symbol_name(name, namebuf);
190+
ret = strcmp(name, namebuf);
223191
if (ret > 0)
224192
low = mid + 1;
225193
else if (ret < 0)
@@ -236,7 +204,7 @@ static int kallsyms_lookup_names(const char *name,
236204
seq = get_symbol_seq(low - 1);
237205
off = get_symbol_offset(seq);
238206
kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
239-
if (compare_symbol_name(name, namebuf))
207+
if (strcmp(name, namebuf))
240208
break;
241209
low--;
242210
}
@@ -248,7 +216,7 @@ static int kallsyms_lookup_names(const char *name,
248216
seq = get_symbol_seq(high + 1);
249217
off = get_symbol_offset(seq);
250218
kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
251-
if (compare_symbol_name(name, namebuf))
219+
if (strcmp(name, namebuf))
252220
break;
253221
high++;
254222
}
@@ -407,8 +375,7 @@ static int kallsyms_lookup_buildid(unsigned long addr,
407375
if (modbuildid)
408376
*modbuildid = NULL;
409377

410-
ret = strlen(namebuf);
411-
goto found;
378+
return strlen(namebuf);
412379
}
413380

414381
/* See if it's in a module or a BPF JITed image. */
@@ -422,8 +389,6 @@ static int kallsyms_lookup_buildid(unsigned long addr,
422389
ret = ftrace_mod_address_lookup(addr, symbolsize,
423390
offset, modname, namebuf);
424391

425-
found:
426-
cleanup_symbol_name(namebuf);
427392
return ret;
428393
}
429394

@@ -450,8 +415,6 @@ const char *kallsyms_lookup(unsigned long addr,
450415

451416
int lookup_symbol_name(unsigned long addr, char *symname)
452417
{
453-
int res;
454-
455418
symname[0] = '\0';
456419
symname[KSYM_NAME_LEN - 1] = '\0';
457420

@@ -462,16 +425,10 @@ int lookup_symbol_name(unsigned long addr, char *symname)
462425
/* Grab name */
463426
kallsyms_expand_symbol(get_symbol_offset(pos),
464427
symname, KSYM_NAME_LEN);
465-
goto found;
428+
return 0;
466429
}
467430
/* See if it's in a module. */
468-
res = lookup_module_symbol_name(addr, symname);
469-
if (res)
470-
return res;
471-
472-
found:
473-
cleanup_symbol_name(symname);
474-
return 0;
431+
return lookup_module_symbol_name(addr, symname);
475432
}
476433

477434
/* Look up a kernel symbol and return it in a text buffer. */

kernel/kallsyms_selftest.c

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -187,31 +187,11 @@ static void test_perf_kallsyms_lookup_name(void)
187187
stat.min, stat.max, div_u64(stat.sum, stat.real_cnt));
188188
}
189189

190-
static bool match_cleanup_name(const char *s, const char *name)
191-
{
192-
char *p;
193-
int len;
194-
195-
if (!IS_ENABLED(CONFIG_LTO_CLANG))
196-
return false;
197-
198-
p = strstr(s, ".llvm.");
199-
if (!p)
200-
return false;
201-
202-
len = strlen(name);
203-
if (p - s != len)
204-
return false;
205-
206-
return !strncmp(s, name, len);
207-
}
208-
209190
static int find_symbol(void *data, const char *name, unsigned long addr)
210191
{
211192
struct test_stat *stat = (struct test_stat *)data;
212193

213-
if (strcmp(name, stat->name) == 0 ||
214-
(!stat->perf && match_cleanup_name(name, stat->name))) {
194+
if (!strcmp(name, stat->name)) {
215195
stat->real_cnt++;
216196
stat->addr = addr;
217197

0 commit comments

Comments
 (0)