3358 lines · 85.3 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * Copyright (C) 2002 Richard Henderson * Copyright (C) 2001 Rusty Russell, 2002, 2010 Rusty Russell IBM. * Copyright (C) 2023 Luis Chamberlain <mcgrof@kernel.org> */ #define INCLUDE_VERMAGIC #include <linux/export.h>#include <linux/extable.h>#include <linux/moduleloader.h>#include <linux/module_signature.h>#include <linux/trace_events.h>#include <linux/init.h>#include <linux/kallsyms.h>#include <linux/buildid.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/kernel_read_file.h>#include <linux/kstrtox.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/elf.h>#include <linux/seq_file.h>#include <linux/syscalls.h>#include <linux/fcntl.h>#include <linux/rcupdate.h>#include <linux/capability.h>#include <linux/cpu.h>#include <linux/moduleparam.h>#include <linux/errno.h>#include <linux/err.h>#include <linux/vermagic.h>#include <linux/notifier.h>#include <linux/sched.h>#include <linux/device.h>#include <linux/string.h>#include <linux/mutex.h>#include <linux/rculist.h>#include <linux/uaccess.h>#include <asm/cacheflush.h>#include <linux/set_memory.h>#include <asm/mmu_context.h>#include <linux/license.h>#include <asm/sections.h>#include <linux/tracepoint.h>#include <linux/ftrace.h>#include <linux/livepatch.h>#include <linux/async.h>#include <linux/percpu.h>#include <linux/kmemleak.h>#include <linux/jump_label.h>#include <linux/pfn.h>#include <linux/bsearch.h>#include <linux/dynamic_debug.h>#include <linux/audit.h>#include <linux/cfi.h>#include <linux/debugfs.h>#include <uapi/linux/module.h>#include "internal.h" #define CREATE_TRACE_POINTS#include <trace/events/module.h> /* * Mutex protects: * 1) List of modules (also safely readable with preempt_disable), * 2) module_use links, * 3) mod_tree.addr_min/mod_tree.addr_max. * (delete and add uses RCU list operations). */DEFINE_MUTEX(module_mutex);LIST_HEAD(modules); /* Work queue for freeing init sections in success case */static void do_free_init(struct work_struct *w);static DECLARE_WORK(init_free_wq, do_free_init);static LLIST_HEAD(init_free_list); struct mod_tree_root mod_tree __cacheline_aligned = {	.addr_min = -1UL,}; struct symsearch {	const struct kernel_symbol *start, *stop;	const s32 *crcs;	enum mod_license license;}; /* * Bounds of module memory, for speeding up __module_address. * Protected by module_mutex. */static void __mod_update_bounds(enum mod_mem_type type __maybe_unused, void *base,				unsigned int size, struct mod_tree_root *tree){	unsigned long min = (unsigned long)base;	unsigned long max = min + size; #ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC	if (mod_mem_type_is_core_data(type)) {		if (min < tree->data_addr_min)			tree->data_addr_min = min;		if (max > tree->data_addr_max)			tree->data_addr_max = max;		return;	}#endif	if (min < tree->addr_min)		tree->addr_min = min;	if (max > tree->addr_max)		tree->addr_max = max;} static void mod_update_bounds(struct module *mod){	for_each_mod_mem_type(type) {		struct module_memory *mod_mem = &mod->mem[type]; 		if (mod_mem->size)			__mod_update_bounds(type, mod_mem->base, mod_mem->size, &mod_tree);	}} /* Block module loading/unloading? */int modules_disabled;core_param(nomodule, modules_disabled, bint, 0); /* Waiting for a module to finish initializing? */static DECLARE_WAIT_QUEUE_HEAD(module_wq); static BLOCKING_NOTIFIER_HEAD(module_notify_list); int register_module_notifier(struct notifier_block *nb){	return blocking_notifier_chain_register(&module_notify_list, nb);}EXPORT_SYMBOL(register_module_notifier); int unregister_module_notifier(struct notifier_block *nb){	return blocking_notifier_chain_unregister(&module_notify_list, nb);}EXPORT_SYMBOL(unregister_module_notifier); /* * We require a truly strong try_module_get(): 0 means success. * Otherwise an error is returned due to ongoing or failed * initialization etc. */static inline int strong_try_module_get(struct module *mod){	BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED);	if (mod && mod->state == MODULE_STATE_COMING)		return -EBUSY;	if (try_module_get(mod))		return 0;	else		return -ENOENT;} static inline void add_taint_module(struct module *mod, unsigned flag,				    enum lockdep_ok lockdep_ok){	add_taint(flag, lockdep_ok);	set_bit(flag, &mod->taints);} /* * A thread that wants to hold a reference to a module only while it * is running can call this to safely exit. */void __noreturn __module_put_and_kthread_exit(struct module *mod, long code){	module_put(mod);	kthread_exit(code);}EXPORT_SYMBOL(__module_put_and_kthread_exit); /* Find a module section: 0 means not found. */static unsigned int find_sec(const struct load_info *info, const char *name){	unsigned int i; 	for (i = 1; i < info->hdr->e_shnum; i++) {		Elf_Shdr *shdr = &info->sechdrs[i];		/* Alloc bit cleared means "ignore it." */		if ((shdr->sh_flags & SHF_ALLOC)		    && strcmp(info->secstrings + shdr->sh_name, name) == 0)			return i;	}	return 0;} /* Find a module section, or NULL. */static void *section_addr(const struct load_info *info, const char *name){	/* Section 0 has sh_addr 0. */	return (void *)info->sechdrs[find_sec(info, name)].sh_addr;} /* Find a module section, or NULL.  Fill in number of "objects" in section. */static void *section_objs(const struct load_info *info,			  const char *name,			  size_t object_size,			  unsigned int *num){	unsigned int sec = find_sec(info, name); 	/* Section 0 has sh_addr 0 and sh_size 0. */	*num = info->sechdrs[sec].sh_size / object_size;	return (void *)info->sechdrs[sec].sh_addr;} /* Find a module section: 0 means not found. Ignores SHF_ALLOC flag. */static unsigned int find_any_sec(const struct load_info *info, const char *name){	unsigned int i; 	for (i = 1; i < info->hdr->e_shnum; i++) {		Elf_Shdr *shdr = &info->sechdrs[i];		if (strcmp(info->secstrings + shdr->sh_name, name) == 0)			return i;	}	return 0;} /* * Find a module section, or NULL. Fill in number of "objects" in section. * Ignores SHF_ALLOC flag. */static __maybe_unused void *any_section_objs(const struct load_info *info,					     const char *name,					     size_t object_size,					     unsigned int *num){	unsigned int sec = find_any_sec(info, name); 	/* Section 0 has sh_addr 0 and sh_size 0. */	*num = info->sechdrs[sec].sh_size / object_size;	return (void *)info->sechdrs[sec].sh_addr;} #ifndef CONFIG_MODVERSIONS#define symversion(base, idx) NULL#else#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)#endif static const char *kernel_symbol_name(const struct kernel_symbol *sym){#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS	return offset_to_ptr(&sym->name_offset);#else	return sym->name;#endif} static const char *kernel_symbol_namespace(const struct kernel_symbol *sym){#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS	if (!sym->namespace_offset)		return NULL;	return offset_to_ptr(&sym->namespace_offset);#else	return sym->namespace;#endif} int cmp_name(const void *name, const void *sym){	return strcmp(name, kernel_symbol_name(sym));} static bool find_exported_symbol_in_section(const struct symsearch *syms,					    struct module *owner,					    struct find_symbol_arg *fsa){	struct kernel_symbol *sym; 	if (!fsa->gplok && syms->license == GPL_ONLY)		return false; 	sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,			sizeof(struct kernel_symbol), cmp_name);	if (!sym)		return false; 	fsa->owner = owner;	fsa->crc = symversion(syms->crcs, sym - syms->start);	fsa->sym = sym;	fsa->license = syms->license; 	return true;} /* * Find an exported symbol and return it, along with, (optional) crc and * (optional) module which owns it.  Needs preempt disabled or module_mutex. */bool find_symbol(struct find_symbol_arg *fsa){	static const struct symsearch arr[] = {		{ __start___ksymtab, __stop___ksymtab, __start___kcrctab,		  NOT_GPL_ONLY },		{ __start___ksymtab_gpl, __stop___ksymtab_gpl,		  __start___kcrctab_gpl,		  GPL_ONLY },	};	struct module *mod;	unsigned int i; 	module_assert_mutex_or_preempt(); 	for (i = 0; i < ARRAY_SIZE(arr); i++)		if (find_exported_symbol_in_section(&arr[i], NULL, fsa))			return true; 	list_for_each_entry_rcu(mod, &modules, list,				lockdep_is_held(&module_mutex)) {		struct symsearch arr[] = {			{ mod->syms, mod->syms + mod->num_syms, mod->crcs,			  NOT_GPL_ONLY },			{ mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,			  mod->gpl_crcs,			  GPL_ONLY },		}; 		if (mod->state == MODULE_STATE_UNFORMED)			continue; 		for (i = 0; i < ARRAY_SIZE(arr); i++)			if (find_exported_symbol_in_section(&arr[i], mod, fsa))				return true;	} 	pr_debug("Failed to find symbol %s\n", fsa->name);	return false;} /* * Search for module by name: must hold module_mutex (or preempt disabled * for read-only access). */struct module *find_module_all(const char *name, size_t len,			       bool even_unformed){	struct module *mod; 	module_assert_mutex_or_preempt(); 	list_for_each_entry_rcu(mod, &modules, list,				lockdep_is_held(&module_mutex)) {		if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)			continue;		if (strlen(mod->name) == len && !memcmp(mod->name, name, len))			return mod;	}	return NULL;} struct module *find_module(const char *name){	return find_module_all(name, strlen(name), false);} #ifdef CONFIG_SMP static inline void __percpu *mod_percpu(struct module *mod){	return mod->percpu;} static int percpu_modalloc(struct module *mod, struct load_info *info){	Elf_Shdr *pcpusec = &info->sechdrs[info->index.pcpu];	unsigned long align = pcpusec->sh_addralign; 	if (!pcpusec->sh_size)		return 0; 	if (align > PAGE_SIZE) {		pr_warn("%s: per-cpu alignment %li > %li\n",			mod->name, align, PAGE_SIZE);		align = PAGE_SIZE;	} 	mod->percpu = __alloc_reserved_percpu(pcpusec->sh_size, align);	if (!mod->percpu) {		pr_warn("%s: Could not allocate %lu bytes percpu data\n",			mod->name, (unsigned long)pcpusec->sh_size);		return -ENOMEM;	}	mod->percpu_size = pcpusec->sh_size;	return 0;} static void percpu_modfree(struct module *mod){	free_percpu(mod->percpu);} static unsigned int find_pcpusec(struct load_info *info){	return find_sec(info, ".data..percpu");} static void percpu_modcopy(struct module *mod,			   const void *from, unsigned long size){	int cpu; 	for_each_possible_cpu(cpu)		memcpy(per_cpu_ptr(mod->percpu, cpu), from, size);} bool __is_module_percpu_address(unsigned long addr, unsigned long *can_addr){	struct module *mod;	unsigned int cpu; 	preempt_disable(); 	list_for_each_entry_rcu(mod, &modules, list) {		if (mod->state == MODULE_STATE_UNFORMED)			continue;		if (!mod->percpu_size)			continue;		for_each_possible_cpu(cpu) {			void *start = per_cpu_ptr(mod->percpu, cpu);			void *va = (void *)addr; 			if (va >= start && va < start + mod->percpu_size) {				if (can_addr) {					*can_addr = (unsigned long) (va - start);					*can_addr += (unsigned long)						per_cpu_ptr(mod->percpu,							    get_boot_cpu_id());				}				preempt_enable();				return true;			}		}	} 	preempt_enable();	return false;} /** * is_module_percpu_address() - test whether address is from module static percpu * @addr: address to test * * Test whether @addr belongs to module static percpu area. * * Return: %true if @addr is from module static percpu area */bool is_module_percpu_address(unsigned long addr){	return __is_module_percpu_address(addr, NULL);} #else /* ... !CONFIG_SMP */ static inline void __percpu *mod_percpu(struct module *mod){	return NULL;}static int percpu_modalloc(struct module *mod, struct load_info *info){	/* UP modules shouldn't have this section: ENOMEM isn't quite right */	if (info->sechdrs[info->index.pcpu].sh_size != 0)		return -ENOMEM;	return 0;}static inline void percpu_modfree(struct module *mod){}static unsigned int find_pcpusec(struct load_info *info){	return 0;}static inline void percpu_modcopy(struct module *mod,				  const void *from, unsigned long size){	/* pcpusec should be 0, and size of that section should be 0. */	BUG_ON(size != 0);}bool is_module_percpu_address(unsigned long addr){	return false;} bool __is_module_percpu_address(unsigned long addr, unsigned long *can_addr){	return false;} #endif /* CONFIG_SMP */

Lines 1–500 of 3358.