cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

kallsyms.c (14327B)


      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 */
     15static 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
     23static 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 */
     37static 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
     77static 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 */
    110void 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. */
    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;
    140	info->core_typeoffs = mod->data_layout.size;
    141	mod->data_layout.size += ndst * sizeof(char);
    142	mod->data_layout.size = strict_align(mod->data_layout.size);
    143
    144	/* Put string table section at end of init part of module. */
    145	strsect->sh_flags |= SHF_ALLOC;
    146	strsect->sh_entsize = module_get_offset(mod, &mod->init_layout.size, strsect,
    147						info->index.str) | INIT_OFFSET_MASK;
    148	pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
    149
    150	/* We'll tack temporary mod_kallsyms on the end. */
    151	mod->init_layout.size = ALIGN(mod->init_layout.size,
    152				      __alignof__(struct mod_kallsyms));
    153	info->mod_kallsyms_init_off = mod->init_layout.size;
    154	mod->init_layout.size += sizeof(struct mod_kallsyms);
    155	info->init_typeoffs = mod->init_layout.size;
    156	mod->init_layout.size += nsrc * sizeof(char);
    157	mod->init_layout.size = strict_align(mod->init_layout.size);
    158}
    159
    160/*
    161 * We use the full symtab and strtab which layout_symtab arranged to
    162 * be appended to the init section.  Later we switch to the cut-down
    163 * core-only ones.
    164 */
    165void add_kallsyms(struct module *mod, const struct load_info *info)
    166{
    167	unsigned int i, ndst;
    168	const Elf_Sym *src;
    169	Elf_Sym *dst;
    170	char *s;
    171	Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
    172
    173	/* Set up to point into init section. */
    174	mod->kallsyms = (void __rcu *)mod->init_layout.base +
    175		info->mod_kallsyms_init_off;
    176
    177	preempt_disable();
    178	/* The following is safe since this pointer cannot change */
    179	rcu_dereference_sched(mod->kallsyms)->symtab = (void *)symsec->sh_addr;
    180	rcu_dereference_sched(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
    181	/* Make sure we get permanent strtab: don't use info->strtab. */
    182	rcu_dereference_sched(mod->kallsyms)->strtab =
    183		(void *)info->sechdrs[info->index.str].sh_addr;
    184	rcu_dereference_sched(mod->kallsyms)->typetab = mod->init_layout.base + info->init_typeoffs;
    185
    186	/*
    187	 * Now populate the cut down core kallsyms for after init
    188	 * and set types up while we still have access to sections.
    189	 */
    190	mod->core_kallsyms.symtab = dst = mod->data_layout.base + info->symoffs;
    191	mod->core_kallsyms.strtab = s = mod->data_layout.base + info->stroffs;
    192	mod->core_kallsyms.typetab = mod->data_layout.base + info->core_typeoffs;
    193	src = rcu_dereference_sched(mod->kallsyms)->symtab;
    194	for (ndst = i = 0; i < rcu_dereference_sched(mod->kallsyms)->num_symtab; i++) {
    195		rcu_dereference_sched(mod->kallsyms)->typetab[i] = elf_type(src + i, info);
    196		if (i == 0 || is_livepatch_module(mod) ||
    197		    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
    198				   info->index.pcpu)) {
    199			mod->core_kallsyms.typetab[ndst] =
    200			    rcu_dereference_sched(mod->kallsyms)->typetab[i];
    201			dst[ndst] = src[i];
    202			dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
    203			s += strscpy(s,
    204				     &rcu_dereference_sched(mod->kallsyms)->strtab[src[i].st_name],
    205				     KSYM_NAME_LEN) + 1;
    206		}
    207	}
    208	preempt_enable();
    209	mod->core_kallsyms.num_symtab = ndst;
    210}
    211
    212#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
    213void init_build_id(struct module *mod, const struct load_info *info)
    214{
    215	const Elf_Shdr *sechdr;
    216	unsigned int i;
    217
    218	for (i = 0; i < info->hdr->e_shnum; i++) {
    219		sechdr = &info->sechdrs[i];
    220		if (!sect_empty(sechdr) && sechdr->sh_type == SHT_NOTE &&
    221		    !build_id_parse_buf((void *)sechdr->sh_addr, mod->build_id,
    222					sechdr->sh_size))
    223			break;
    224	}
    225}
    226#else
    227void init_build_id(struct module *mod, const struct load_info *info)
    228{
    229}
    230#endif
    231
    232/*
    233 * This ignores the intensely annoying "mapping symbols" found
    234 * in ARM ELF files: $a, $t and $d.
    235 */
    236static inline int is_arm_mapping_symbol(const char *str)
    237{
    238	if (str[0] == '.' && str[1] == 'L')
    239		return true;
    240	return str[0] == '$' && strchr("axtd", str[1]) &&
    241	       (str[2] == '\0' || str[2] == '.');
    242}
    243
    244static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
    245{
    246	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
    247}
    248
    249/*
    250 * Given a module and address, find the corresponding symbol and return its name
    251 * while providing its size and offset if needed.
    252 */
    253static const char *find_kallsyms_symbol(struct module *mod,
    254					unsigned long addr,
    255					unsigned long *size,
    256					unsigned long *offset)
    257{
    258	unsigned int i, best = 0;
    259	unsigned long nextval, bestval;
    260	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
    261
    262	/* At worse, next value is at end of module */
    263	if (within_module_init(addr, mod))
    264		nextval = (unsigned long)mod->init_layout.base + mod->init_layout.text_size;
    265	else
    266		nextval = (unsigned long)mod->core_layout.base + mod->core_layout.text_size;
    267
    268	bestval = kallsyms_symbol_value(&kallsyms->symtab[best]);
    269
    270	/*
    271	 * Scan for closest preceding symbol, and next symbol. (ELF
    272	 * starts real symbols at 1).
    273	 */
    274	for (i = 1; i < kallsyms->num_symtab; i++) {
    275		const Elf_Sym *sym = &kallsyms->symtab[i];
    276		unsigned long thisval = kallsyms_symbol_value(sym);
    277
    278		if (sym->st_shndx == SHN_UNDEF)
    279			continue;
    280
    281		/*
    282		 * We ignore unnamed symbols: they're uninformative
    283		 * and inserted at a whim.
    284		 */
    285		if (*kallsyms_symbol_name(kallsyms, i) == '\0' ||
    286		    is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
    287			continue;
    288
    289		if (thisval <= addr && thisval > bestval) {
    290			best = i;
    291			bestval = thisval;
    292		}
    293		if (thisval > addr && thisval < nextval)
    294			nextval = thisval;
    295	}
    296
    297	if (!best)
    298		return NULL;
    299
    300	if (size)
    301		*size = nextval - bestval;
    302	if (offset)
    303		*offset = addr - bestval;
    304
    305	return kallsyms_symbol_name(kallsyms, best);
    306}
    307
    308void * __weak dereference_module_function_descriptor(struct module *mod,
    309						     void *ptr)
    310{
    311	return ptr;
    312}
    313
    314/*
    315 * For kallsyms to ask for address resolution.  NULL means not found.  Careful
    316 * not to lock to avoid deadlock on oopses, simply disable preemption.
    317 */
    318const char *module_address_lookup(unsigned long addr,
    319				  unsigned long *size,
    320			    unsigned long *offset,
    321			    char **modname,
    322			    const unsigned char **modbuildid,
    323			    char *namebuf)
    324{
    325	const char *ret = NULL;
    326	struct module *mod;
    327
    328	preempt_disable();
    329	mod = __module_address(addr);
    330	if (mod) {
    331		if (modname)
    332			*modname = mod->name;
    333		if (modbuildid) {
    334#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
    335			*modbuildid = mod->build_id;
    336#else
    337			*modbuildid = NULL;
    338#endif
    339		}
    340
    341		ret = find_kallsyms_symbol(mod, addr, size, offset);
    342	}
    343	/* Make a copy in here where it's safe */
    344	if (ret) {
    345		strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
    346		ret = namebuf;
    347	}
    348	preempt_enable();
    349
    350	return ret;
    351}
    352
    353int lookup_module_symbol_name(unsigned long addr, char *symname)
    354{
    355	struct module *mod;
    356
    357	preempt_disable();
    358	list_for_each_entry_rcu(mod, &modules, list) {
    359		if (mod->state == MODULE_STATE_UNFORMED)
    360			continue;
    361		if (within_module(addr, mod)) {
    362			const char *sym;
    363
    364			sym = find_kallsyms_symbol(mod, addr, NULL, NULL);
    365			if (!sym)
    366				goto out;
    367
    368			strscpy(symname, sym, KSYM_NAME_LEN);
    369			preempt_enable();
    370			return 0;
    371		}
    372	}
    373out:
    374	preempt_enable();
    375	return -ERANGE;
    376}
    377
    378int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
    379			       unsigned long *offset, char *modname, char *name)
    380{
    381	struct module *mod;
    382
    383	preempt_disable();
    384	list_for_each_entry_rcu(mod, &modules, list) {
    385		if (mod->state == MODULE_STATE_UNFORMED)
    386			continue;
    387		if (within_module(addr, mod)) {
    388			const char *sym;
    389
    390			sym = find_kallsyms_symbol(mod, addr, size, offset);
    391			if (!sym)
    392				goto out;
    393			if (modname)
    394				strscpy(modname, mod->name, MODULE_NAME_LEN);
    395			if (name)
    396				strscpy(name, sym, KSYM_NAME_LEN);
    397			preempt_enable();
    398			return 0;
    399		}
    400	}
    401out:
    402	preempt_enable();
    403	return -ERANGE;
    404}
    405
    406int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
    407		       char *name, char *module_name, int *exported)
    408{
    409	struct module *mod;
    410
    411	preempt_disable();
    412	list_for_each_entry_rcu(mod, &modules, list) {
    413		struct mod_kallsyms *kallsyms;
    414
    415		if (mod->state == MODULE_STATE_UNFORMED)
    416			continue;
    417		kallsyms = rcu_dereference_sched(mod->kallsyms);
    418		if (symnum < kallsyms->num_symtab) {
    419			const Elf_Sym *sym = &kallsyms->symtab[symnum];
    420
    421			*value = kallsyms_symbol_value(sym);
    422			*type = kallsyms->typetab[symnum];
    423			strscpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
    424			strscpy(module_name, mod->name, MODULE_NAME_LEN);
    425			*exported = is_exported(name, *value, mod);
    426			preempt_enable();
    427			return 0;
    428		}
    429		symnum -= kallsyms->num_symtab;
    430	}
    431	preempt_enable();
    432	return -ERANGE;
    433}
    434
    435/* Given a module and name of symbol, find and return the symbol's value */
    436unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
    437{
    438	unsigned int i;
    439	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
    440
    441	for (i = 0; i < kallsyms->num_symtab; i++) {
    442		const Elf_Sym *sym = &kallsyms->symtab[i];
    443
    444		if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
    445		    sym->st_shndx != SHN_UNDEF)
    446			return kallsyms_symbol_value(sym);
    447	}
    448	return 0;
    449}
    450
    451/* Look for this name: can be of form module:name. */
    452unsigned long module_kallsyms_lookup_name(const char *name)
    453{
    454	struct module *mod;
    455	char *colon;
    456	unsigned long ret = 0;
    457
    458	/* Don't lock: we're in enough trouble already. */
    459	preempt_disable();
    460	if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
    461		if ((mod = find_module_all(name, colon - name, false)) != NULL)
    462			ret = find_kallsyms_symbol_value(mod, colon + 1);
    463	} else {
    464		list_for_each_entry_rcu(mod, &modules, list) {
    465			if (mod->state == MODULE_STATE_UNFORMED)
    466				continue;
    467			if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
    468				break;
    469		}
    470	}
    471	preempt_enable();
    472	return ret;
    473}
    474
    475#ifdef CONFIG_LIVEPATCH
    476int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
    477					     struct module *, 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		/* Use rcu_dereference_sched() to remain compliant with the sparse tool */
    492		preempt_disable();
    493		kallsyms = rcu_dereference_sched(mod->kallsyms);
    494		preempt_enable();
    495
    496		for (i = 0; i < kallsyms->num_symtab; i++) {
    497			const Elf_Sym *sym = &kallsyms->symtab[i];
    498
    499			if (sym->st_shndx == SHN_UNDEF)
    500				continue;
    501
    502			ret = fn(data, kallsyms_symbol_name(kallsyms, i),
    503				 mod, kallsyms_symbol_value(sym));
    504			if (ret != 0)
    505				goto out;
    506		}
    507	}
    508out:
    509	mutex_unlock(&module_mutex);
    510	return ret;
    511}
    512#endif /* CONFIG_LIVEPATCH */