分享

网易博客欢迎您

 老匹夫 2014-09-12

unsigned long min_coredump;     /* minimal dump size */

};

每一种可执行文件类型被添加进内核时,都通过函数register_binfmt将该类可执行文对应的linux_binfmt结构件注册到内核。

static inline void register_binfmt(struct linux_binfmt *fmt)

{

__register_binfmt(fmt, 0);

}

函数register_binfmt只是__register_binfmt的一个前端,真正完成注册操作的函数是__register_binfmt。可执行文件的注册就是将其对应的linux_binfmt结构链接到全局链表formats中。

void __register_binfmt(struct linux_binfmt * fmt, int insert)

{

BUG_ON(!fmt);

write_lock(&binfmt_lock);

insert ? list_add(&fmt->lh, &formats) :

list_add_tail(&fmt->lh, &formats);

write_unlock(&binfmt_lock);

}

2 程序的运行

函数 sys_execve是linux处理程序执行的系统调用,函数接收的参数含义:

filenamei:可执行文件在用户空间路径名的地址;

argv:以空字符结束的指针数组,每个指针指向一个命令行参数;

envp:以空字符结束的指针数组,每个字符串表示一个环境变量;

regs:指向通用寄存器组的指针。

asmlinkage int sys_execve(const char __user *filenamei,const char __user *const __user *argv,const char __user *const __user *envp, struct pt_regs *regs)

{

int error;

char * filename;

将可执行文件路径名从用户空间拷到内核空间

filename = getname(filenamei);

error = PTR_ERR(filename);

if (IS_ERR(filename))

goto out;

error = do_execve(filename, argv, envp, regs);

putname(filename);

out:

return error;

}

【sys_execve--->do_execve--->do_execve_common】

static int do_execve_common(const char *filename, struct user_arg_ptr argv,

struct user_arg_ptr envp,struct pt_regs *regs)

{

struct linux_binprm *bprm;

struct file *file;

struct files_struct *displaced;

bool clear_in_exec;

int retval;

const struct cred *cred = current_cred();

......

current->flags &= ~PF_NPROC_EXCEEDED;

当进程刚创建还没用exec运行新程序时,子进程和父进程共享地址空间,函数unshare_files为子进程创建一个新的文件管理结构

retval = unshare_files(&displaced);

if (retval)

goto out_ret;

上面讲述的linux_binfmt结构描述了一种可执行文件格式,结构体linux_binprm描述了一个运行的可执行文件。动态分配一个linux_binprm结构,将用新的可执行文件填充该结构。

bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);

if (!bprm)

goto out_files;

结构struct cred描述用户id、组id等于安全和权能相关的结构,函数prepare_bprm_creds将为新进程创建一个新的struct cred,以脱离与父进程的共享

retval = prepare_bprm_creds(bprm);

if (retval)

goto out_free;

检测是否是一个安全的可执行文件

retval = check_unsafe_exec(bprm);

if (retval < 0)

goto out_free;

clear_in_exec = retval;

current->in_execve = 1;

打开可执行文件并返回一个文件描述结构指针

file = open_exec(filename);

retval = PTR_ERR(file);

if (IS_ERR(file))

goto out_unmark;

在用exec系统调用启动一个新进程时,是调度器跨越CPU移动该进程的一个很好的时机。这时候,该进程尚未执行,因此将其移动到另一个CPU不会带来对CPU高速缓存的负面效应。exec系统调用会调用函数sched_exec挑选当前负荷最少的CPU(而且进程得允许在该CPU上运行)。如果不是当前CPU,那么会使用migration_cpu_stop,向迁移线程发送一个迁移请求。

sched_exec();

bprm->file = file;

bprm->filename = filename;

bprm->interp = filename;

为新进程初始化一些内存管理信息

retval = bprm_mm_init(bprm);

if (retval)

goto out_file;

计算命令行参数个数

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;

初始化linux_binprm结构的euid和egid字段。用可执行文件的前128字节填充linux_binprm的buf字段,这些字节包含用于识别可执行文件格式的一个魔数和其他信息。

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;

函数search_binary_handler对可执行文件格式种类链表formats进行扫描,并调用每种可执行文件结构的load_binary方法对可执行文件进行操作,如果成功就停止扫描,表示找到了对应的可执行文件格式。

retval = search_binary_handler(bprm,regs);

if (retval < 0)

goto out;

......

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多