跟踪sys_execve的执行过程

郑德伦 原创作品转载请注明出处 《Linux内核分析》MOOC课程
http://mooc.study.163.com/course/USTC-1000029000
一、 配置新的MenuOS环境
在终端进入LinuxKernel目录,输入

rm –rf menu
git clone https://github.com/mengning/menu.git
mv test_exec.c test.c
make rootfs

完成新的MenuOS的配置。在此版本的MenuOS中,加入了exec功能。也就是执行execlp库函数,来创建一个新的进程hello。
二、 追踪sys_execve的执行过程
打开终端,进入LinuxKernel目录输入
qemu –kernel linux-3.18.6/arch/x86/boot/bzImage –initrd rootfs.img –S –s
然后打开另一个终端输入

gdb
(gdb)file linux-3.18.6/vmlinux
(gdb)target remote:1234
(gdb)c
(gdb)b sys_execve
(gdb)b load_elf_binary
(gdb)b start_thread
(gdb)b do_execve
(gdb)c

我们开始跟踪执行过程,在qemu中输入exec,首先进入断点是sys_execve,在在中端处理程序中,调用了do_execve(),其中getname从用户空间获取filename(也就是hello)的路径,到内核中。

这里写图片描述
进入do_execve函数体内发现,实际工作是完成argv envp赋值,然后调用do_execve_common
这里写图片描述
我们进入do_execve_common函数体内
这里写图片描述
我们看下do_execve_common的源代码,do_execve_common完成了一个linux_binprm的结构体 bprm的初始化工作:

retval = bprm_mm_init(bprm);初始化了mm_strcut
bprm->argc = count(argv, MAX_ARG_STRINGS);//计算参数个数,直到为NULL
retval = prepare_binprm(bprm);//把要加载文件的前128 读入bprm->buf
retval = copy_strings_kernel(1, &bprm->filename, bprm);//copy第一个参数filename
bprm->exec = bprm->p;//参数的起始地址
retval = copy_strings(bprm->envc, envp, bprm);//copy环境变量
retval = copy_strings(bprm->argc, argv, bprm);//copy可执行文件所带参数:argv[0]:hello argv[1]:hello
retval = exec_binprm(bprm);//执行bprm
int do_execve_common(struct filename *filename,
                struct user_arg_ptr argv,
                struct user_arg_ptr envp)
{
    struct linux_binprm *bprm;
    struct file *file;
    struct files_struct *displaced;
    int retval;

    /**省略中间一部分***/
    bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
    if (!bprm)
        goto out_files;

    retval = prepare_bprm_creds(bprm);
    if (retval)
        goto out_free;

    check_unsafe_exec(bprm);
    current->in_execve = 1;

    file = do_open_exec(filename);
    retval = PTR_ERR(file);
    if (IS_ERR(file))
        goto out_unmark;

    sched_exec();

    bprm->file = file;
    bprm->filename = bprm->interp = filename->name;

    retval = bprm_mm_init(bprm);
    if (retval)
        goto out_unmark;

    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;

    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;

    retval = exec_binprm(bprm);
    if (retval < 0)
        goto out;

    /***省略中间一部分代码****/
    return retval;
}

然后我们跟踪到exec_binprm,查看函数代码,这段代码将父进程的pid保存,获取新的pid,然后执行search_binary_hander(bprm),用来遍历format链表,找到合适的处理hello的方式。

static int exec_binprm(struct linux_binprm *bprm)
{
    pid_t old_pid, old_vpid;
    int ret;

    /* Need to fetch pid before load_binary changes it */
    old_pid = current->pid;
    rcu_read_lock();
    old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
    rcu_read_unlock();

    ret = search_binary_handler(bprm);
    if (ret >= 0) {
        audit_bprm(bprm);
        trace_sched_process_exec(current, old_pid, bprm);
        ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
        proc_exec_connector(current);
    }

    return ret;
}

我们继续continue 调试,达到断点search_bintary_handler
这里写图片描述
在这里面有个结构体linux_binfmt *fmt;

static struct linux_binfmt elf_format = {

    .module         = THIS_MODULE,
    .load_binary    = load_elf_binary,
    .load_shlib     = load_elf_library,
    .core_dump      = elf_core_dump,
    .min_coredump   = ELF_EXEC_PAGESIZE,
};

里面的.load_binary字段初始化为load_elf_binary由此可见load_binary应该是一个函数指针。
我们继续跟踪到达load_elf_binary,这个函数完成的二进制文件的装载和启动,其中在函数的末尾有start_thread(regs, elf_entry, bprm->p);是二进制的启动代码,我们继续跟踪到达start_thread

这里写图片描述
start_thread函数完成pt_reg结构的转换,从当前进程转换到新进程,完成进程的切换,从而开始执行execve的进程。
三、 总结
通过上面的调试过程,我们已经比较清楚的了解到一个sys_execve系统调用的执行过程,具体的流程图如下:
这里写图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章