📄 module.c
字号:
amagic += strcspn(amagic, " "); bmagic += strcspn(bmagic, " "); } return strcmp(amagic, bmagic) == 0;}#elsestatic inline int check_version(Elf_Shdr *sechdrs, unsigned int versindex, const char *symname, struct module *mod, const unsigned long *crc){ return 1;}static inline int check_modstruct_version(Elf_Shdr *sechdrs, unsigned int versindex, struct module *mod){ return 1;}static inline int same_magic(const char *amagic, const char *bmagic, bool has_crcs){ return strcmp(amagic, bmagic) == 0;}#endif /* CONFIG_MODVERSIONS *//* Resolve a symbol for this module. I.e. if we find one, record usage. Must be holding module_mutex. */static unsigned long resolve_symbol(Elf_Shdr *sechdrs, unsigned int versindex, const char *name, struct module *mod){ struct module *owner; unsigned long ret; const unsigned long *crc; ret = find_symbol(name, &owner, &crc, !(mod->taints & TAINT_PROPRIETARY_MODULE), true); if (!IS_ERR_VALUE(ret)) { /* use_module can fail due to OOM, or module initialization or unloading */ if (!check_version(sechdrs, versindex, name, mod, crc) || !use_module(mod, owner)) ret = -EINVAL; } return ret;}/* * /sys/module/foo/sections stuff * J. Corbet <corbet@lwn.net> */#if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS)struct module_sect_attr{ struct module_attribute mattr; char *name; unsigned long address;};struct module_sect_attrs{ struct attribute_group grp; unsigned int nsections; struct module_sect_attr attrs[0];};static ssize_t module_sect_show(struct module_attribute *mattr, struct module *mod, char *buf){ struct module_sect_attr *sattr = container_of(mattr, struct module_sect_attr, mattr); return sprintf(buf, "0x%lx\n", sattr->address);}static void free_sect_attrs(struct module_sect_attrs *sect_attrs){ unsigned int section; for (section = 0; section < sect_attrs->nsections; section++) kfree(sect_attrs->attrs[section].name); kfree(sect_attrs);}static void add_sect_attrs(struct module *mod, unsigned int nsect, char *secstrings, Elf_Shdr *sechdrs){ unsigned int nloaded = 0, i, size[2]; struct module_sect_attrs *sect_attrs; struct module_sect_attr *sattr; struct attribute **gattr; /* Count loaded sections and allocate structures */ for (i = 0; i < nsect; i++) if (sechdrs[i].sh_flags & SHF_ALLOC) nloaded++; size[0] = ALIGN(sizeof(*sect_attrs) + nloaded * sizeof(sect_attrs->attrs[0]), sizeof(sect_attrs->grp.attrs[0])); size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]); sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL); if (sect_attrs == NULL) return; /* Setup section attributes. */ sect_attrs->grp.name = "sections"; sect_attrs->grp.attrs = (void *)sect_attrs + size[0]; sect_attrs->nsections = 0; sattr = §_attrs->attrs[0]; gattr = §_attrs->grp.attrs[0]; for (i = 0; i < nsect; i++) { if (! (sechdrs[i].sh_flags & SHF_ALLOC)) continue; sattr->address = sechdrs[i].sh_addr; sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, GFP_KERNEL); if (sattr->name == NULL) goto out; sect_attrs->nsections++; sattr->mattr.show = module_sect_show; sattr->mattr.store = NULL; sattr->mattr.attr.name = sattr->name; sattr->mattr.attr.mode = S_IRUGO; *(gattr++) = &(sattr++)->mattr.attr; } *gattr = NULL; if (sysfs_create_group(&mod->mkobj.kobj, §_attrs->grp)) goto out; mod->sect_attrs = sect_attrs; return; out: free_sect_attrs(sect_attrs);}static void remove_sect_attrs(struct module *mod){ if (mod->sect_attrs) { sysfs_remove_group(&mod->mkobj.kobj, &mod->sect_attrs->grp); /* We are positive that no one is using any sect attrs * at this point. Deallocate immediately. */ free_sect_attrs(mod->sect_attrs); mod->sect_attrs = NULL; }}/* * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections. */struct module_notes_attrs { struct kobject *dir; unsigned int notes; struct bin_attribute attrs[0];};static ssize_t module_notes_read(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count){ /* * The caller checked the pos and count against our size. */ memcpy(buf, bin_attr->private + pos, count); return count;}static void free_notes_attrs(struct module_notes_attrs *notes_attrs, unsigned int i){ if (notes_attrs->dir) { while (i-- > 0) sysfs_remove_bin_file(notes_attrs->dir, ¬es_attrs->attrs[i]); kobject_put(notes_attrs->dir); } kfree(notes_attrs);}static void add_notes_attrs(struct module *mod, unsigned int nsect, char *secstrings, Elf_Shdr *sechdrs){ unsigned int notes, loaded, i; struct module_notes_attrs *notes_attrs; struct bin_attribute *nattr; /* Count notes sections and allocate structures. */ notes = 0; for (i = 0; i < nsect; i++) if ((sechdrs[i].sh_flags & SHF_ALLOC) && (sechdrs[i].sh_type == SHT_NOTE)) ++notes; if (notes == 0) return; notes_attrs = kzalloc(sizeof(*notes_attrs) + notes * sizeof(notes_attrs->attrs[0]), GFP_KERNEL); if (notes_attrs == NULL) return; notes_attrs->notes = notes; nattr = ¬es_attrs->attrs[0]; for (loaded = i = 0; i < nsect; ++i) { if (!(sechdrs[i].sh_flags & SHF_ALLOC)) continue; if (sechdrs[i].sh_type == SHT_NOTE) { nattr->attr.name = mod->sect_attrs->attrs[loaded].name; nattr->attr.mode = S_IRUGO; nattr->size = sechdrs[i].sh_size; nattr->private = (void *) sechdrs[i].sh_addr; nattr->read = module_notes_read; ++nattr; } ++loaded; } notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj); if (!notes_attrs->dir) goto out; for (i = 0; i < notes; ++i) if (sysfs_create_bin_file(notes_attrs->dir, ¬es_attrs->attrs[i])) goto out; mod->notes_attrs = notes_attrs; return; out: free_notes_attrs(notes_attrs, i);}static void remove_notes_attrs(struct module *mod){ if (mod->notes_attrs) free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);}#elsestatic inline void add_sect_attrs(struct module *mod, unsigned int nsect, char *sectstrings, Elf_Shdr *sechdrs){}static inline void remove_sect_attrs(struct module *mod){}static inline void add_notes_attrs(struct module *mod, unsigned int nsect, char *sectstrings, Elf_Shdr *sechdrs){}static inline void remove_notes_attrs(struct module *mod){}#endif#ifdef CONFIG_SYSFSint module_add_modinfo_attrs(struct module *mod){ struct module_attribute *attr; struct module_attribute *temp_attr; int error = 0; int i; mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) * (ARRAY_SIZE(modinfo_attrs) + 1)), GFP_KERNEL); if (!mod->modinfo_attrs) return -ENOMEM; temp_attr = mod->modinfo_attrs; for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { if (!attr->test || (attr->test && attr->test(mod))) { memcpy(temp_attr, attr, sizeof(*temp_attr)); error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr); ++temp_attr; } } return error;}void module_remove_modinfo_attrs(struct module *mod){ struct module_attribute *attr; int i; for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) { /* pick a field to test for end of list */ if (!attr->attr.name) break; sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); if (attr->free) attr->free(mod); } kfree(mod->modinfo_attrs);}int mod_sysfs_init(struct module *mod){ int err; struct kobject *kobj; if (!module_sysfs_initialized) { printk(KERN_ERR "%s: module sysfs not initialized\n", mod->name); err = -EINVAL; goto out; } kobj = kset_find_obj(module_kset, mod->name); if (kobj) { printk(KERN_ERR "%s: module is already loaded\n", mod->name); kobject_put(kobj); err = -EINVAL; goto out; } mod->mkobj.mod = mod; memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); mod->mkobj.kobj.kset = module_kset; err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL, "%s", mod->name); if (err) kobject_put(&mod->mkobj.kobj); /* delay uevent until full sysfs population */out: return err;}int mod_sysfs_setup(struct module *mod, struct kernel_param *kparam, unsigned int num_params){ int err; mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj); if (!mod->holders_dir) { err = -ENOMEM; goto out_unreg; } err = module_param_sysfs_setup(mod, kparam, num_params); if (err) goto out_unreg_holders; err = module_add_modinfo_attrs(mod); if (err) goto out_unreg_param; kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD); return 0;out_unreg_param: module_param_sysfs_remove(mod);out_unreg_holders: kobject_put(mod->holders_dir);out_unreg: kobject_put(&mod->mkobj.kobj); return err;}static void mod_sysfs_fini(struct module *mod){ kobject_put(&mod->mkobj.kobj);}#else /* CONFIG_SYSFS */static void mod_sysfs_fini(struct module *mod){}#endif /* CONFIG_SYSFS */static void mod_kobject_remove(struct module *mod){ module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); kobject_put(mod->mkobj.drivers_dir); kobject_put(mod->holders_dir); mod_sysfs_fini(mod);}/* * link the module with the whole machine is stopped with interrupts off * - this defends against kallsyms not taking locks */static int __link_module(void *_mod){ struct module *mod = _mod; list_add(&mod->list, &modules); return 0;}/* * unlink the module with the whole machine is stopped with interrupts off * - this defends against kallsyms not taking locks */static int __unlink_module(void *_mod){ struct module *mod = _mod; list_del(&mod->list); return 0;}/* Free a module, remove from lists, etc (must hold module_mutex). */static void free_module(struct module *mod){ /* Delete from various lists */ stop_machine(__unlink_module, mod, NULL); remove_notes_attrs(mod); remove_sect_attrs(mod); mod_kobject_remove(mod); unwind_remove_table(mod->unwind_info, 0); /* Arch-specific cleanup. */ module_arch_cleanup(mod); /* Module unload stuff */ module_unload_free(mod); /* This may be NULL, but that's OK */ module_free(mod, mod->module_init); kfree(mod->args); if (mod->percpu) percpu_modfree(mod->percpu); /* Free lock-classes: */ lockdep_free_key_range(mod->module_core, mod->core_size); /* Finally, free the core (containing the module structure) */ module_free(mod, mod->module_core);}void *__symbol_get(const char *symbol){ struct module *owner; unsigned long value; preempt_disable(); value = find_symbol(symbol, &owner, NULL, true, true); if (IS_ERR_VALUE(value)) value = 0; else if (strong_try_module_get(owner)) value = 0; preempt_enable(); return (void *)value;}EXPORT_SYMBOL_GPL(__symbol_get);/* * Ensure that an exported symbol [global namespace] does not already exist * in the kernel or in some other module's exported symbol table. */static int verify_export_symbols(struct module *mod){ unsigned int i; struct module *owner; const struct kernel_symbol *s; struct { const struct kernel_symbol *sym; unsigned int num; } arr[] = { { mod->syms, mod->num_syms }, { mod->gpl_syms, mod->num_gpl_syms }, { mod->gpl_future_syms, mod->num_gpl_future_syms },#ifdef CONFIG_UNUSED_SYMBOLS { mod->unused_syms, mod->num_unused_syms }, { mod->unused_gpl_syms, mod->num_unused_gpl_syms },#endif }; for (i = 0; i < ARRAY_SIZE(arr); i++) { for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { if (!IS_ERR_VALUE(find_symbol(s->name, &owner, NULL, true, false))) { printk(KERN_ERR "%s: exports duplicate symbol %s" " (owned by %s)\n", mod->name, s->name, module_name(owner));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -