C语言的execve经过库函数,最终也会通过int 0x80中断陷入内核,并通过eax寄存器来传递调用号。
内核会根据系统初始化时注册的中断处理函数来对其进行处理。它的中断处理函数为system_call。这个函数定义在system_call.s中,它会保存一些寄存器的值(对于系统调用来说,保存的主要是参数),然后根据调用号调用syscall_table中相应的表项。syscall_table定义在include/linux/sys.h文件中,它是一个函数指针数组。对于execve来说它找到的表项就是sys_execve。它仍然是定义在system_call.s中的,在这里面它最终又调用了do_execve。
下面我们来具体看一下
94 call _sys_call_table(,%eax,4)
system_call.s:
80 _system_call:
81 cmpl $nr_system_calls-1,%eax
82 ja bad_sys_call
83 push %ds
84 push %es
85 push %fs
86 pushl %edx
87 pushl %ecx # push %ebx,%ecx,%edx as parameters
88 pushl %ebx # to the system call
81 cmpl $nr_system_calls-1,%eax
82 ja bad_sys_call
83 push %ds
84 push %es
85 push %fs
86 pushl %edx
87 pushl %ecx # push %ebx,%ecx,%edx as parameters
88 pushl %ebx # to the system call
89 movl $0x10,%edx # set up ds,es to kernel space
90 mov %dx,%ds
91 mov %dx,%es
90 mov %dx,%ds
91 mov %dx,%es
可以看到每次系统调用都会设置fs指向用户段,这使得内核可以和用户空间拷贝数据
92 movl $0x17,%edx # fs points to local data space
93 mov %dx,%fs
92 movl $0x17,%edx # fs points to local data space
93 mov %dx,%fs
94 call _sys_call_table(,%eax,4)
这里根据调用号会找到sys_execve
_sys_execve:
199 .align 2
200 _sys_execve:
201 lea EIP(%esp),%eax
202 pushl %eax
203 call _do_execve
204 addl $4,%esp
205 ret
201-202行把eip压栈,作为do_execve参数
_sys_execve:
199 .align 2
200 _sys_execve:
201 lea EIP(%esp),%eax
202 pushl %eax
203 call _do_execve
204 addl $4,%esp
205 ret
201-202行把eip压栈,作为do_execve参数
我们分段来看do_execve的过程:
179 /*
180 * 'do_execve()' executes a new program.
181 */
182 int do_execve(unsigned long * eip,long tmp,char * filename,
183 char ** argv, char ** envp)
184 {
185 struct m_inode * inode;
186 struct buffer_head * bh;
187 struct exec ex;
188 unsigned long page[MAX_ARG_PAGES];
189 int i,argc,envc;
190 int e_uid, e_gid;
191 int retval;
1
180 * 'do_execve()' executes a new program.
181 */
182 int do_execve(unsigned long * eip,long tmp,char * filename,
183 char ** argv, char ** envp)
184 {
185 struct m_inode * inode;
186 struct buffer_head * bh;
187 struct exec ex;
188 unsigned long page[MAX_ARG_PAGES];
189 int i,argc,envc;
190 int e_uid, e_gid;
191 int retval;
1