admin管理员组文章数量:1632964
目录
- 出现[permanent]的原因
- 分析驱动加载异常的情况
测试环境 suse 11 sp4 3.0.101-63
出现[permanent]的原因
- 没有编写驱动exit函数
- 驱动加载异常
- 源码
// kernel/module.c static inline void print_unload_info(struct seq_file *m, struct module *mod) { struct module_use *use; int printed_something = 0; seq_printf(m, " %u ", module_refcount(mod)); /* Always include a trailing , so userspace can differentiate between this and the old multi-field proc format. */ list_for_each_entry(use, &mod->source_list, source_list) { printed_something = 1; seq_printf(m, "%s,", use->source->name); } // 可见只有当 mod->init 存在,mod->exit 为零 if (mod->init != NULL && mod->exit == NULL) { printed_something = 1; seq_printf(m, "[permanent],"); } if (!printed_something) seq_printf(m, "-"); }
分析驱动加载异常的情况
当前只遇到这种
gcc版本不一致,导致结构体使用的对齐不一致,导致结构体的内存不一致
-
struct module 记录到 this_module
// include/linux/module.h struct module { enum module_state state; ... #ifdef CONFIG_MODULE_UNLOAD /* What modules depend on me? */ struct list_head source_list; /* What modules do I depend on? */ struct list_head target_list; /* Who is waiting for us to be unloaded */ struct task_struct *waiter; /* Destruction function. */ void (*exit)(void); struct module_ref { unsigned int incs; unsigned int decs; } __percpu *refptr; #endif // 没有配置CONFIG_CONSTRUCTORS,所以下面这段不编译 #ifdef CONFIG_CONSTRUCTORS /* Constructor functions. */ ctor_fn_t *ctors; unsigned int num_ctors; #endif };
-
加载驱动时,this_module的加载:
/* * Set up our basic convenience variables (pointers to section headers, * search for module section index etc), and do some basic section * verification. * * Return the temporary module pointer (we'll replace it with the final * one when we move the module sections around). */ static struct module *setup_load_info(struct load_info *info) { unsigned int i; int err; struct module *mod; /* Set up the convenience variables */ info->sechdrs = (void *)info->hdr + info->hdr->e_shoff; info->secstrings = (void *)info->hdr + info->sechdrs[info->hdr->e_shstrndx].sh_offset; err = rewrite_section_headers(info); if (err) return ERR_PTR(err); /* Find internal symbols and strings. */ for (i = 1; i < info->hdr->e_shnum; i++) { if (info->sechdrs[i].sh_type == SHT_SYMTAB) { info->index.sym = i; info->index.str = info->sechdrs[i].sh_link; info->strtab = (char *)info->hdr + info->sechdrs[info->index.str].sh_offset; break; } } // 加载this_module info->index.mod = find_sec(info, ".gnu.linkonce.this_module"); if (!info->index.mod) { printk(KERN_WARNING "No module found in object\n"); return ERR_PTR(-ENOEXEC); } /* This is temporary: point mod into copy of data. */ mod = (void *)info->sechdrs[info->index.mod].sh_addr; if (info->index.sym == 0) { printk(KERN_WARNING "%s: module has no symbols (stripped?)\n", mod->name); return ERR_PTR(-ENOEXEC); } info->index.pcpu = find_pcpusec(info); /* Check module struct version now, before we try to use module. */ if (!check_modstruct_version(info->sechdrs, info->index.vers, mod)) return ERR_PTR(-ENOEXEC); return mod; }
-
读取驱动的.this_module:
readelf -x .gnu.linkonce.this_module filename
readelf -x .rela.gnu.linkonce.this_module filename
由重定向信息(.rela.gnu.linkonce.this_module
)可得:
左边:0x248被重定向,重定向的符号在符号下标为0x73(115),其实就是exit函数root:~$ readelf -s filename ... 115: 0000000000000000 131 FUNC GLOBAL DEFAULT 4 cleanup_module ... # module_init(xxx_init); 将xxx_init 重命名为 init_module # module_exit(xxx_tgt_exit);将xxx_exit 重命名为 cleanup_module
右边:0x250被重定向,重定向的符号在符号下标为0x6e(110),其实就是exit函数
... 110: 0000000000000000 131 FUNC GLOBAL DEFAULT 4 cleanup_module ...
可见,左边的
*exit
被放到0x248
的位置,右边的*exit
被放到了0x250
的位置,如果使用左边的系统加载右边的驱动,即使可以正确重定向,即改变了0x250(左边*refptr
)的值,但0x248(左边的*exit
)没有改变仍然为0(NULL
),这钟情况容易导致引用数错误(*refptr)
elf 分析
版权声明:本文标题:linux module [permanent] 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1729149070a1187886.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论