Commit | Line | Data |
---|---|---|
91fb02f3 AT |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * Module kallsyms support | |
4 | * | |
5 | * Copyright (C) 2010 Rusty Russell | |
6 | */ | |
7 | ||
8 | #include <linux/module.h> | |
9 | #include <linux/kallsyms.h> | |
10 | #include <linux/buildid.h> | |
11 | #include <linux/bsearch.h> | |
12 | #include "internal.h" | |
13 | ||
14 | /* Lookup exported symbol in given range of kernel_symbols */ | |
15 | static const struct kernel_symbol *lookup_exported_symbol(const char *name, | |
16 | const struct kernel_symbol *start, | |
17 | const struct kernel_symbol *stop) | |
18 | { | |
19 | return bsearch(name, start, stop - start, | |
20 | sizeof(struct kernel_symbol), cmp_name); | |
21 | } | |
22 | ||
23 | static int is_exported(const char *name, unsigned long value, | |
24 | const struct module *mod) | |
25 | { | |
26 | const struct kernel_symbol *ks; | |
27 | ||
28 | if (!mod) | |
29 | ks = lookup_exported_symbol(name, __start___ksymtab, __stop___ksymtab); | |
30 | else | |
31 | ks = lookup_exported_symbol(name, mod->syms, mod->syms + mod->num_syms); | |
32 | ||
33 | return ks && kernel_symbol_value(ks) == value; | |
34 | } | |
35 | ||
36 | /* As per nm */ | |
37 | static char elf_type(const Elf_Sym *sym, const struct load_info *info) | |
38 | { | |
39 | const Elf_Shdr *sechdrs = info->sechdrs; | |
40 | ||
41 | if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { | |
42 | if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT) | |
43 | return 'v'; | |
44 | else | |
45 | return 'w'; | |
46 | } | |
47 | if (sym->st_shndx == SHN_UNDEF) | |
48 | return 'U'; | |
49 | if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu) | |
50 | return 'a'; | |
51 | if (sym->st_shndx >= SHN_LORESERVE) | |
52 | return '?'; | |
53 | if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR) | |
54 | return 't'; | |
55 | if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC && | |
56 | sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) { | |
57 | if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE)) | |
58 | return 'r'; | |
59 | else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL) | |
60 | return 'g'; | |
61 | else | |
62 | return 'd'; | |
63 | } | |
64 | if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) { | |
65 | if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL) | |
66 | return 's'; | |
67 | else | |
68 | return 'b'; | |
69 | } | |
70 | if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name, | |
71 | ".debug")) { | |
72 | return 'n'; | |
73 | } | |
74 | return '?'; | |
75 | } | |
76 | ||
77 | static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs, | |
78 | unsigned int shnum, unsigned int pcpundx) | |
79 | { | |
80 | const Elf_Shdr *sec; | |
81 | ||
82 | if (src->st_shndx == SHN_UNDEF || | |
83 | src->st_shndx >= shnum || | |
84 | !src->st_name) | |
85 | return false; | |
86 | ||
87 | #ifdef CONFIG_KALLSYMS_ALL | |
88 | if (src->st_shndx == pcpundx) | |
89 | return true; | |
90 | #endif | |
91 | ||
92 | sec = sechdrs + src->st_shndx; | |
93 | if (!(sec->sh_flags & SHF_ALLOC) | |
94 | #ifndef CONFIG_KALLSYMS_ALL | |
95 | || !(sec->sh_flags & SHF_EXECINSTR) | |
96 | #endif | |
97 | || (sec->sh_entsize & INIT_OFFSET_MASK)) | |
98 | return false; | |
99 | ||
100 | return true; | |
101 | } | |
102 | ||
103 | /* | |
104 | * We only allocate and copy the strings needed by the parts of symtab | |
105 | * we keep. This is simple, but has the effect of making multiple | |
106 | * copies of duplicates. We could be more sophisticated, see | |
107 | * linux-kernel thread starting with | |
108 | * <73defb5e4bca04a6431392cc341112b1@localhost>. | |
109 | */ | |
110 | void layout_symtab(struct module *mod, struct load_info *info) | |
111 | { | |
112 | Elf_Shdr *symsect = info->sechdrs + info->index.sym; | |
113 | Elf_Shdr *strsect = info->sechdrs + info->index.str; | |
114 | const Elf_Sym *src; | |
115 | unsigned int i, nsrc, ndst, strtab_size = 0; | |
116 | ||
117 | /* Put symbol section at end of init part of module. */ | |
118 | symsect->sh_flags |= SHF_ALLOC; | |
119 | symsect->sh_entsize = module_get_offset(mod, &mod->init_layout.size, symsect, | |
120 | info->index.sym) | INIT_OFFSET_MASK; | |
121 | pr_debug("\t%s\n", info->secstrings + symsect->sh_name); | |
122 | ||
123 | src = (void *)info->hdr + symsect->sh_offset; | |
124 | nsrc = symsect->sh_size / sizeof(*src); | |
125 | ||
126 | /* Compute total space required for the core symbols' strtab. */ | |
127 | for (ndst = i = 0; i < nsrc; i++) { | |
128 | if (i == 0 || is_livepatch_module(mod) || | |
129 | is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum, | |
130 | info->index.pcpu)) { | |
131 | strtab_size += strlen(&info->strtab[src[i].st_name]) + 1; | |
132 | ndst++; | |
133 | } | |
134 | } | |
135 | ||
136 | /* Append room for core symbols at end of core part. */ | |
6ab9942c CL |
137 | info->symoffs = ALIGN(mod->data_layout.size, symsect->sh_addralign ?: 1); |
138 | info->stroffs = mod->data_layout.size = info->symoffs + ndst * sizeof(Elf_Sym); | |
139 | mod->data_layout.size += strtab_size; | |
35adf9a4 | 140 | /* Note add_kallsyms() computes strtab_size as core_typeoffs - stroffs */ |
6ab9942c CL |
141 | info->core_typeoffs = mod->data_layout.size; |
142 | mod->data_layout.size += ndst * sizeof(char); | |
143 | mod->data_layout.size = strict_align(mod->data_layout.size); | |
91fb02f3 AT |
144 | |
145 | /* Put string table section at end of init part of module. */ | |
146 | strsect->sh_flags |= SHF_ALLOC; | |
147 | strsect->sh_entsize = module_get_offset(mod, &mod->init_layout.size, strsect, | |
148 | info->index.str) | INIT_OFFSET_MASK; | |
149 | pr_debug("\t%s\n", info->secstrings + strsect->sh_name); | |
150 | ||
151 | /* We'll tack temporary mod_kallsyms on the end. */ | |
152 | mod->init_layout.size = ALIGN(mod->init_layout.size, | |
153 | __alignof__(struct mod_kallsyms)); | |
154 | info->mod_kallsyms_init_off = mod->init_layout.size; | |
155 | mod->init_layout.size += sizeof(struct mod_kallsyms); | |
156 | info->init_typeoffs = mod->init_layout.size; | |
157 | mod->init_layout.size += nsrc * sizeof(char); | |
7337f929 | 158 | mod->init_layout.size = strict_align(mod->init_layout.size); |
91fb02f3 AT |
159 | } |
160 | ||
161 | /* | |
162 | * We use the full symtab and strtab which layout_symtab arranged to | |
163 | * be appended to the init section. Later we switch to the cut-down | |
164 | * core-only ones. | |
165 | */ | |
166 | void add_kallsyms(struct module *mod, const struct load_info *info) | |
167 | { | |
168 | unsigned int i, ndst; | |
169 | const Elf_Sym *src; | |
170 | Elf_Sym *dst; | |
171 | char *s; | |
172 | Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; | |
35adf9a4 | 173 | unsigned long strtab_size; |
91fb02f3 AT |
174 | |
175 | /* Set up to point into init section. */ | |
08126db5 AT |
176 | mod->kallsyms = (void __rcu *)mod->init_layout.base + |
177 | info->mod_kallsyms_init_off; | |
91fb02f3 | 178 | |
e69a6614 | 179 | rcu_read_lock(); |
91fb02f3 | 180 | /* The following is safe since this pointer cannot change */ |
e69a6614 AT |
181 | rcu_dereference(mod->kallsyms)->symtab = (void *)symsec->sh_addr; |
182 | rcu_dereference(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym); | |
91fb02f3 | 183 | /* Make sure we get permanent strtab: don't use info->strtab. */ |
e69a6614 | 184 | rcu_dereference(mod->kallsyms)->strtab = |
08126db5 | 185 | (void *)info->sechdrs[info->index.str].sh_addr; |
e69a6614 | 186 | rcu_dereference(mod->kallsyms)->typetab = mod->init_layout.base + info->init_typeoffs; |
91fb02f3 AT |
187 | |
188 | /* | |
189 | * Now populate the cut down core kallsyms for after init | |
190 | * and set types up while we still have access to sections. | |
191 | */ | |
6ab9942c CL |
192 | mod->core_kallsyms.symtab = dst = mod->data_layout.base + info->symoffs; |
193 | mod->core_kallsyms.strtab = s = mod->data_layout.base + info->stroffs; | |
194 | mod->core_kallsyms.typetab = mod->data_layout.base + info->core_typeoffs; | |
35adf9a4 | 195 | strtab_size = info->core_typeoffs - info->stroffs; |
e69a6614 AT |
196 | src = rcu_dereference(mod->kallsyms)->symtab; |
197 | for (ndst = i = 0; i < rcu_dereference(mod->kallsyms)->num_symtab; i++) { | |
198 | rcu_dereference(mod->kallsyms)->typetab[i] = elf_type(src + i, info); | |
91fb02f3 AT |
199 | if (i == 0 || is_livepatch_module(mod) || |
200 | is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum, | |
201 | info->index.pcpu)) { | |
35adf9a4 AH |
202 | ssize_t ret; |
203 | ||
91fb02f3 | 204 | mod->core_kallsyms.typetab[ndst] = |
e69a6614 | 205 | rcu_dereference(mod->kallsyms)->typetab[i]; |
91fb02f3 AT |
206 | dst[ndst] = src[i]; |
207 | dst[ndst++].st_name = s - mod->core_kallsyms.strtab; | |
35adf9a4 | 208 | ret = strscpy(s, |
e69a6614 | 209 | &rcu_dereference(mod->kallsyms)->strtab[src[i].st_name], |
35adf9a4 AH |
210 | strtab_size); |
211 | if (ret < 0) | |
212 | break; | |
213 | s += ret + 1; | |
214 | strtab_size -= ret + 1; | |
91fb02f3 AT |
215 | } |
216 | } | |
e69a6614 | 217 | rcu_read_unlock(); |
91fb02f3 AT |
218 | mod->core_kallsyms.num_symtab = ndst; |
219 | } | |
220 | ||
221 | #if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) | |
222 | void init_build_id(struct module *mod, const struct load_info *info) | |
223 | { | |
224 | const Elf_Shdr *sechdr; | |
225 | unsigned int i; | |
226 | ||
227 | for (i = 0; i < info->hdr->e_shnum; i++) { | |
228 | sechdr = &info->sechdrs[i]; | |
229 | if (!sect_empty(sechdr) && sechdr->sh_type == SHT_NOTE && | |
230 | !build_id_parse_buf((void *)sechdr->sh_addr, mod->build_id, | |
231 | sechdr->sh_size)) | |
232 | break; | |
233 | } | |
234 | } | |
235 | #else | |
236 | void init_build_id(struct module *mod, const struct load_info *info) | |
237 | { | |
238 | } | |
239 | #endif | |
240 | ||
241 | /* | |
242 | * This ignores the intensely annoying "mapping symbols" found | |
243 | * in ARM ELF files: $a, $t and $d. | |
244 | */ | |
245 | static inline int is_arm_mapping_symbol(const char *str) | |
246 | { | |
247 | if (str[0] == '.' && str[1] == 'L') | |
248 | return true; | |
249 | return str[0] == '$' && strchr("axtd", str[1]) && | |
250 | (str[2] == '\0' || str[2] == '.'); | |
251 | } | |
252 | ||
253 | static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum) | |
254 | { | |
255 | return kallsyms->strtab + kallsyms->symtab[symnum].st_name; | |
256 | } | |
257 | ||
258 | /* | |
259 | * Given a module and address, find the corresponding symbol and return its name | |
260 | * while providing its size and offset if needed. | |
261 | */ | |
262 | static const char *find_kallsyms_symbol(struct module *mod, | |
263 | unsigned long addr, | |
264 | unsigned long *size, | |
265 | unsigned long *offset) | |
266 | { | |
267 | unsigned int i, best = 0; | |
268 | unsigned long nextval, bestval; | |
269 | struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); | |
270 | ||
271 | /* At worse, next value is at end of module */ | |
272 | if (within_module_init(addr, mod)) | |
273 | nextval = (unsigned long)mod->init_layout.base + mod->init_layout.text_size; | |
274 | else | |
275 | nextval = (unsigned long)mod->core_layout.base + mod->core_layout.text_size; | |
276 | ||
277 | bestval = kallsyms_symbol_value(&kallsyms->symtab[best]); | |
278 | ||
279 | /* | |
280 | * Scan for closest preceding symbol, and next symbol. (ELF | |
281 | * starts real symbols at 1). | |
282 | */ | |
283 | for (i = 1; i < kallsyms->num_symtab; i++) { | |
284 | const Elf_Sym *sym = &kallsyms->symtab[i]; | |
285 | unsigned long thisval = kallsyms_symbol_value(sym); | |
286 | ||
287 | if (sym->st_shndx == SHN_UNDEF) | |
288 | continue; | |
289 | ||
290 | /* | |
291 | * We ignore unnamed symbols: they're uninformative | |
292 | * and inserted at a whim. | |
293 | */ | |
294 | if (*kallsyms_symbol_name(kallsyms, i) == '\0' || | |
295 | is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i))) | |
296 | continue; | |
297 | ||
298 | if (thisval <= addr && thisval > bestval) { | |
299 | best = i; | |
300 | bestval = thisval; | |
301 | } | |
302 | if (thisval > addr && thisval < nextval) | |
303 | nextval = thisval; | |
304 | } | |
305 | ||
306 | if (!best) | |
307 | return NULL; | |
308 | ||
309 | if (size) | |
310 | *size = nextval - bestval; | |
311 | if (offset) | |
312 | *offset = addr - bestval; | |
313 | ||
314 | return kallsyms_symbol_name(kallsyms, best); | |
315 | } | |
316 | ||
317 | void * __weak dereference_module_function_descriptor(struct module *mod, | |
318 | void *ptr) | |
319 | { | |
320 | return ptr; | |
321 | } | |
322 | ||
323 | /* | |
324 | * For kallsyms to ask for address resolution. NULL means not found. Careful | |
325 | * not to lock to avoid deadlock on oopses, simply disable preemption. | |
326 | */ | |
327 | const char *module_address_lookup(unsigned long addr, | |
328 | unsigned long *size, | |
329 | unsigned long *offset, | |
330 | char **modname, | |
331 | const unsigned char **modbuildid, | |
332 | char *namebuf) | |
333 | { | |
334 | const char *ret = NULL; | |
335 | struct module *mod; | |
336 | ||
337 | preempt_disable(); | |
338 | mod = __module_address(addr); | |
339 | if (mod) { | |
340 | if (modname) | |
341 | *modname = mod->name; | |
342 | if (modbuildid) { | |
343 | #if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) | |
344 | *modbuildid = mod->build_id; | |
345 | #else | |
346 | *modbuildid = NULL; | |
347 | #endif | |
348 | } | |
349 | ||
350 | ret = find_kallsyms_symbol(mod, addr, size, offset); | |
351 | } | |
352 | /* Make a copy in here where it's safe */ | |
353 | if (ret) { | |
354 | strncpy(namebuf, ret, KSYM_NAME_LEN - 1); | |
355 | ret = namebuf; | |
356 | } | |
357 | preempt_enable(); | |
358 | ||
359 | return ret; | |
360 | } | |
361 | ||
362 | int lookup_module_symbol_name(unsigned long addr, char *symname) | |
363 | { | |
364 | struct module *mod; | |
365 | ||
366 | preempt_disable(); | |
367 | list_for_each_entry_rcu(mod, &modules, list) { | |
368 | if (mod->state == MODULE_STATE_UNFORMED) | |
369 | continue; | |
370 | if (within_module(addr, mod)) { | |
371 | const char *sym; | |
372 | ||
373 | sym = find_kallsyms_symbol(mod, addr, NULL, NULL); | |
374 | if (!sym) | |
375 | goto out; | |
376 | ||
377 | strscpy(symname, sym, KSYM_NAME_LEN); | |
378 | preempt_enable(); | |
379 | return 0; | |
380 | } | |
381 | } | |
382 | out: | |
383 | preempt_enable(); | |
384 | return -ERANGE; | |
385 | } | |
386 | ||
387 | int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, | |
388 | unsigned long *offset, char *modname, char *name) | |
389 | { | |
390 | struct module *mod; | |
391 | ||
392 | preempt_disable(); | |
393 | list_for_each_entry_rcu(mod, &modules, list) { | |
394 | if (mod->state == MODULE_STATE_UNFORMED) | |
395 | continue; | |
396 | if (within_module(addr, mod)) { | |
397 | const char *sym; | |
398 | ||
399 | sym = find_kallsyms_symbol(mod, addr, size, offset); | |
400 | if (!sym) | |
401 | goto out; | |
402 | if (modname) | |
403 | strscpy(modname, mod->name, MODULE_NAME_LEN); | |
404 | if (name) | |
405 | strscpy(name, sym, KSYM_NAME_LEN); | |
406 | preempt_enable(); | |
407 | return 0; | |
408 | } | |
409 | } | |
410 | out: | |
411 | preempt_enable(); | |
412 | return -ERANGE; | |
413 | } | |
414 | ||
415 | int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, | |
416 | char *name, char *module_name, int *exported) | |
417 | { | |
418 | struct module *mod; | |
419 | ||
420 | preempt_disable(); | |
421 | list_for_each_entry_rcu(mod, &modules, list) { | |
422 | struct mod_kallsyms *kallsyms; | |
423 | ||
424 | if (mod->state == MODULE_STATE_UNFORMED) | |
425 | continue; | |
426 | kallsyms = rcu_dereference_sched(mod->kallsyms); | |
427 | if (symnum < kallsyms->num_symtab) { | |
428 | const Elf_Sym *sym = &kallsyms->symtab[symnum]; | |
429 | ||
430 | *value = kallsyms_symbol_value(sym); | |
431 | *type = kallsyms->typetab[symnum]; | |
432 | strscpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN); | |
433 | strscpy(module_name, mod->name, MODULE_NAME_LEN); | |
434 | *exported = is_exported(name, *value, mod); | |
435 | preempt_enable(); | |
436 | return 0; | |
437 | } | |
438 | symnum -= kallsyms->num_symtab; | |
439 | } | |
440 | preempt_enable(); | |
441 | return -ERANGE; | |
442 | } | |
443 | ||
444 | /* Given a module and name of symbol, find and return the symbol's value */ | |
445 | unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name) | |
446 | { | |
447 | unsigned int i; | |
448 | struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); | |
449 | ||
450 | for (i = 0; i < kallsyms->num_symtab; i++) { | |
451 | const Elf_Sym *sym = &kallsyms->symtab[i]; | |
452 | ||
453 | if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 && | |
454 | sym->st_shndx != SHN_UNDEF) | |
455 | return kallsyms_symbol_value(sym); | |
456 | } | |
457 | return 0; | |
458 | } | |
459 | ||
460 | /* Look for this name: can be of form module:name. */ | |
461 | unsigned long module_kallsyms_lookup_name(const char *name) | |
462 | { | |
463 | struct module *mod; | |
464 | char *colon; | |
465 | unsigned long ret = 0; | |
466 | ||
467 | /* Don't lock: we're in enough trouble already. */ | |
468 | preempt_disable(); | |
469 | if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) { | |
470 | if ((mod = find_module_all(name, colon - name, false)) != NULL) | |
471 | ret = find_kallsyms_symbol_value(mod, colon + 1); | |
472 | } else { | |
473 | list_for_each_entry_rcu(mod, &modules, list) { | |
474 | if (mod->state == MODULE_STATE_UNFORMED) | |
475 | continue; | |
476 | if ((ret = find_kallsyms_symbol_value(mod, name)) != 0) | |
477 | break; | |
478 | } | |
479 | } | |
480 | preempt_enable(); | |
481 | return ret; | |
482 | } | |
483 | ||
484 | #ifdef CONFIG_LIVEPATCH | |
485 | int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, | |
486 | struct module *, unsigned long), | |
487 | void *data) | |
488 | { | |
489 | struct module *mod; | |
490 | unsigned int i; | |
491 | int ret = 0; | |
492 | ||
493 | mutex_lock(&module_mutex); | |
494 | list_for_each_entry(mod, &modules, list) { | |
08126db5 | 495 | struct mod_kallsyms *kallsyms; |
91fb02f3 AT |
496 | |
497 | if (mod->state == MODULE_STATE_UNFORMED) | |
498 | continue; | |
08126db5 AT |
499 | |
500 | /* Use rcu_dereference_sched() to remain compliant with the sparse tool */ | |
501 | preempt_disable(); | |
502 | kallsyms = rcu_dereference_sched(mod->kallsyms); | |
503 | preempt_enable(); | |
504 | ||
91fb02f3 AT |
505 | for (i = 0; i < kallsyms->num_symtab; i++) { |
506 | const Elf_Sym *sym = &kallsyms->symtab[i]; | |
507 | ||
508 | if (sym->st_shndx == SHN_UNDEF) | |
509 | continue; | |
510 | ||
511 | ret = fn(data, kallsyms_symbol_name(kallsyms, i), | |
512 | mod, kallsyms_symbol_value(sym)); | |
513 | if (ret != 0) | |
514 | goto out; | |
515 | } | |
516 | } | |
517 | out: | |
518 | mutex_unlock(&module_mutex); | |
519 | return ret; | |
520 | } | |
521 | #endif /* CONFIG_LIVEPATCH */ |