unsigned long min_coredump; /* minimal dump size */
};
每一种可执行文件类型被添加进内核时,都通过函数register_binfmt将该类可执行文对应的linux_binfmt结构件注册到内核。
static inline void register_binfmt(struct linux_binfmt *fmt)
{
__register_binfmt(fmt, 0);
}
函数register_binfmt只是__register_binfmt的一个前端,真正完成注册操作的函数是__register_binfmt。可执行文件的注册就是将其对应的linux_binfmt结构链接到全局链表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 程序的运行函数 sys_execve是linux处理程序执行的系统调用,函数接收的参数含义:
filenamei:可执行文件在用户空间路径名的地址;
argv:以空字符结束的指针数组,每个指针指向一个命令行参数;
envp:以空字符结束的指针数组,每个字符串表示一个环境变量;
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;
将可执行文件路径名从用户空间拷到内核空间
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;
当进程刚创建还没用exec运行新程序时,子进程和父进程共享地址空间,函数unshare_files为子进程创建一个新的文件管理结构
retval = unshare_files(&displaced);
if (retval)
goto out_ret;
上面讲述的linux_binfmt结构描述了一种可执行文件格式,结构体linux_binprm描述了一个运行的可执行文件。动态分配一个linux_binprm结构,将用新的可执行文件填充该结构。
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
if (!bprm)
goto out_files;
结构struct cred描述用户id、组id等于安全和权能相关的结构,函数prepare_bprm_creds将为新进程创建一个新的struct cred,以脱离与父进程的共享
retval = prepare_bprm_creds(bprm);
if (retval)
goto out_free;
检测是否是一个安全的可执行文件
retval = check_unsafe_exec(bprm);
if (retval < 0)
goto out_free;
clear_in_exec = retval;
current->in_execve = 1;
打开可执行文件并返回一个文件描述结构指针
file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
goto out_unmark;
在用exec系统调用启动一个新进程时,是调度器跨越CPU移动该进程的一个很好的时机。这时候,该进程尚未执行,因此将其移动到另一个CPU不会带来对CPU高速缓存的负面效应。exec系统调用会调用函数sched_exec挑选当前负荷最少的CPU(而且进程得允许在该CPU上运行)。如果不是当前CPU,那么会使用migration_cpu_stop,向迁移线程发送一个迁移请求。
sched_exec();
bprm->file = file;
bprm->filename = filename;
bprm->interp = filename;
为新进程初始化一些内存管理信息
retval = bprm_mm_init(bprm);
if (retval)
goto out_file;
计算命令行参数个数
bprm->argc = count(argv, MAX_ARG_STRINGS);
if ((retval = bprm->argc) < 0)
goto out;
计算环境变量个数
bprm->envc = count(envp, MAX_ARG_STRINGS);
if ((retval = bprm->envc) < 0)
goto out;
初始化linux_binprm结构的euid和egid字段。用可执行文件的前128字节填充linux_binprm的buf字段,这些字节包含用于识别可执行文件格式的一个魔数和其他信息。
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;
将环境变量拷到进程栈中
retval = copy_strings(bprm->envc, envp, bprm);
if (retval < 0)
goto out;
将命令行参数拷到栈中
retval = copy_strings(bprm->argc, argv, bprm);
if (retval < 0)
goto out;
函数search_binary_handler对可执行文件格式种类链表formats进行扫描,并调用每种可执行文件结构的load_binary方法对可执行文件进行操作,如果成功就停止扫描,表示找到了对应的可执行文件格式。
retval = search_binary_handler(bprm,regs);
if (retval < 0)
goto out;
......
联系客服