Linux0.11内核源码解析-exec.c

主要实现对二进制可执行文件和shell文件的加载和执行,其中主要的函数是do_execve(),它是系统中断调用int 0x80的功能号__NR_execve()调用,是exec()函数的主要实现以下几点功能:

1.执行对参数和环境参数空间页面的初始化操作,初始化空间页面指针数组,根据执行文件名取执行对象的i节点,计算参数个数和环境变量个数,检查文件类型、执行权限

2.根据执行文件开始部分的头数据结构,对其中信息进行处理,根据被执行文件i节点读取文件头部信息,若是shell以#!开始,则分析shell程序名和其参数;根据幻数和段长度等信息判断是否可执行

3.对当前调用进程进行运行新文件前初始化操作,指向新执行文件的i节点,复位信号处理句柄,根据头结构信息设置局部描述符地址和段长;设置参数和环境参数页面指针;修改进程各执行字段内容

4.替换堆栈上原调用execve()程序的返回地址为新执行程序运行地址,运行新加载的程序

 create_tables函数用于根据给定的当前堆栈指针值p以及参数个数argc和环境变量个数envc,在新的程序堆栈中创建环境和参数变量指针表,并返回此时的堆栈指针值sp

 create_tables

用戶内存中解析环境变量和参数字符串,创建指针表,并将地址放到堆栈上,返回栈指针

/** MAX_ARG_PAGES defines the number of pages allocated for arguments* and envelope for the new program. 32 should suffice, this gives* a maximum env+arg of 128kB !*/
#define MAX_ARG_PAGES 32/** create_tables() parses the env- and arg-strings in new user* memory and creates the pointer tables from them, and puts their* addresses on the "stack", returning the new stack pointer value.*/
static unsigned long * create_tables(char * p,int argc,int envc)
{unsigned long *argv,*envp;unsigned long * sp;//堆栈指针是以4字节为边界寻址sp = (unsigned long *) (0xfffffffc & (unsigned long) p);//sp向下移动,空出环境参数占用空间个数,让环境参数指针envp指向该处sp -= envc+1;envp = sp;//sp向下移动,空出环境参数占用的空间个数,并让环境参数指针envp指向该处sp -= argc+1;argv = sp;//argc、argv、envpput_fs_long((unsigned long)envp,--sp);put_fs_long((unsigned long)argv,--sp);put_fs_long((unsigned long)argc,--sp);//argcwhile (argc-->0) {put_fs_long((unsigned long) p,argv++);while (get_fs_byte(p++)) /* nothing */ ;}//最后放置NULLput_fs_long(0,argv);//envcwhile (envc-->0) {put_fs_long((unsigned long) p,envp++);while (get_fs_byte(p++)) /* nothing */ ;}//最后放置NULLput_fs_long(0,envp);return sp;
}

count

计算参数个数

/** count() counts the number of arguments/envelopes*/
static int count(char ** argv)
{int i=0;char ** tmp;if ((tmp = argv))//判断为NULL就退出while (get_fs_long((unsigned long *) (tmp++)))i++;return i;
}

copy_string

函数从用户内存空间拷贝参数和环境字符串到内核空闲页面内存中,argc

/** 'copy_string()' copies argument/envelope strings from user* memory to free pages in kernel mem. These are in a format ready* to be put directly into the top of new user memory.** Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies* whether the string and the string array are from user or kernel segments:* * from_kmem     argv *        argv ***    0          user space    user space*    1          kernel space  user space*    2          kernel space  kernel space* * We do this by playing games with the fs segment register.  Since it* it is expensive to load a segment register, we try to avoid calling* set_fs() unless we absolutely have to.*/
static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,unsigned long p, int from_kmem)
{char *tmp, *pag=NULL;int len, offset = 0;unsigned long old_fs, new_fs;if (!p)return 0;	/* bullet-proofing */new_fs = get_ds();old_fs = get_fs();if (from_kmem==2)set_fs(new_fs);while (argc-- > 0) {if (from_kmem == 1)set_fs(new_fs);if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))panic("argc is wrong");if (from_kmem == 1)set_fs(old_fs);len=0;		/* remember zero-padding *///计算字符串的长度do {len++;} while (get_fs_byte(tmp++));//字符串长度判断if (p-len < 0) {	/* this shouldn't happen - 128kB */set_fs(old_fs);return 0;}while (len) {--p; --tmp; --len;//首次复制字符串,offset复制为0if (--offset < 0) {//p指针在页内的偏移offset = p % PAGE_SIZE;//恢复fs段寄存器if (from_kmem==2)set_fs(old_fs);//如果pag不为NULL,说明页面在之前的拷贝过程得到分配//pag指针为NULL,说明该页面还没有分配内存空间if (!(pag = (char *) page[p/PAGE_SIZE]) &&!(pag = (char *) (page[p/PAGE_SIZE] =(unsigned long *) get_free_page()))) return 0;if (from_kmem==2)set_fs(new_fs);}*(pag + offset) = get_fs_byte(tmp);}}//还原fsif (from_kmem==2)set_fs(old_fs);return p;
}

修改局部描述符表中的描述符基址和段限长,并将参数和环境页面放置在数据段末端

参数:text_size 执行文件头部中a_text字段给出的代码段长度值,page参数和环境空间页面指针数组

static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
{unsigned long code_limit,data_limit,code_base,data_base;int i;
//根据执行文件头部a_text的值,计算以页面长度为边界代码段限长,并设置数据段长度为64MBcode_limit = text_size+PAGE_SIZE -1;code_limit &= 0xFFFFF000;data_limit = 0x4000000;
//取当前进程中局部描述符代码段描述符中代码段基地址,代码段基址和数据段基址相同code_base = get_base(current->ldt[1]);data_base = code_base;
//重新设置局部表中代码段和数据描述符的基址和段限长set_base(current->ldt[1],code_base);set_limit(current->ldt[1],code_limit);set_base(current->ldt[2],data_base);set_limit(current->ldt[2],data_limit);
/* make sure fs points to the NEW data segment */__asm__("pushl $0x17\n\tpop %%fs"::);data_base += data_limit;for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {data_base -= PAGE_SIZE;if (page[i])put_page(page[i],data_base);}return data_limit;
}

execve系统中断调用函数,加载并执行子进程

函数系统中断调用int 0x80功能号__NR_execve,

参数:eip指向堆栈中调用系统中断的程序代码指针eip,

tmp:_sys_execve时返回地址

filename 被执行程序文件名

argv命令行参数指针数组

envp环境变量指针数组

/** 'do_execve()' executes a new program.*/
int do_execve(unsigned long * eip,long tmp,char * filename,char ** argv, char ** envp)
{struct m_inode * inode;struct buffer_head * bh;struct exec ex;unsigned long page[MAX_ARG_PAGES];int i,argc,envc;int e_uid, e_gid;int retval;int sh_bang = 0;unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;if ((0xffff & eip[1]) != 0x000f)panic("execve called from supervisor mode");for (i=0 ; i<MAX_ARG_PAGES ; i++)	/* clear page-table */page[i]=0;if (!(inode=namei(filename)))		/* get executables inode */return -ENOENT;argc = count(argv);envc = count(envp);restart_interp:if (!S_ISREG(inode->i_mode)) {	/* must be regular file */retval = -EACCES;goto exec_error2;}i = inode->i_mode;e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;if (current->euid == inode->i_uid)i >>= 6;else if (current->egid == inode->i_gid)i >>= 3;if (!(i & 1) &&!((inode->i_mode & 0111) && suser())) {retval = -ENOEXEC;goto exec_error2;}if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {retval = -EACCES;goto exec_error2;}ex = *((struct exec *) bh->b_data);	/* read exec-header */if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {/** This section does the #! interpretation.* Sorta complicated, but hopefully it will work.  -TYT*/char buf[1023], *cp, *interp, *i_name, *i_arg;unsigned long old_fs;strncpy(buf, bh->b_data+2, 1022);brelse(bh);iput(inode);buf[1022] = '\0';if ((cp = strchr(buf, '\n'))) {*cp = '\0';for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);}if (!cp || *cp == '\0') {retval = -ENOEXEC; /* No interpreter name found */goto exec_error1;}interp = i_name = cp;i_arg = 0;for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {if (*cp == '/')i_name = cp+1;}if (*cp) {*cp++ = '\0';i_arg = cp;}/** OK, we've parsed out the interpreter name and* (optional) argument.*/if (sh_bang++ == 0) {p = copy_strings(envc, envp, page, p, 0);p = copy_strings(--argc, argv+1, page, p, 0);}/** Splice in (1) the interpreter's name for argv[0]*           (2) (optional) argument to interpreter*           (3) filename of shell script** This is done in reverse order, because of how the* user environment and arguments are stored.*/p = copy_strings(1, &filename, page, p, 1);argc++;if (i_arg) {p = copy_strings(1, &i_arg, page, p, 2);argc++;}p = copy_strings(1, &i_name, page, p, 2);argc++;if (!p) {retval = -ENOMEM;goto exec_error1;}/** OK, now restart the process with the interpreter's inode.*/old_fs = get_fs();set_fs(get_ds());if (!(inode=namei(interp))) { /* get executables inode */set_fs(old_fs);retval = -ENOENT;goto exec_error1;}set_fs(old_fs);goto restart_interp;}brelse(bh);if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {retval = -ENOEXEC;goto exec_error2;}if (N_TXTOFF(ex) != BLOCK_SIZE) {printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);retval = -ENOEXEC;goto exec_error2;}if (!sh_bang) {p = copy_strings(envc,envp,page,p,0);p = copy_strings(argc,argv,page,p,0);if (!p) {retval = -ENOMEM;goto exec_error2;}}
/* OK, This is the point of no return */if (current->executable)iput(current->executable);current->executable = inode;for (i=0 ; i<32 ; i++)current->sigaction[i].sa_handler = NULL;for (i=0 ; i<NR_OPEN ; i++)if ((current->close_on_exec>>i)&1)sys_close(i);current->close_on_exec = 0;free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));free_page_tables(get_base(current->ldt[2]),get_limit(0x17));if (last_task_used_math == current)last_task_used_math = NULL;current->used_math = 0;p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;p = (unsigned long) create_tables((char *)p,argc,envc);current->brk = ex.a_bss +(current->end_data = ex.a_data +(current->end_code = ex.a_text));current->start_stack = p & 0xfffff000;current->euid = e_uid;current->egid = e_gid;i = ex.a_text+ex.a_data;while (i&0xfff)put_fs_byte(0,(char *) (i++));eip[0] = ex.a_entry;		/* eip, magic happens :-) */eip[3] = p;			/* stack pointer */return 0;
exec_error2:iput(inode);
exec_error1:for (i=0 ; i<MAX_ARG_PAGES ; i++)free_page(page[i]);return(retval);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/127662.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于51单片机的智能指纹考勤系统设计

**单片机设计介绍&#xff0c;1661【毕设课设】基于51单片机的智能指纹考勤系统设计-原理图-PCB-程序-报告 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于51单片机的智能指纹考勤系统是一种利用51单片机作为主控芯片&#x…

Java生成二维码并打印二维码和文字信息

目录 1、生成二维码&#xff0c;并调用画布进行二维码和文字的描绘。 2、主程序&#xff1a;获取打印机&#xff0c;并打印内容 3、打印效果 参考文献&#xff1a; 前期工作是安装好打印机驱动&#xff0c;可连接打印机。 添加三个依赖jar&#xff1a; 具体见文底的参考文献…

k8s 多网卡方案multus

kubernetes 多网卡方案之 Multus_CNI 部署以及基本使用 一、multus cni 出现的背景 在k8s的环境中启动一个容器&#xff0c;默认情况下只存在两个虚拟网络接口&#xff08;loopback 和 eth0&#xff09;&#xff0c; loopback 的流量始终都会在本容器内或本机循环&#xff0c…

有谁知道怎么下载微信视频号视频吗?

抖音视频下载、某站视频下载都很常见&#xff0c;那你知道怎么下载V信视频号视频吗/今天给大家分享两种简单方便的办法&#xff0c;继续往下看吧&#xff01;一、犀牛视频下载机器人犀牛视频下载器可以直接解析并下载视频号短视频。您只需转发视频到机器人即可下载。此方法也是…

掌握口才与演讲技巧,让你职场中脱颖而出

在职场竞争日趋激烈的今天&#xff0c;口才和演讲能力已经成为一个人成功的重要标志之一。掌握了优秀的口才与演讲技巧&#xff0c;不仅可以帮助你在工作中更好地表达自己和传达信息&#xff0c;同时也可以让你在同事和上级心中留下深刻印象&#xff0c;从而在职场中脱颖而出&a…

费用预算管理系统

费用预算管理系统 1. 模块概述 《费用管理》以企业费用管理为核心&#xff0c;围绕费用支出审批流程&#xff0c;从费用发生前的事前申请&#xff0c;报销单据审批、付款单据审批&#xff0c;再到出纳付款、会计记账等所有工作流程都在系统中全员、协同完成&#xff1b;并且能…

PaDiM 无监督异常检测和定位-论文和源码阅读

目录 1. 论文 1.1 检测效果 1.2 框架 1.2.1 特征提取embedding extraction 1.2.2 正样本学习Learning of the normality 1.2.3 计算异常图 inference: computation of the anomaly map 2. 源码 2.1 dataset 2.2 model 2.3 提取特征 2.4 infer 1. 论文 https://arx…

图扑 HT for Web 手机端运维管理系统

随着信息技术的快速发展&#xff0c;网络技术的应用涉及到人们生活的方方面面。其中&#xff0c;手机运维管理系统可提供数字化、智能化的方式&#xff0c;帮助企业和组织管理监控企业的 IT 环境&#xff0c;提高运维效率、降低维护成本、增强安全性、提升服务质量&#xff0c;…

分享一下微信小程序里怎么开店

如何在微信小程序中成功开店&#xff1a;从选品到运营的全方位指南 一、引言 随着微信小程序的日益普及&#xff0c;越来越多的人开始尝试在微信小程序中开设自己的店铺。微信小程序具有便捷、易用、即用即走等特点&#xff0c;使得开店门槛大大降低。本文将详细介绍如何在微…

【计算系统】5分钟了解超算,高性能计算,并行计算,分布式计算,网格计算,集群计算以及云计算的区别

5分钟了解超算&#xff0c;高性能计算&#xff0c;并行计算&#xff0c;分布式计算&#xff0c;网格计算&#xff0c;集群计算以及云计算的区别 1. 超算2. 高性能计算3. 并行计算4. 分布式计算5. 网格计算6. 集群计算7. 云计算小结相关资料 1. 超算 超级计算机&#xff08;Sup…

分享88个工作总结PPT,总有一款适合您

分享88个工作总结PPT&#xff0c;总有一款适合您 88个工作总结PPT下载链接&#xff1a;https://pan.baidu.com/s/1y08X9RMdIOCncbs28aMgDw?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 蓝色水彩风年终总结PPT模板 清新水彩简…

深度学习之基于YoloV5火灾烟雾报警系统(GUI界面)

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、火灾烟雾报警系统四. 总结 一项目简介 YoloV5 是深度学习中用于目标检测的一种算法&#xff0c;可以对输入的图像进行识别&#xff0c;标识出…

windows server 2016-IIS静态服务器-设置详细过程

文章目录 1.打开仪表盘新建角色2.iis功能模块3.启动服务器4.优点 1.打开仪表盘新建角色 2.iis功能模块 能选上的尽量选上&#xff0c;除非知道自己用不上。 然后确认&#xff0c;下一步&#xff0c;安装。 3.启动服务器 搜索IIS&#xff0c;启动IIS管理器。 启动网站。 右…

HHDBCS扩展数据库类型

为应对市面上的数据库种类繁多的问题&#xff0c;HHDBCS设置了扩展数据库功能。 在登陆界面点击“工具”&#xff0c;选择“扩展数据库类型”&#xff1b; 注&#xff1a;HHDBCS支持已kingbase&#xff0c;本文仅用来举例。 填入名称、所需数据库的信息&#xff0c;上传驱动…

【tensorboard打开失败】No dashboards are active for the current data set.

这里我再跟视频学的时候&#xff0c;找了很多的指令&#xff0c;说是对应版本不一样&#xff0c;但是发现用了很多指令都可以弹出来跳转的url&#xff0c;那应该就不是输入指令的问题 直到我想把logs里面的文件删掉重新跑的时候&#xff0c;我突然注意到这里有中文字符&#xf…

Android Icon 添加水印 Python脚本

源代码 # -*- coding: utf-8 -*- from PIL import Image 图片合成def mergePictureLXJ():commonIcon Image.open("icon.png")markIcon Image.open("领现金.png")markLayer Image.new(RGBA, commonIcon.size, (0, 0, 0, 0))markLayer.paste(markIcon, (0…

StoneDB-8.0-V2.1.0 企业版正式发布!免费公测中!

很高兴告诉大家&#xff0c;我们StoneDB-8.0-V2.1.0企业版正式发布了&#xff01;经过一个月的开发&#xff0c;我们的研发团队用极高的效率对2.0新架构版本查漏补缺&#xff0c;完善了最新架构的代码&#xff0c;并对性能、稳定性做出了优化&#xff0c;同时也修复了一些用户们…

C语言到底算高级程序语言还是低级程序语言?

C语言到底算高级程序语言还是低级程序语言&#xff1f; 高级语言 这里的高级都是相对于汇编语言来说的&#xff0c;是指脱离了计算机的硬件系统&#xff0c;可以按照人的思维逻辑进 行编程的语言 低级语言-般都依赖硬件, 基本换个硬件就得重写&#xff0c;很多人说C语言是低…

pytorch笔记 GRUCELL

1 介绍 GRU的一个单元 2 基本使用方法 torch.nn.GRUCell(input_size, hidden_size, biasTrue, deviceNone, dtypeNone) 输入&#xff1a;&#xff08;batch&#xff0c;input_size&#xff09; 输出和隐藏层&#xff1a;&#xff08;batch&#xff0c;hidden_size&#xf…

基于深度学习的人脸专注度检测计算系统 - opencv python cnn 计算机竞赛

文章目录 1 前言2 相关技术2.1CNN简介2.2 人脸识别算法2.3专注检测原理2.4 OpenCV 3 功能介绍3.1人脸录入功能3.2 人脸识别3.3 人脸专注度检测3.4 识别记录 4 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的人脸专注度…