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