模塊加載
load_module()
函數(shù)調用的功能函數(shù)如下:
module_sig_check()
函數(shù)用于檢查模塊的簽名驗證elf_header_check()
函數(shù)用于檢查模塊的elf頭和區(qū)段有效性layout_and_allocate()
函數(shù)用于分配內核內存空間,把模塊相關的節(jié)區(qū)復制過來audit_log_kern_module()
函數(shù)用于檢查是否開啟了安全審計add_unformed_module()
函數(shù)用于判斷模塊是否已經加載,若沒有則將模塊添加到內核模塊鏈表中percpu_modalloc()
函數(shù)用于申請percpu變量內存,這個變量每個CPU都有一份,無相獨立module_unload_init()
函數(shù)用于初始化化模塊依賴和引用鏈表,并對模塊引用計數(shù)加1init_param_lock()
函數(shù)用于初始化互斥鎖find_module_sections()
函數(shù)用于遍歷模塊中的其它分段check_module_license_and_versions()
函數(shù)用于檢測模塊的CRC是否正確,license授權是否正確setup_modinfo()
函數(shù)根據(jù).modinfo段設置模塊信息simplify_symbols()
函數(shù)用于將模塊內存中的靜態(tài)鏈接重定位表中的符號,全部指向其真實的內存地址apply_relocations()
函數(shù)用于遍歷目標文件中的所有內存節(jié)區(qū)的重定位節(jié)區(qū),并遍歷每個節(jié)區(qū)中的每個靜態(tài)鏈接重定位表項,對其做靜態(tài)鏈接post_relocation()
函數(shù)用于對重定位后的percpu變量重新賦值,并將即將加載完成的模塊的符號加入到內核模塊的符號鏈表中,如果成功加載此模塊且內核配置了CONFIG_KALLSYMS
,那么在/proc/kallsyms下可以看到此模塊的符號flush_module_icache()
函數(shù)用于刷新模塊的init_layout和core_layout的cache。strndup_user()
函數(shù)用于復制用戶空間的參數(shù)到內核空間dynamic_debug_setup()
函數(shù)用于處理debug
節(jié)區(qū),需要開啟內核CONFIG_DYNAMIC_DEBUG
才會啟用ftrace_module_init()
函數(shù)需要開啟相關的ftrace配置complete_formation()
函數(shù)用于遍歷模塊中的所有導出函數(shù),并檢查在內核中是否有同名的導出符號,為模塊的init_layout/core_layout做RONX保護prepare_coming_module()
函數(shù)用于發(fā)送模塊加載通知鏈parse_args()
函數(shù)用于參數(shù)解析與sysfs、livepatch的設置mod_sysfs_setup()
函數(shù)用于在sysfs中創(chuàng)建模塊相應的項is_livepatch_module()
函數(shù)用于檢查模塊是否是熱補丁模塊copy_module_elf()
函數(shù)用于拷貝模塊的elf頭free_copy()
函數(shù)用于釋放最初內核申請的用于保存模塊原文件信息的內存trace_module_load()
函數(shù)用于加載一些和trace相關的內容,便于后期跟蹤調試do_init_module()
函數(shù)用于調用模塊的初始化函數(shù)
static int load_module(struct load_info *info, const char __user *uargs,
int flags)
{
struct module *mod;
long err;
char *after_dashes;
err = module_sig_check(info, flags);
if (err)
goto free_copy;
err = elf_header_check(info);
if (err)
goto free_copy;
/* Figure out module layout, and allocate all the memory. */
mod = layout_and_allocate(info, flags);
if (IS_ERR(mod)) {
err = PTR_ERR(mod);
goto free_copy;
}
audit_log_kern_module(mod- >name);
/* Reserve our place in the list. */
err = add_unformed_module(mod);
if (err)
goto free_module;
#ifdef CONFIG_MODULE_SIG
mod- >sig_ok = info- >sig_ok;
if (!mod- >sig_ok) {
pr_notice_once("%s: module verification failed: signature "
"and/or required key missing - tainting "
"kernel\\n", mod- >name);
add_taint_module(mod, TAINT_UNSIGNED_MODULE, LOCKDEP_STILL_OK);
}
#endif
/* To avoid stressing percpu allocator, do this once we're unique. */
err = percpu_modalloc(mod, info);
if (err)
goto unlink_mod;
/* Now module is in final location, initialize linked lists, etc. */
err = module_unload_init(mod);
if (err)
goto unlink_mod;
init_param_lock(mod);
/* Now we've got everything in the final locations, we can
* find optional sections. */
err = find_module_sections(mod, info);
if (err)
goto free_unload;
err = check_module_license_and_versions(mod);
if (err)
goto free_unload;
/* Set up MODINFO_ATTR fields */
setup_modinfo(mod, info);
/* Fix up syms, so that st_value is a pointer to location. */
err = simplify_symbols(mod, info);
if (err < 0)
goto free_modinfo;
err = apply_relocations(mod, info);
if (err < 0)
goto free_modinfo;
err = post_relocation(mod, info);
if (err < 0)
goto free_modinfo;
flush_module_icache(mod);
/* Now copy in args */
mod- >args = strndup_user(uargs, ~0UL > > 1);
if (IS_ERR(mod- >args)) {
err = PTR_ERR(mod- >args);
goto free_arch_cleanup;
}
dynamic_debug_setup(mod, info- >debug, info- >num_debug);
/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
ftrace_module_init(mod);
/* Finally it's fully formed, ready to start executing. */
err = complete_formation(mod, info);
if (err)
goto ddebug_cleanup;
err = prepare_coming_module(mod);
if (err)
goto bug_cleanup;
/* Module is ready to execute: parsing args may do that. */
after_dashes = parse_args(mod- >name, mod- >args, mod- >kp, mod- >num_kp,
-32768, 32767, mod,
unknown_module_param_cb);
if (IS_ERR(after_dashes)) {
err = PTR_ERR(after_dashes);
goto coming_cleanup;
} else if (after_dashes) {
pr_warn("%s: parameters '%s' after `--' ignored\\n",
mod- >name, after_dashes);
}
/* Link in to sysfs. */
err = mod_sysfs_setup(mod, info, mod- >kp, mod- >num_kp);
if (err < 0)
goto coming_cleanup;
if (is_livepatch_module(mod)) {
err = copy_module_elf(mod, info);
if (err < 0)
goto sysfs_cleanup;
}
/* Get rid of temporary copy. */
free_copy(info);
/* Done! */
trace_module_load(mod);
return do_init_module(mod);
sysfs_cleanup:
mod_sysfs_teardown(mod);
coming_cleanup:
mod- >state = MODULE_STATE_GOING;
destroy_params(mod- >kp, mod- >num_kp);
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_GOING, mod);
klp_module_going(mod);
bug_cleanup:
mod- >state = MODULE_STATE_GOING;
/* module_bug_cleanup needs module_mutex protection */
mutex_lock(&module_mutex);
module_bug_cleanup(mod);
mutex_unlock(&module_mutex);
/* we can't deallocate the module until we clear memory protection */
module_disable_ro(mod);
module_disable_nx(mod);
ddebug_cleanup:
dynamic_debug_remove(mod, info- >debug);
synchronize_sched();
kfree(mod- >args);
free_arch_cleanup:
module_arch_cleanup(mod);
free_modinfo:
free_modinfo(mod);
free_unload:
module_unload_free(mod);
unlink_mod:
mutex_lock(&module_mutex);
/* Unlink carefully: kallsyms could be walking list. */
list_del_rcu(&mod- >list);
mod_tree_remove(mod);
wake_up_all(&module_wq);
/* Wait for RCU-sched synchronizing before releasing mod- >list. */
synchronize_sched();
mutex_unlock(&module_mutex);
free_module:
/*
* Ftrace needs to clean up what it initialized.
* This does nothing if ftrace_module_init() wasn't called,
* but it must be called outside of module_mutex.
*/
ftrace_release_mod(mod);
/* Free lock-classes; relies on the preceding sync_rcu() */
lockdep_free_key_range(