linux-2.6.11-exec

来源:互联网 发布:html input value js 编辑:程序博客网 时间:2024/05/22 05:02

在unistd.h中
asmlinkage int sys_execve(struct pt_regs regs);
进入函数实现,在process.c中

asmlinkage int sys_execve(struct pt_regs regs){    int error;    char * filename;    filename = getname((char __user *) regs.ebx);    error = PTR_ERR(filename);    if (IS_ERR(filename))        goto out;    error = do_execve(filename,            (char __user * __user *) regs.ecx,            (char __user * __user *) regs.edx,            &regs);//核心函数    if (error == 0) {        task_lock(current);        current->ptrace &= ~PT_DTRACE;        task_unlock(current);        /* Make sure we don't return using sysenter.. */        set_thread_flag(TIF_IRET);    }    putname(filename);out:    return error;}

它调用了do_exec

do_execve(filename,(char __user * __user *) regs.ecx,(char __user * __user *) regs.edx,&regs);

一共是四个参数,看一下我们调用的exec族的函数原型

int execl(const char *path, const char *arg, ...)  int execv(const char *path, char *const argv[])  int execle(const char *path, const char *arg, ..., char *const envp[])  int execve(const char *path, char *const argv[], char *const envp[])  int execlp(const char *file, const char *arg, ...)  int execvp(const char *file, char *const argv[]) 

作对比可知,第一个参数都是文件名称,其余参数都是由regs这个结构体代进去的,看一下regs结构体好了

struct pt_regs {    long ebx;//存放文件名称    long ecx;//参数1    long edx;//环境变量    long esi;    long edi;    long ebp;    long eax;    int  xds;    int  xes;    long orig_eax;    long eip;    int  xcs;    long eflags;    long esp;    int  xss;};

这个结构体里存的是寄存器,在ptrace.h中定义
看一下do_execve的函数原型

int do_execve(char * filename,    char __user *__user *argv,    char __user *__user *envp,    struct pt_regs * regs)

在这个函数中定义了一个struct linux_binprm 类型的结构体指针*bprm,这个结构用来保存装载二进制文件时使用的参数。

struct linux_binprm{    char buf[BINPRM_BUF_SIZE];    struct page *page[MAX_ARG_PAGES];    struct mm_struct *mm;//k    unsigned long p; /* current top of mem */    int sh_bang;    struct file * file;    int e_uid, e_gid;    kernel_cap_t cap_inheritable, cap_permitted, cap_effective;    void *security;    int argc, envc;    char * filename;        /* Name of binary as seen by procps */    /* Name of the binary really executed. Most of the time same as filename, but could be different for binfmt_{misc,script} */    unsigned interp_flags;    unsigned interp_data;    unsigned long loader, exec;};

为它申请空间并置0

bprm = kmalloc(sizeof(*bprm), GFP_KERNEL);    if (!bprm)        goto out_ret;    memset(bprm, 0, sizeof(*bprm));

然后调用struct file *open_exec(const char *name)函数,在此函数中调用path_lookup,dentry_open,path_release三个函数以获得与可执行文件相关的目录项对象、文件对象和索引结点对象。

struct file *open_exec(const char *name){    struct nameidata nd;    int err;    struct file *file;    nd.intent.open.flags = FMODE_READ;    /**     * 调用path_lookup,dentry_open,path_release以获得与可执行文件     * 相关的目录项对象、文件对象和索引结点对象。     */    err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd);    file = ERR_PTR(err);    if (!err) {        struct inode *inode = nd.dentry->d_inode;        file = ERR_PTR(-EACCES);        if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&            S_ISREG(inode->i_mode)) {            /**             * 检查执行权限             */            int err = permission(inode, MAY_EXEC, &nd);            if (!err && !(inode->i_mode & 0111))                err = -EACCES;            file = ERR_PTR(err);            if (!err) {                file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);//打开一个目录项                if (!IS_ERR(file)) {                    /**                     * deny_write_access通过检查索引结点的i_writecount字段,                     * 确定可执行文件没有被写入。并把-1存放在这个字段以禁止进一步的写访问                     */                    err = deny_write_access(file);                    if (err) {                        fput(file);                        file = ERR_PTR(err);                    }                }out:                return file;            }        }        path_release(&nd);    }    goto out;}

出来之后经过多项检查,调用sched_exec()确定最小负载CPU以执行新程序,并把当前进程转移过去。
这步完成之后进行对部分参数进行赋值

    bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);    bprm->file = file;    bprm->filename = filename;    bprm->interp = filename;    bprm->mm = mm_alloc();    retval = -ENOMEM;    if (!bprm->mm)        goto out_file;

注:bprm是struct linux_binprm 类型的结构体指针

    /**     * 把路径名,命令行参数,环境串复制到一个或者多个新分配的页框中,     * 最终,它们会被分配给用户态地址空间     */    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;

下面调用了search_binary_handler(bprm,regs);

int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)

在search_binary_handler中定义了一个结构体struct exec * eh,在A.out.h中定义

struct exec{  unsigned long a_info;     /使用宏的N_MAGIC */  unsigned a_text;      /* length of text, in bytes */  unsigned a_data;      /* length of data, in bytes */  unsigned a_bss;       /* 用字节表示文件的未初始化数据区域的长度*/  unsigned a_syms;      /* 文件中符号表数据的长度,以字节为单位*/  unsigned a_entry;     /* start address */  unsigned a_trsize;    /* 文本的重新定位信息的长度,以字节为单位*/  unsigned a_drsize;    /* 数据的重新定位信息的长度,以字节为单位*/};

看一下内核对cpu的操作代码

/** * 所有CPU的运行队列。 */static DEFINE_PER_CPU(struct runqueue, runqueues);#define for_each_domain(cpu, domain) \    for (domain = cpu_rq(cpu)->sd; domain; domain = domain->parent)/** * 该宏产生索引为n的CPU的运行队列的地址。 */#define cpu_rq(cpu)     (&per_cpu(runqueues, (cpu)))/** * 该宏产生本地CPU的运行队列的地址。 */#define this_rq()       (&__get_cpu_var(runqueues))/** * 该宏产生任务所在的运行队列的地址。 */#define task_rq(p)      cpu_rq(task_cpu(p))/** * 该宏产生索引为n的CPU的运行队列的当前任务。 */#define cpu_curr(cpu)       (cpu_rq(cpu)->curr)/*

这里写图片描述
这里写图片描述

原创粉丝点击