/* SPDX-License-Identifier: GPL-2.0-or-later */ /* Module internals * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) */ #include #include #include #include #include #ifndef ARCH_SHF_SMALL #define ARCH_SHF_SMALL 0 #endif /* If this is set, the section belongs in the init part of the module */ #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG - 1)) /* Maximum number of characters written by module_flags() */ #define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4) /* * Modules' sections will be aligned on page boundaries * to ensure complete separation of code and data, but * only when CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y */ #ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX # define debug_align(X) PAGE_ALIGN(X) #else # define debug_align(X) (X) #endif extern struct mutex module_mutex; extern struct list_head modules; /* Provided by the linker */ extern const struct kernel_symbol __start___ksymtab[]; extern const struct kernel_symbol __stop___ksymtab[]; extern const struct kernel_symbol __start___ksymtab_gpl[]; extern const struct kernel_symbol __stop___ksymtab_gpl[]; extern const s32 __start___kcrctab[]; extern const s32 __start___kcrctab_gpl[]; struct load_info { const char *name; /* pointer to module in temporary copy, freed at end of load_module() */ struct module *mod; Elf_Ehdr *hdr; unsigned long len; Elf_Shdr *sechdrs; char *secstrings, *strtab; unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs; struct _ddebug *debug; unsigned int num_debug; bool sig_ok; #ifdef CONFIG_KALLSYMS unsigned long mod_kallsyms_init_off; #endif #ifdef CONFIG_MODULE_DECOMPRESS struct page **pages; unsigned int max_pages; unsigned int used_pages; #endif struct { unsigned int sym, str, mod, vers, info, pcpu; } index; }; int mod_verify_sig(const void *mod, struct load_info *info); #ifdef CONFIG_LIVEPATCH int copy_module_elf(struct module *mod, struct load_info *info); void free_module_elf(struct module *mod); #else /* !CONFIG_LIVEPATCH */ static inline int copy_module_elf(struct module *mod, struct load_info *info) { return 0; } static inline void free_module_elf(struct module *mod) { } #endif /* CONFIG_LIVEPATCH */ static inline bool set_livepatch_module(struct module *mod) { #ifdef CONFIG_LIVEPATCH mod->klp = true; return true; #else return false; #endif } #ifdef CONFIG_MODULE_DECOMPRESS int module_decompress(struct load_info *info, const void *buf, size_t size); void module_decompress_cleanup(struct load_info *info); #else static inline int module_decompress(struct load_info *info, const void *buf, size_t size) { return -EOPNOTSUPP; } static inline void module_decompress_cleanup(struct load_info *info) { } #endif #ifdef CONFIG_MODULES_TREE_LOOKUP struct mod_tree_root { struct latch_tree_root root; unsigned long addr_min; unsigned long addr_max; }; extern struct mod_tree_root mod_tree; void mod_tree_insert(struct module *mod); void mod_tree_remove_init(struct module *mod); void mod_tree_remove(struct module *mod); struct module *mod_find(unsigned long addr); #else /* !CONFIG_MODULES_TREE_LOOKUP */ static inline void mod_tree_insert(struct module *mod) { } static inline void mod_tree_remove_init(struct module *mod) { } static inline void mod_tree_remove(struct module *mod) { } static inline struct module *mod_find(unsigned long addr) { struct module *mod; list_for_each_entry_rcu(mod, &modules, list, lockdep_is_held(&module_mutex)) { if (within_module(addr, mod)) return mod; } return NULL; } #endif /* CONFIG_MODULES_TREE_LOOKUP */ #ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX void frob_text(const struct module_layout *layout, int (*set_memory)(unsigned long start, int num_pages)); #endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */ #ifdef CONFIG_STRICT_MODULE_RWX void module_enable_ro(const struct module *mod, bool after_init); void module_enable_nx(const struct module *mod); int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod); #else /* !CONFIG_STRICT_MODULE_RWX */ static inline void module_enable_nx(const struct module *mod) { } static inline void module_enable_ro(const struct module *mod, bool after_init) {} static inline int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { return 0; } #endif /* CONFIG_STRICT_MODULE_RWX */ #ifdef CONFIG_MODULE_SIG int module_sig_check(struct load_info *info, int flags); #else /* !CONFIG_MODULE_SIG */ static inline int module_sig_check(struct load_info *info, int flags) { return 0; } #endif /* !CONFIG_MODULE_SIG */ #ifdef CONFIG_DEBUG_KMEMLEAK void kmemleak_load_module(const struct module *mod, const struct load_info *info); #else /* !CONFIG_DEBUG_KMEMLEAK */ static inline void kmemleak_load_module(const struct module *mod, const struct load_info *info) { } #endif /* CONFIG_DEBUG_KMEMLEAK */