execve 启动新程序
- execve 实现
系统相关 系统无关
sys_execve - > do_execve
do_execve 定义
1 * 2 * sys_execve() executes a new program. 3 */ 4 int do_execve(char * filename, 5 char __user *__user *argv, 6 char __user *__user *envp, 7 struct pt_regs * regs)
do_execve 执行流程图
首先打开内核文件,具体可见第八章
bprm_init
mm_alloc 生成新的mm_struct 实例管理进程地址空间
init_new_context 特定于体系,用于初始化该实例
__bprm_mm_init 建立初始的栈
新进程的各个参数会合并到一个struct linux_binprm *bprm;的机构。 prepare_binprm用于提供一些父进程相关的值
prepare_binprm也维护了SUID SGID位的处理
1 /* 2 * Fill the binprm structure from the inode. 3 * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes 4 */ 5 int prepare_binprm(struct linux_binprm *bprm) 6 { 7 int mode; 8 struct inode * inode = bprm->file->f_path.dentry->d_inode; 9 int retval; 10 11 mode = inode->i_mode; 12 if (bprm->file->f_op == NULL) 13 return -EACCES; 14 15 bprm->e_uid = current->euid; 16 bprm->e_gid = current->egid; 17 18 if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { 19 /* Set-uid? */ 20 if (mode & S_ISUID) { 21 current->personality &= ~PER_CLEAR_ON_SETID; 22 bprm->e_uid = inode->i_uid; 23 } 24 25 /* Set-gid? */ 26 /* 27 * If setgid is set but no group execute bit then this 28 * is a candidate for mandatory locking, not a setgid 29 * executable. 30 */ 31 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 32 current->personality &= ~PER_CLEAR_ON_SETID; 33 bprm->e_gid = inode->i_gid; 34 } 35 } 36 37 /* fill in binprm security blob */ 38 retval = security_bprm_set(bprm); 39 if (retval) 40 return retval; 41 42 memset(bprm->buf,0,BINPRM_BUF_SIZE); 43 return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); 44 }
search_binary_handler用于在do_execve 结束是查找一种适当的二进制格式,具体细节(待补充。。。)
二进制格式处理程序负责将新的程序数据加载到旧的地址空间中,
二进制格式处理程序执行步骤如下:
- 释放原进程资源
- 将应用进程映射到虚拟地址空间
- text 段,start_code 和 end_code 指定该段在地址空间驻留区域
- 预先初始化的数据位于start_data和end_data之间
- heap 用于动态内存分配,亦置于虚拟地址空间中,start_brk和brk 指定其边界
- stack 由start_stack 定义,几乎所有体系自动向下增长,PA-Risc是例外,对于栈的反向增长,体系结构的相关部分必须告诉内核,可以通过设置符号STACK_DROWSUP
- 程序的参数与环境也映射到虚拟地址空间中,分别位于arg_start 和arg_end 之间
- 设置进程的相关指令和其他特定于体系结构的寄存器,以便调度器选择该进程时候开始执行程序的main函数
2 解释二进制格式
1 /* 2 * This structure defines the functions that are used to load the binary formats that 3 * linux accepts. 4 */ 5 struct linux_binfmt { 6 struct list_head lh; 7 struct module *module; 8 int (*load_binary)(struct linux_binprm *, struct pt_regs * regs); 9 int (*load_shlib)(struct file *); 10 int (*core_dump)(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); 11 unsigned long min_coredump; /* minimal dump size */ 12 int hasvdso; 13 };
每种二进制格式提供下面三个函数
load_binary加载普通程序
load_shlib用于加载共享库。
coredump error 下输出内存转储
每种二进制格式需要使用register_binfmt向内核注册。该函数的目的是向一个链表增加一个新的二进制格式
该链表表头是fs/exec.c的全局变量formats, linux_binfmt 实例通过其next成员彼此联系起来