Linux内核架构读书笔记

execve 启动新程序

  1. 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 结束是查找一种适当的二进制格式,具体细节(待补充。。。)

    二进制格式处理程序负责将新的程序数据加载到旧的地址空间中,

    二进制格式处理程序执行步骤如下:

  1.  释放原进程资源
  2.  将应用进程映射到虚拟地址空间
    1. text 段,start_code 和 end_code 指定该段在地址空间驻留区域
    2. 预先初始化的数据位于start_data和end_data之间
    3. heap 用于动态内存分配,亦置于虚拟地址空间中,start_brk和brk 指定其边界
    4. stack 由start_stack 定义,几乎所有体系自动向下增长,PA-Risc是例外,对于栈的反向增长,体系结构的相关部分必须告诉内核,可以通过设置符号STACK_DROWSUP 
    5. 程序的参数与环境也映射到虚拟地址空间中,分别位于arg_start 和arg_end 之间
  3.  设置进程的相关指令和其他特定于体系结构的寄存器,以便调度器选择该进程时候开始执行程序的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成员彼此联系起来

  

原文地址:https://www.cnblogs.com/songbingyu/p/3683038.html