unsigned long min_coredump; /* minimal dump size */ }; 每一種可執(zhí)行文件類型被添加進內(nèi)核時,都通過函數(shù)register_binfmt將該類可執(zhí)行文對應(yīng)的linux_binfmt結(jié)構(gòu)件注冊到內(nèi)核。 static inline void register_binfmt(struct linux_binfmt *fmt) { __register_binfmt(fmt, 0); } 函數(shù)register_binfmt只是__register_binfmt的一個前端,真正完成注冊操作的函數(shù)是__register_binfmt??蓤?zhí)行文件的注冊就是將其對應(yīng)的linux_binfmt結(jié)構(gòu)鏈接到全局鏈表formats中。 void __register_binfmt(struct linux_binfmt * fmt, int insert) { BUG_ON(!fmt); write_lock(&binfmt_lock); insert ? list_add(&fmt->lh, &formats) : list_add_tail(&fmt->lh, &formats); write_unlock(&binfmt_lock); } 2 程序的運行函數(shù) sys_execve是linux處理程序執(zhí)行的系統(tǒng)調(diào)用,函數(shù)接收的參數(shù)含義: filenamei:可執(zhí)行文件在用戶空間路徑名的地址; argv:以空字符結(jié)束的指針數(shù)組,每個指針指向一個命令行參數(shù); envp:以空字符結(jié)束的指針數(shù)組,每個字符串表示一個環(huán)境變量; regs:指向通用寄存器組的指針。 asmlinkage int sys_execve(const char __user *filenamei,const char __user *const __user *argv,const char __user *const __user *envp, struct pt_regs *regs) { int error; char * filename; 將可執(zhí)行文件路徑名從用戶空間拷到內(nèi)核空間 filename = getname(filenamei); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; error = do_execve(filename, argv, envp, regs); putname(filename); out: return error; } 【sys_execve--->do_execve--->do_execve_common】 static int do_execve_common(const char *filename, struct user_arg_ptr argv, struct user_arg_ptr envp,struct pt_regs *regs) { struct linux_binprm *bprm; struct file *file; struct files_struct *displaced; bool clear_in_exec; int retval; const struct cred *cred = current_cred(); ...... current->flags &= ~PF_NPROC_EXCEEDED; 當(dāng)進程剛創(chuàng)建還沒用exec運行新程序時,子進程和父進程共享地址空間,函數(shù)unshare_files為子進程創(chuàng)建一個新的文件管理結(jié)構(gòu) retval = unshare_files(&displaced); if (retval) goto out_ret; 上面講述的linux_binfmt結(jié)構(gòu)描述了一種可執(zhí)行文件格式,結(jié)構(gòu)體linux_binprm描述了一個運行的可執(zhí)行文件。動態(tài)分配一個linux_binprm結(jié)構(gòu),將用新的可執(zhí)行文件填充該結(jié)構(gòu)。 bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); if (!bprm) goto out_files; 結(jié)構(gòu)struct cred描述用戶id、組id等于安全和權(quán)能相關(guān)的結(jié)構(gòu),函數(shù)prepare_bprm_creds將為新進程創(chuàng)建一個新的struct cred,以脫離與父進程的共享 retval = prepare_bprm_creds(bprm); if (retval) goto out_free; 檢測是否是一個安全的可執(zhí)行文件 retval = check_unsafe_exec(bprm); if (retval < 0) goto out_free; clear_in_exec = retval; current->in_execve = 1; 打開可執(zhí)行文件并返回一個文件描述結(jié)構(gòu)指針 file = open_exec(filename); retval = PTR_ERR(file); if (IS_ERR(file)) goto out_unmark; 在用exec系統(tǒng)調(diào)用啟動一個新進程時,是調(diào)度器跨越CPU移動該進程的一個很好的時機。這時候,該進程尚未執(zhí)行,因此將其移動到另一個CPU不會帶來對CPU高速緩存的負面效應(yīng)。exec系統(tǒng)調(diào)用會調(diào)用函數(shù)sched_exec挑選當(dāng)前負荷最少的CPU(而且進程得允許在該CPU上運行)。如果不是當(dāng)前CPU,那么會使用migration_cpu_stop,向遷移線程發(fā)送一個遷移請求。 sched_exec(); bprm->file = file; bprm->filename = filename; bprm->interp = filename; 為新進程初始化一些內(nèi)存管理信息 retval = bprm_mm_init(bprm); if (retval) goto out_file; 計算命令行參數(shù)個數(shù) bprm->argc = count(argv, MAX_ARG_STRINGS); if ((retval = bprm->argc) < 0) goto out; 計算環(huán)境變量個數(shù) bprm->envc = count(envp, MAX_ARG_STRINGS); if ((retval = bprm->envc) < 0) goto out; 初始化linux_binprm結(jié)構(gòu)的euid和egid字段。用可執(zhí)行文件的前128字節(jié)填充linux_binprm的buf字段,這些字節(jié)包含用于識別可執(zhí)行文件格式的一個魔數(shù)和其他信息。 retval = prepare_binprm(bprm); if (retval < 0) goto out; 將文件路徑名拷到新進程棧中 retval = copy_strings_kernel(1, &bprm->filename, bprm); if (retval < 0) goto out; bprm->exec = bprm->p; 將環(huán)境變量拷到進程棧中 retval = copy_strings(bprm->envc, envp, bprm); if (retval < 0) goto out; 將命令行參數(shù)拷到棧中 retval = copy_strings(bprm->argc, argv, bprm); if (retval < 0) goto out; 函數(shù)search_binary_handler對可執(zhí)行文件格式種類鏈表formats進行掃描,并調(diào)用每種可執(zhí)行文件結(jié)構(gòu)的load_binary方法對可執(zhí)行文件進行操作,如果成功就停止掃描,表示找到了對應(yīng)的可執(zhí)行文件格式。 retval = search_binary_handler(bprm,regs); if (retval < 0) goto out; ...... |
|