lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <53e615c1-47ec-237c-7623-3f8995977706@csgroup.eu>
Date:   Tue, 22 Feb 2022 17:59:37 +0000
From:   Christophe Leroy <christophe.leroy@...roup.eu>
To:     Aaron Tomlin <atomlin@...hat.com>,
        "mcgrof@...nel.org" <mcgrof@...nel.org>
CC:     "cl@...ux.com" <cl@...ux.com>,
        "pmladek@...e.com" <pmladek@...e.com>,
        "mbenes@...e.cz" <mbenes@...e.cz>,
        "akpm@...ux-foundation.org" <akpm@...ux-foundation.org>,
        "jeyu@...nel.org" <jeyu@...nel.org>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
        "linux-modules@...r.kernel.org" <linux-modules@...r.kernel.org>,
        "void@...ifault.com" <void@...ifault.com>,
        "atomlin@...mlin.com" <atomlin@...mlin.com>,
        "allen.lkml@...il.com" <allen.lkml@...il.com>,
        "joe@...ches.com" <joe@...ches.com>,
        "msuchanek@...e.de" <msuchanek@...e.de>,
        "oleksandr@...alenko.name" <oleksandr@...alenko.name>
Subject: Re: [PATCH v8 09/13] module: Move kallsyms support into a separate
 file



Le 22/02/2022 à 15:12, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates kallsyms code out of core module
> code kernel/module/kallsyms.c
> 
> Signed-off-by: Aaron Tomlin <atomlin@...hat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@...roup.eu>

> ---
>   kernel/module/Makefile   |   1 +
>   kernel/module/internal.h |  29 +++
>   kernel/module/kallsyms.c | 506 +++++++++++++++++++++++++++++++++++++
>   kernel/module/main.c     | 531 +--------------------------------------
>   4 files changed, 542 insertions(+), 525 deletions(-)
>   create mode 100644 kernel/module/kallsyms.c
> 
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index 12388627725c..9901bed3ab5b 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -14,3 +14,4 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o
>   obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
>   obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
>   obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
> +obj-$(CONFIG_KALLSYMS) += kallsyms.o
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index b0c360839f63..44ca05b9eb8f 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -68,6 +68,19 @@ struct load_info {
>   };
>   
>   int mod_verify_sig(const void *mod, struct load_info *info);
> +struct module *find_module_all(const char *name, size_t len, bool even_unformed);
> +int cmp_name(const void *name, const void *sym);
> +long module_get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr,
> +		       unsigned int section);
> +
> +static inline unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
> +{
> +#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
> +	return (unsigned long)offset_to_ptr(&sym->value_offset);
> +#else
> +	return sym->value;
> +#endif
> +}
>   
>   #ifdef CONFIG_LIVEPATCH
>   int copy_module_elf(struct module *mod, struct load_info *info);
> @@ -174,3 +187,19 @@ void kmemleak_load_module(const struct module *mod, const struct load_info *info
>   static inline void kmemleak_load_module(const struct module *mod,
>   					const struct load_info *info) { }
>   #endif /* CONFIG_DEBUG_KMEMLEAK */
> +
> +#ifdef CONFIG_KALLSYMS
> +void init_build_id(struct module *mod, const struct load_info *info);
> +void layout_symtab(struct module *mod, struct load_info *info);
> +void add_kallsyms(struct module *mod, const struct load_info *info);
> +unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name);
> +
> +static inline bool sect_empty(const Elf_Shdr *sect)
> +{
> +	return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
> +}
> +#else /* !CONFIG_KALLSYMS */
> +static inline void init_build_id(struct module *mod, const struct load_info *info) { }
> +static inline void layout_symtab(struct module *mod, struct load_info *info) { }
> +static inline void add_kallsyms(struct module *mod, const struct load_info *info) { }
> +#endif /* CONFIG_KALLSYMS */
> diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c
> new file mode 100644
> index 000000000000..b6d49bb5afed
> --- /dev/null
> +++ b/kernel/module/kallsyms.c
> @@ -0,0 +1,506 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Module kallsyms support
> + *
> + * Copyright (C) 2010 Rusty Russell
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kallsyms.h>
> +#include <linux/buildid.h>
> +#include <linux/bsearch.h>
> +#include "internal.h"
> +
> +/* Lookup exported symbol in given range of kernel_symbols */
> +static const struct kernel_symbol *lookup_exported_symbol(const char *name,
> +							  const struct kernel_symbol *start,
> +							  const struct kernel_symbol *stop)
> +{
> +	return bsearch(name, start, stop - start,
> +			sizeof(struct kernel_symbol), cmp_name);
> +}
> +
> +static int is_exported(const char *name, unsigned long value,
> +		       const struct module *mod)
> +{
> +	const struct kernel_symbol *ks;
> +
> +	if (!mod)
> +		ks = lookup_exported_symbol(name, __start___ksymtab, __stop___ksymtab);
> +	else
> +		ks = lookup_exported_symbol(name, mod->syms, mod->syms + mod->num_syms);
> +
> +	return ks && kernel_symbol_value(ks) == value;
> +}
> +
> +/* As per nm */
> +static char elf_type(const Elf_Sym *sym, const struct load_info *info)
> +{
> +	const Elf_Shdr *sechdrs = info->sechdrs;
> +
> +	if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
> +		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
> +			return 'v';
> +		else
> +			return 'w';
> +	}
> +	if (sym->st_shndx == SHN_UNDEF)
> +		return 'U';
> +	if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
> +		return 'a';
> +	if (sym->st_shndx >= SHN_LORESERVE)
> +		return '?';
> +	if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR)
> +		return 't';
> +	if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC &&
> +	    sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) {
> +		if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE))
> +			return 'r';
> +		else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
> +			return 'g';
> +		else
> +			return 'd';
> +	}
> +	if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) {
> +		if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
> +			return 's';
> +		else
> +			return 'b';
> +	}
> +	if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name,
> +		      ".debug")) {
> +		return 'n';
> +	}
> +	return '?';
> +}
> +
> +static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
> +			   unsigned int shnum, unsigned int pcpundx)
> +{
> +	const Elf_Shdr *sec;
> +
> +	if (src->st_shndx == SHN_UNDEF ||
> +	    src->st_shndx >= shnum ||
> +	    !src->st_name)
> +		return false;
> +
> +#ifdef CONFIG_KALLSYMS_ALL
> +	if (src->st_shndx == pcpundx)
> +		return true;
> +#endif
> +
> +	sec = sechdrs + src->st_shndx;
> +	if (!(sec->sh_flags & SHF_ALLOC)
> +#ifndef CONFIG_KALLSYMS_ALL
> +	    || !(sec->sh_flags & SHF_EXECINSTR)
> +#endif
> +	    || (sec->sh_entsize & INIT_OFFSET_MASK))
> +		return false;
> +
> +	return true;
> +}
> +
> +/*
> + * We only allocate and copy the strings needed by the parts of symtab
> + * we keep.  This is simple, but has the effect of making multiple
> + * copies of duplicates.  We could be more sophisticated, see
> + * linux-kernel thread starting with
> + * <73defb5e4bca04a6431392cc341112b1@...alhost>.
> + */
> +void layout_symtab(struct module *mod, struct load_info *info)
> +{
> +	Elf_Shdr *symsect = info->sechdrs + info->index.sym;
> +	Elf_Shdr *strsect = info->sechdrs + info->index.str;
> +	const Elf_Sym *src;
> +	unsigned int i, nsrc, ndst, strtab_size = 0;
> +
> +	/* Put symbol section at end of init part of module. */
> +	symsect->sh_flags |= SHF_ALLOC;
> +	symsect->sh_entsize = module_get_offset(mod, &mod->init_layout.size, symsect,
> +						info->index.sym) | INIT_OFFSET_MASK;
> +	pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
> +
> +	src = (void *)info->hdr + symsect->sh_offset;
> +	nsrc = symsect->sh_size / sizeof(*src);
> +
> +	/* Compute total space required for the core symbols' strtab. */
> +	for (ndst = i = 0; i < nsrc; i++) {
> +		if (i == 0 || is_livepatch_module(mod) ||
> +		    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
> +				   info->index.pcpu)) {
> +			strtab_size += strlen(&info->strtab[src[i].st_name]) + 1;
> +			ndst++;
> +		}
> +	}
> +
> +	/* Append room for core symbols at end of core part. */
> +	info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
> +	info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
> +	mod->core_layout.size += strtab_size;
> +	info->core_typeoffs = mod->core_layout.size;
> +	mod->core_layout.size += ndst * sizeof(char);
> +	mod->core_layout.size = debug_align(mod->core_layout.size);
> +
> +	/* Put string table section at end of init part of module. */
> +	strsect->sh_flags |= SHF_ALLOC;
> +	strsect->sh_entsize = module_get_offset(mod, &mod->init_layout.size, strsect,
> +						info->index.str) | INIT_OFFSET_MASK;
> +	pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
> +
> +	/* We'll tack temporary mod_kallsyms on the end. */
> +	mod->init_layout.size = ALIGN(mod->init_layout.size,
> +				      __alignof__(struct mod_kallsyms));
> +	info->mod_kallsyms_init_off = mod->init_layout.size;
> +	mod->init_layout.size += sizeof(struct mod_kallsyms);
> +	info->init_typeoffs = mod->init_layout.size;
> +	mod->init_layout.size += nsrc * sizeof(char);
> +	mod->init_layout.size = debug_align(mod->init_layout.size);
> +}
> +
> +/*
> + * We use the full symtab and strtab which layout_symtab arranged to
> + * be appended to the init section.  Later we switch to the cut-down
> + * core-only ones.
> + */
> +void add_kallsyms(struct module *mod, const struct load_info *info)
> +{
> +	unsigned int i, ndst;
> +	const Elf_Sym *src;
> +	Elf_Sym *dst;
> +	char *s;
> +	Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
> +
> +	/* Set up to point into init section. */
> +	mod->kallsyms = (void __rcu *)mod->init_layout.base +
> +		info->mod_kallsyms_init_off;
> +
> +	/* The following is safe since this pointer cannot change */
> +	rcu_dereference_sched(mod->kallsyms)->symtab = (void *)symsec->sh_addr;
> +	rcu_dereference_sched(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
> +	/* Make sure we get permanent strtab: don't use info->strtab. */
> +	rcu_dereference_sched(mod->kallsyms)->strtab =
> +		(void *)info->sechdrs[info->index.str].sh_addr;
> +	rcu_dereference_sched(mod->kallsyms)->typetab =
> +		mod->init_layout.base + info->init_typeoffs;
> +
> +	/*
> +	 * Now populate the cut down core kallsyms for after init
> +	 * and set types up while we still have access to sections.
> +	 */
> +	mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
> +	mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
> +	mod->core_kallsyms.typetab = mod->core_layout.base + info->core_typeoffs;
> +	src = rcu_dereference_sched(mod->kallsyms)->symtab;
> +	for (ndst = i = 0; i < rcu_dereference_sched(mod->kallsyms)->num_symtab; i++) {
> +		rcu_dereference_sched(mod->kallsyms)->typetab[i] = elf_type(src + i, info);
> +		if (i == 0 || is_livepatch_module(mod) ||
> +		    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
> +				   info->index.pcpu)) {
> +			mod->core_kallsyms.typetab[ndst] =
> +			    rcu_dereference_sched(mod->kallsyms)->typetab[i];
> +			dst[ndst] = src[i];
> +			dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
> +			s += strscpy(s,
> +				     &rcu_dereference_sched(mod->kallsyms)->strtab[src[i].st_name],
> +				     KSYM_NAME_LEN) + 1;
> +		}
> +	}
> +	mod->core_kallsyms.num_symtab = ndst;
> +}
> +
> +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> +void init_build_id(struct module *mod, const struct load_info *info)
> +{
> +	const Elf_Shdr *sechdr;
> +	unsigned int i;
> +
> +	for (i = 0; i < info->hdr->e_shnum; i++) {
> +		sechdr = &info->sechdrs[i];
> +		if (!sect_empty(sechdr) && sechdr->sh_type == SHT_NOTE &&
> +		    !build_id_parse_buf((void *)sechdr->sh_addr, mod->build_id,
> +					sechdr->sh_size))
> +			break;
> +	}
> +}
> +#else
> +void init_build_id(struct module *mod, const struct load_info *info)
> +{
> +}
> +#endif
> +
> +/*
> + * This ignores the intensely annoying "mapping symbols" found
> + * in ARM ELF files: $a, $t and $d.
> + */
> +static inline int is_arm_mapping_symbol(const char *str)
> +{
> +	if (str[0] == '.' && str[1] == 'L')
> +		return true;
> +	return str[0] == '$' && strchr("axtd", str[1]) &&
> +	       (str[2] == '\0' || str[2] == '.');
> +}
> +
> +static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
> +{
> +	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
> +}
> +
> +/*
> + * Given a module and address, find the corresponding symbol and return its name
> + * while providing its size and offset if needed.
> + */
> +static const char *find_kallsyms_symbol(struct module *mod,
> +					unsigned long addr,
> +					unsigned long *size,
> +					unsigned long *offset)
> +{
> +	unsigned int i, best = 0;
> +	unsigned long nextval, bestval;
> +	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> +
> +	/* At worse, next value is at end of module */
> +	if (within_module_init(addr, mod))
> +		nextval = (unsigned long)mod->init_layout.base + mod->init_layout.text_size;
> +	else
> +		nextval = (unsigned long)mod->core_layout.base + mod->core_layout.text_size;
> +
> +	bestval = kallsyms_symbol_value(&kallsyms->symtab[best]);
> +
> +	/*
> +	 * Scan for closest preceding symbol, and next symbol. (ELF
> +	 * starts real symbols at 1).
> +	 */
> +	for (i = 1; i < kallsyms->num_symtab; i++) {
> +		const Elf_Sym *sym = &kallsyms->symtab[i];
> +		unsigned long thisval = kallsyms_symbol_value(sym);
> +
> +		if (sym->st_shndx == SHN_UNDEF)
> +			continue;
> +
> +		/*
> +		 * We ignore unnamed symbols: they're uninformative
> +		 * and inserted at a whim.
> +		 */
> +		if (*kallsyms_symbol_name(kallsyms, i) == '\0' ||
> +		    is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
> +			continue;
> +
> +		if (thisval <= addr && thisval > bestval) {
> +			best = i;
> +			bestval = thisval;
> +		}
> +		if (thisval > addr && thisval < nextval)
> +			nextval = thisval;
> +	}
> +
> +	if (!best)
> +		return NULL;
> +
> +	if (size)
> +		*size = nextval - bestval;
> +	if (offset)
> +		*offset = addr - bestval;
> +
> +	return kallsyms_symbol_name(kallsyms, best);
> +}
> +
> +void * __weak dereference_module_function_descriptor(struct module *mod,
> +						     void *ptr)
> +{
> +	return ptr;
> +}
> +
> +/*
> + * For kallsyms to ask for address resolution.  NULL means not found.  Careful
> + * not to lock to avoid deadlock on oopses, simply disable preemption.
> + */
> +const char *module_address_lookup(unsigned long addr,
> +				  unsigned long *size,
> +			    unsigned long *offset,
> +			    char **modname,
> +			    const unsigned char **modbuildid,
> +			    char *namebuf)
> +{
> +	const char *ret = NULL;
> +	struct module *mod;
> +
> +	preempt_disable();
> +	mod = __module_address(addr);
> +	if (mod) {
> +		if (modname)
> +			*modname = mod->name;
> +		if (modbuildid) {
> +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> +			*modbuildid = mod->build_id;
> +#else
> +			*modbuildid = NULL;
> +#endif
> +		}
> +
> +		ret = find_kallsyms_symbol(mod, addr, size, offset);
> +	}
> +	/* Make a copy in here where it's safe */
> +	if (ret) {
> +		strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
> +		ret = namebuf;
> +	}
> +	preempt_enable();
> +
> +	return ret;
> +}
> +
> +int lookup_module_symbol_name(unsigned long addr, char *symname)
> +{
> +	struct module *mod;
> +
> +	preempt_disable();
> +	list_for_each_entry_rcu(mod, &modules, list) {
> +		if (mod->state == MODULE_STATE_UNFORMED)
> +			continue;
> +		if (within_module(addr, mod)) {
> +			const char *sym;
> +
> +			sym = find_kallsyms_symbol(mod, addr, NULL, NULL);
> +			if (!sym)
> +				goto out;
> +
> +			strscpy(symname, sym, KSYM_NAME_LEN);
> +			preempt_enable();
> +			return 0;
> +		}
> +	}
> +out:
> +	preempt_enable();
> +	return -ERANGE;
> +}
> +
> +int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
> +			       unsigned long *offset, char *modname, char *name)
> +{
> +	struct module *mod;
> +
> +	preempt_disable();
> +	list_for_each_entry_rcu(mod, &modules, list) {
> +		if (mod->state == MODULE_STATE_UNFORMED)
> +			continue;
> +		if (within_module(addr, mod)) {
> +			const char *sym;
> +
> +			sym = find_kallsyms_symbol(mod, addr, size, offset);
> +			if (!sym)
> +				goto out;
> +			if (modname)
> +				strscpy(modname, mod->name, MODULE_NAME_LEN);
> +			if (name)
> +				strscpy(name, sym, KSYM_NAME_LEN);
> +			preempt_enable();
> +			return 0;
> +		}
> +	}
> +out:
> +	preempt_enable();
> +	return -ERANGE;
> +}
> +
> +int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
> +		       char *name, char *module_name, int *exported)
> +{
> +	struct module *mod;
> +
> +	preempt_disable();
> +	list_for_each_entry_rcu(mod, &modules, list) {
> +		struct mod_kallsyms *kallsyms;
> +
> +		if (mod->state == MODULE_STATE_UNFORMED)
> +			continue;
> +		kallsyms = rcu_dereference_sched(mod->kallsyms);
> +		if (symnum < kallsyms->num_symtab) {
> +			const Elf_Sym *sym = &kallsyms->symtab[symnum];
> +
> +			*value = kallsyms_symbol_value(sym);
> +			*type = kallsyms->typetab[symnum];
> +			strscpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
> +			strscpy(module_name, mod->name, MODULE_NAME_LEN);
> +			*exported = is_exported(name, *value, mod);
> +			preempt_enable();
> +			return 0;
> +		}
> +		symnum -= kallsyms->num_symtab;
> +	}
> +	preempt_enable();
> +	return -ERANGE;
> +}
> +
> +/* Given a module and name of symbol, find and return the symbol's value */
> +unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
> +{
> +	unsigned int i;
> +	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> +
> +	for (i = 0; i < kallsyms->num_symtab; i++) {
> +		const Elf_Sym *sym = &kallsyms->symtab[i];
> +
> +		if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
> +		    sym->st_shndx != SHN_UNDEF)
> +			return kallsyms_symbol_value(sym);
> +	}
> +	return 0;
> +}
> +
> +/* Look for this name: can be of form module:name. */
> +unsigned long module_kallsyms_lookup_name(const char *name)
> +{
> +	struct module *mod;
> +	char *colon;
> +	unsigned long ret = 0;
> +
> +	/* Don't lock: we're in enough trouble already. */
> +	preempt_disable();
> +	if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
> +		if ((mod = find_module_all(name, colon - name, false)) != NULL)
> +			ret = find_kallsyms_symbol_value(mod, colon + 1);
> +	} else {
> +		list_for_each_entry_rcu(mod, &modules, list) {
> +			if (mod->state == MODULE_STATE_UNFORMED)
> +				continue;
> +			if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
> +				break;
> +		}
> +	}
> +	preempt_enable();
> +	return ret;
> +}
> +
> +#ifdef CONFIG_LIVEPATCH
> +int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
> +					     struct module *, unsigned long),
> +				   void *data)
> +{
> +	struct module *mod;
> +	unsigned int i;
> +	int ret = 0;
> +
> +	mutex_lock(&module_mutex);
> +	list_for_each_entry(mod, &modules, list) {
> +		/* Still use rcu_dereference_sched to remain compliant with sparse */
> +		struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> +
> +		if (mod->state == MODULE_STATE_UNFORMED)
> +			continue;
> +		for (i = 0; i < kallsyms->num_symtab; i++) {
> +			const Elf_Sym *sym = &kallsyms->symtab[i];
> +
> +			if (sym->st_shndx == SHN_UNDEF)
> +				continue;
> +
> +			ret = fn(data, kallsyms_symbol_name(kallsyms, i),
> +				 mod, kallsyms_symbol_value(sym));
> +			if (ret != 0)
> +				goto out;
> +		}
> +	}
> +out:
> +	mutex_unlock(&module_mutex);
> +	return ret;
> +}
> +#endif /* CONFIG_LIVEPATCH */
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 7dd283959c5c..952079987ea4 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -288,15 +288,6 @@ static bool check_exported_symbol(const struct symsearch *syms,
>   	return true;
>   }
>   
> -static unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
> -{
> -#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
> -	return (unsigned long)offset_to_ptr(&sym->value_offset);
> -#else
> -	return sym->value;
> -#endif
> -}
> -
>   static const char *kernel_symbol_name(const struct kernel_symbol *sym)
>   {
>   #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
> @@ -317,7 +308,7 @@ static const char *kernel_symbol_namespace(const struct kernel_symbol *sym)
>   #endif
>   }
>   
> -static int cmp_name(const void *name, const void *sym)
> +int cmp_name(const void *name, const void *sym)
>   {
>   	return strcmp(name, kernel_symbol_name(sym));
>   }
> @@ -387,8 +378,8 @@ static bool find_symbol(struct find_symbol_arg *fsa)
>    * Search for module by name: must hold module_mutex (or preempt disabled
>    * for read-only access).
>    */
> -static struct module *find_module_all(const char *name, size_t len,
> -				      bool even_unformed)
> +struct module *find_module_all(const char *name, size_t len,
> +			       bool even_unformed)
>   {
>   	struct module *mod;
>   
> @@ -1294,13 +1285,6 @@ resolve_symbol_wait(struct module *mod,
>   	return ksym;
>   }
>   
> -#ifdef CONFIG_KALLSYMS
> -static inline bool sect_empty(const Elf_Shdr *sect)
> -{
> -	return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
> -}
> -#endif
> -
>   /*
>    * /sys/module/foo/sections stuff
>    * J. Corbet <corbet@....net>
> @@ -2065,7 +2049,7 @@ unsigned int __weak arch_mod_section_prepend(struct module *mod,
>   }
>   
>   /* Update size with this section: return offset. */
> -static long get_offset(struct module *mod, unsigned int *size,
> +long module_get_offset(struct module *mod, unsigned int *size,
>   		       Elf_Shdr *sechdr, unsigned int section)
>   {
>   	long ret;
> @@ -2121,7 +2105,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
>   			    || s->sh_entsize != ~0UL
>   			    || module_init_layout_section(sname))
>   				continue;
> -			s->sh_entsize = get_offset(mod, &mod->core_layout.size, s, i);
> +			s->sh_entsize = module_get_offset(mod, &mod->core_layout.size, s, i);
>   			pr_debug("\t%s\n", sname);
>   		}
>   		switch (m) {
> @@ -2154,7 +2138,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
>   			    || s->sh_entsize != ~0UL
>   			    || !module_init_layout_section(sname))
>   				continue;
> -			s->sh_entsize = (get_offset(mod, &mod->init_layout.size, s, i)
> +			s->sh_entsize = (module_get_offset(mod, &mod->init_layout.size, s, i)
>   					 | INIT_OFFSET_MASK);
>   			pr_debug("\t%s\n", sname);
>   		}
> @@ -2267,228 +2251,6 @@ static void free_modinfo(struct module *mod)
>   	}
>   }
>   
> -#ifdef CONFIG_KALLSYMS
> -
> -/* Lookup exported symbol in given range of kernel_symbols */
> -static const struct kernel_symbol *lookup_exported_symbol(const char *name,
> -							  const struct kernel_symbol *start,
> -							  const struct kernel_symbol *stop)
> -{
> -	return bsearch(name, start, stop - start,
> -			sizeof(struct kernel_symbol), cmp_name);
> -}
> -
> -static int is_exported(const char *name, unsigned long value,
> -		       const struct module *mod)
> -{
> -	const struct kernel_symbol *ks;
> -	if (!mod)
> -		ks = lookup_exported_symbol(name, __start___ksymtab, __stop___ksymtab);
> -	else
> -		ks = lookup_exported_symbol(name, mod->syms, mod->syms + mod->num_syms);
> -
> -	return ks != NULL && kernel_symbol_value(ks) == value;
> -}
> -
> -/* As per nm */
> -static char elf_type(const Elf_Sym *sym, const struct load_info *info)
> -{
> -	const Elf_Shdr *sechdrs = info->sechdrs;
> -
> -	if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
> -		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
> -			return 'v';
> -		else
> -			return 'w';
> -	}
> -	if (sym->st_shndx == SHN_UNDEF)
> -		return 'U';
> -	if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
> -		return 'a';
> -	if (sym->st_shndx >= SHN_LORESERVE)
> -		return '?';
> -	if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR)
> -		return 't';
> -	if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC
> -	    && sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) {
> -		if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE))
> -			return 'r';
> -		else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
> -			return 'g';
> -		else
> -			return 'd';
> -	}
> -	if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) {
> -		if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
> -			return 's';
> -		else
> -			return 'b';
> -	}
> -	if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name,
> -		      ".debug")) {
> -		return 'n';
> -	}
> -	return '?';
> -}
> -
> -static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
> -			unsigned int shnum, unsigned int pcpundx)
> -{
> -	const Elf_Shdr *sec;
> -
> -	if (src->st_shndx == SHN_UNDEF
> -	    || src->st_shndx >= shnum
> -	    || !src->st_name)
> -		return false;
> -
> -#ifdef CONFIG_KALLSYMS_ALL
> -	if (src->st_shndx == pcpundx)
> -		return true;
> -#endif
> -
> -	sec = sechdrs + src->st_shndx;
> -	if (!(sec->sh_flags & SHF_ALLOC)
> -#ifndef CONFIG_KALLSYMS_ALL
> -	    || !(sec->sh_flags & SHF_EXECINSTR)
> -#endif
> -	    || (sec->sh_entsize & INIT_OFFSET_MASK))
> -		return false;
> -
> -	return true;
> -}
> -
> -/*
> - * We only allocate and copy the strings needed by the parts of symtab
> - * we keep.  This is simple, but has the effect of making multiple
> - * copies of duplicates.  We could be more sophisticated, see
> - * linux-kernel thread starting with
> - * <73defb5e4bca04a6431392cc341112b1@...alhost>.
> - */
> -static void layout_symtab(struct module *mod, struct load_info *info)
> -{
> -	Elf_Shdr *symsect = info->sechdrs + info->index.sym;
> -	Elf_Shdr *strsect = info->sechdrs + info->index.str;
> -	const Elf_Sym *src;
> -	unsigned int i, nsrc, ndst, strtab_size = 0;
> -
> -	/* Put symbol section at end of init part of module. */
> -	symsect->sh_flags |= SHF_ALLOC;
> -	symsect->sh_entsize = get_offset(mod, &mod->init_layout.size, symsect,
> -					 info->index.sym) | INIT_OFFSET_MASK;
> -	pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
> -
> -	src = (void *)info->hdr + symsect->sh_offset;
> -	nsrc = symsect->sh_size / sizeof(*src);
> -
> -	/* Compute total space required for the core symbols' strtab. */
> -	for (ndst = i = 0; i < nsrc; i++) {
> -		if (i == 0 || is_livepatch_module(mod) ||
> -		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
> -				   info->index.pcpu)) {
> -			strtab_size += strlen(&info->strtab[src[i].st_name])+1;
> -			ndst++;
> -		}
> -	}
> -
> -	/* Append room for core symbols at end of core part. */
> -	info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
> -	info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
> -	mod->core_layout.size += strtab_size;
> -	info->core_typeoffs = mod->core_layout.size;
> -	mod->core_layout.size += ndst * sizeof(char);
> -	mod->core_layout.size = debug_align(mod->core_layout.size);
> -
> -	/* Put string table section at end of init part of module. */
> -	strsect->sh_flags |= SHF_ALLOC;
> -	strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect,
> -					 info->index.str) | INIT_OFFSET_MASK;
> -	pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
> -
> -	/* We'll tack temporary mod_kallsyms on the end. */
> -	mod->init_layout.size = ALIGN(mod->init_layout.size,
> -				      __alignof__(struct mod_kallsyms));
> -	info->mod_kallsyms_init_off = mod->init_layout.size;
> -	mod->init_layout.size += sizeof(struct mod_kallsyms);
> -	info->init_typeoffs = mod->init_layout.size;
> -	mod->init_layout.size += nsrc * sizeof(char);
> -	mod->init_layout.size = debug_align(mod->init_layout.size);
> -}
> -
> -/*
> - * We use the full symtab and strtab which layout_symtab arranged to
> - * be appended to the init section.  Later we switch to the cut-down
> - * core-only ones.
> - */
> -static void add_kallsyms(struct module *mod, const struct load_info *info)
> -{
> -	unsigned int i, ndst;
> -	const Elf_Sym *src;
> -	Elf_Sym *dst;
> -	char *s;
> -	Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
> -
> -	/* Set up to point into init section. */
> -	mod->kallsyms = mod->init_layout.base + info->mod_kallsyms_init_off;
> -
> -	mod->kallsyms->symtab = (void *)symsec->sh_addr;
> -	mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
> -	/* Make sure we get permanent strtab: don't use info->strtab. */
> -	mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
> -	mod->kallsyms->typetab = mod->init_layout.base + info->init_typeoffs;
> -
> -	/*
> -	 * Now populate the cut down core kallsyms for after init
> -	 * and set types up while we still have access to sections.
> -	 */
> -	mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
> -	mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
> -	mod->core_kallsyms.typetab = mod->core_layout.base + info->core_typeoffs;
> -	src = mod->kallsyms->symtab;
> -	for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) {
> -		mod->kallsyms->typetab[i] = elf_type(src + i, info);
> -		if (i == 0 || is_livepatch_module(mod) ||
> -		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
> -				   info->index.pcpu)) {
> -			mod->core_kallsyms.typetab[ndst] =
> -			    mod->kallsyms->typetab[i];
> -			dst[ndst] = src[i];
> -			dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
> -			s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name],
> -				     KSYM_NAME_LEN) + 1;
> -		}
> -	}
> -	mod->core_kallsyms.num_symtab = ndst;
> -}
> -#else
> -static inline void layout_symtab(struct module *mod, struct load_info *info)
> -{
> -}
> -
> -static void add_kallsyms(struct module *mod, const struct load_info *info)
> -{
> -}
> -#endif /* CONFIG_KALLSYMS */
> -
> -#if IS_ENABLED(CONFIG_KALLSYMS) && IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> -static void init_build_id(struct module *mod, const struct load_info *info)
> -{
> -	const Elf_Shdr *sechdr;
> -	unsigned int i;
> -
> -	for (i = 0; i < info->hdr->e_shnum; i++) {
> -		sechdr = &info->sechdrs[i];
> -		if (!sect_empty(sechdr) && sechdr->sh_type == SHT_NOTE &&
> -		    !build_id_parse_buf((void *)sechdr->sh_addr, mod->build_id,
> -					sechdr->sh_size))
> -			break;
> -	}
> -}
> -#else
> -static void init_build_id(struct module *mod, const struct load_info *info)
> -{
> -}
> -#endif
> -
>   static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, unsigned int num)
>   {
>   	if (!debug)
> @@ -3799,287 +3561,6 @@ static inline int within(unsigned long addr, void *start, unsigned long size)
>   	return ((void *)addr >= start && (void *)addr < start + size);
>   }
>   
> -#ifdef CONFIG_KALLSYMS
> -/*
> - * This ignores the intensely annoying "mapping symbols" found
> - * in ARM ELF files: $a, $t and $d.
> - */
> -static inline int is_arm_mapping_symbol(const char *str)
> -{
> -	if (str[0] == '.' && str[1] == 'L')
> -		return true;
> -	return str[0] == '$' && strchr("axtd", str[1])
> -	       && (str[2] == '\0' || str[2] == '.');
> -}
> -
> -static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
> -{
> -	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
> -}
> -
> -/*
> - * Given a module and address, find the corresponding symbol and return its name
> - * while providing its size and offset if needed.
> - */
> -static const char *find_kallsyms_symbol(struct module *mod,
> -					unsigned long addr,
> -					unsigned long *size,
> -					unsigned long *offset)
> -{
> -	unsigned int i, best = 0;
> -	unsigned long nextval, bestval;
> -	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> -
> -	/* At worse, next value is at end of module */
> -	if (within_module_init(addr, mod))
> -		nextval = (unsigned long)mod->init_layout.base+mod->init_layout.text_size;
> -	else
> -		nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
> -
> -	bestval = kallsyms_symbol_value(&kallsyms->symtab[best]);
> -
> -	/*
> -	 * Scan for closest preceding symbol, and next symbol. (ELF
> -	 * starts real symbols at 1).
> -	 */
> -	for (i = 1; i < kallsyms->num_symtab; i++) {
> -		const Elf_Sym *sym = &kallsyms->symtab[i];
> -		unsigned long thisval = kallsyms_symbol_value(sym);
> -
> -		if (sym->st_shndx == SHN_UNDEF)
> -			continue;
> -
> -		/*
> -		 * We ignore unnamed symbols: they're uninformative
> -		 * and inserted at a whim.
> -		 */
> -		if (*kallsyms_symbol_name(kallsyms, i) == '\0'
> -		    || is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
> -			continue;
> -
> -		if (thisval <= addr && thisval > bestval) {
> -			best = i;
> -			bestval = thisval;
> -		}
> -		if (thisval > addr && thisval < nextval)
> -			nextval = thisval;
> -	}
> -
> -	if (!best)
> -		return NULL;
> -
> -	if (size)
> -		*size = nextval - bestval;
> -	if (offset)
> -		*offset = addr - bestval;
> -
> -	return kallsyms_symbol_name(kallsyms, best);
> -}
> -
> -void * __weak dereference_module_function_descriptor(struct module *mod,
> -						     void *ptr)
> -{
> -	return ptr;
> -}
> -
> -/*
> - * For kallsyms to ask for address resolution.  NULL means not found.  Careful
> - * not to lock to avoid deadlock on oopses, simply disable preemption.
> - */
> -const char *module_address_lookup(unsigned long addr,
> -			    unsigned long *size,
> -			    unsigned long *offset,
> -			    char **modname,
> -			    const unsigned char **modbuildid,
> -			    char *namebuf)
> -{
> -	const char *ret = NULL;
> -	struct module *mod;
> -
> -	preempt_disable();
> -	mod = __module_address(addr);
> -	if (mod) {
> -		if (modname)
> -			*modname = mod->name;
> -		if (modbuildid) {
> -#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> -			*modbuildid = mod->build_id;
> -#else
> -			*modbuildid = NULL;
> -#endif
> -		}
> -
> -		ret = find_kallsyms_symbol(mod, addr, size, offset);
> -	}
> -	/* Make a copy in here where it's safe */
> -	if (ret) {
> -		strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
> -		ret = namebuf;
> -	}
> -	preempt_enable();
> -
> -	return ret;
> -}
> -
> -int lookup_module_symbol_name(unsigned long addr, char *symname)
> -{
> -	struct module *mod;
> -
> -	preempt_disable();
> -	list_for_each_entry_rcu(mod, &modules, list) {
> -		if (mod->state == MODULE_STATE_UNFORMED)
> -			continue;
> -		if (within_module(addr, mod)) {
> -			const char *sym;
> -
> -			sym = find_kallsyms_symbol(mod, addr, NULL, NULL);
> -			if (!sym)
> -				goto out;
> -
> -			strlcpy(symname, sym, KSYM_NAME_LEN);
> -			preempt_enable();
> -			return 0;
> -		}
> -	}
> -out:
> -	preempt_enable();
> -	return -ERANGE;
> -}
> -
> -int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
> -			unsigned long *offset, char *modname, char *name)
> -{
> -	struct module *mod;
> -
> -	preempt_disable();
> -	list_for_each_entry_rcu(mod, &modules, list) {
> -		if (mod->state == MODULE_STATE_UNFORMED)
> -			continue;
> -		if (within_module(addr, mod)) {
> -			const char *sym;
> -
> -			sym = find_kallsyms_symbol(mod, addr, size, offset);
> -			if (!sym)
> -				goto out;
> -			if (modname)
> -				strlcpy(modname, mod->name, MODULE_NAME_LEN);
> -			if (name)
> -				strlcpy(name, sym, KSYM_NAME_LEN);
> -			preempt_enable();
> -			return 0;
> -		}
> -	}
> -out:
> -	preempt_enable();
> -	return -ERANGE;
> -}
> -
> -int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
> -			char *name, char *module_name, int *exported)
> -{
> -	struct module *mod;
> -
> -	preempt_disable();
> -	list_for_each_entry_rcu(mod, &modules, list) {
> -		struct mod_kallsyms *kallsyms;
> -
> -		if (mod->state == MODULE_STATE_UNFORMED)
> -			continue;
> -		kallsyms = rcu_dereference_sched(mod->kallsyms);
> -		if (symnum < kallsyms->num_symtab) {
> -			const Elf_Sym *sym = &kallsyms->symtab[symnum];
> -
> -			*value = kallsyms_symbol_value(sym);
> -			*type = kallsyms->typetab[symnum];
> -			strlcpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
> -			strlcpy(module_name, mod->name, MODULE_NAME_LEN);
> -			*exported = is_exported(name, *value, mod);
> -			preempt_enable();
> -			return 0;
> -		}
> -		symnum -= kallsyms->num_symtab;
> -	}
> -	preempt_enable();
> -	return -ERANGE;
> -}
> -
> -/* Given a module and name of symbol, find and return the symbol's value */
> -static unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
> -{
> -	unsigned int i;
> -	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> -
> -	for (i = 0; i < kallsyms->num_symtab; i++) {
> -		const Elf_Sym *sym = &kallsyms->symtab[i];
> -
> -		if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
> -		    sym->st_shndx != SHN_UNDEF)
> -			return kallsyms_symbol_value(sym);
> -	}
> -	return 0;
> -}
> -
> -/* Look for this name: can be of form module:name. */
> -unsigned long module_kallsyms_lookup_name(const char *name)
> -{
> -	struct module *mod;
> -	char *colon;
> -	unsigned long ret = 0;
> -
> -	/* Don't lock: we're in enough trouble already. */
> -	preempt_disable();
> -	if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
> -		if ((mod = find_module_all(name, colon - name, false)) != NULL)
> -			ret = find_kallsyms_symbol_value(mod, colon+1);
> -	} else {
> -		list_for_each_entry_rcu(mod, &modules, list) {
> -			if (mod->state == MODULE_STATE_UNFORMED)
> -				continue;
> -			if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
> -				break;
> -		}
> -	}
> -	preempt_enable();
> -	return ret;
> -}
> -
> -#ifdef CONFIG_LIVEPATCH
> -int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
> -					     struct module *, unsigned long),
> -				   void *data)
> -{
> -	struct module *mod;
> -	unsigned int i;
> -	int ret = 0;
> -
> -	mutex_lock(&module_mutex);
> -	list_for_each_entry(mod, &modules, list) {
> -		/* We hold module_mutex: no need for rcu_dereference_sched */
> -		struct mod_kallsyms *kallsyms = mod->kallsyms;
> -
> -		if (mod->state == MODULE_STATE_UNFORMED)
> -			continue;
> -		for (i = 0; i < kallsyms->num_symtab; i++) {
> -			const Elf_Sym *sym = &kallsyms->symtab[i];
> -
> -			if (sym->st_shndx == SHN_UNDEF)
> -				continue;
> -
> -			ret = fn(data, kallsyms_symbol_name(kallsyms, i),
> -				 mod, kallsyms_symbol_value(sym));
> -			if (ret != 0)
> -				goto out;
> -
> -			cond_resched();
> -		}
> -	}
> -out:
> -	mutex_unlock(&module_mutex);
> -	return ret;
> -}
> -#endif /* CONFIG_LIVEPATCH */
> -#endif /* CONFIG_KALLSYMS */
> -
>   static void cfi_init(struct module *mod)
>   {
>   #ifdef CONFIG_CFI_CLANG

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ