博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
跟踪sys_execve的执行过程
阅读量:2172 次
发布时间:2019-05-01

本文共 3606 字,大约阅读时间需要 12 分钟。

原创作品转载请注明出处 《Linux内核分析》MOOC课程

一、 配置新的MenuOS环境
在终端进入LinuxKernel目录,输入

rm –rf menugit clone https://github.com/mengning/menu.gitmv test_exec.c test.cmake 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_strcutbprm->argc = count(argv, MAX_ARG_STRINGS);//计算参数个数,直到为NULLretval = prepare_binprm(bprm);//把要加载文件的前128 读入bprm->bufretval = copy_strings_kernel(1, &bprm->filename, bprm);//copy第一个参数filenamebprm->exec = bprm->p;//参数的起始地址retval = copy_strings(bprm->envc, envp, bprm);//copy环境变量retval = copy_strings(bprm->argc, argv, bprm);//copy可执行文件所带参数:argv[0]:hello argv[1]:helloretval = 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系统调用的执行过程,具体的流程图如下:
这里写图片描述

你可能感兴趣的文章
用ARIMA模型做需求预测
查看>>
推荐系统
查看>>
TensorFlow-11-策略网络
查看>>
浅谈 GBDT
查看>>
如何选择优化器 optimizer
查看>>
一文了解强化学习
查看>>
CART 分类与回归树
查看>>
seq2seq 的 keras 实现
查看>>
seq2seq 入门
查看>>
什么是 Dropout
查看>>
用 LSTM 做时间序列预测的一个小例子
查看>>
用 LSTM 来做一个分类小问题
查看>>
详解 LSTM
查看>>
按时间轴简述九大卷积神经网络
查看>>
详解循环神经网络(Recurrent Neural Network)
查看>>
为什么要用交叉验证
查看>>
用学习曲线 learning curve 来判别过拟合问题
查看>>
用验证曲线 validation curve 选择超参数
查看>>
用 Grid Search 对 SVM 进行调参
查看>>
用 Pipeline 将训练集参数重复应用到测试集
查看>>