技术标签: 两个不同的进程 虚拟地址相同
Linux的进程地址空间[一]
segments
一个进程通常由加载一个elf文件启动,而elf文件是由若干segments组成的,同样的,进程地址空间也由许多不同属性的segments组成,但这与硬件意义上的segmentation机制(参考这篇文章)不同,后者在某些体系结构(比如x86)中起重要作用,充当内存中物理地址连续的独立空间。Linux进程中的segment是虚拟地址空间中用于保存数据的区域,只在虚拟地址上连续。
text段包含了当前运行进程的二进制代码,其起始地址在IA32体系中中通常为0x08048000,在IA64体系中通常为0x0000000000400000(都是虚拟地址哈)。data段存储已初始化的全局变量,bss段存储未初始化的全局变量。从上图可以看出,这3个segments是紧挨者的,因为它们的大小是确定的,不会动态变化。
与之相对应的就是heap段和stack段。heap段存储动态分配的内存中的数据,stack段用于保存局部变量和实现函数/过程调用的上下文,它们的大小都是会在进程运行过程中发生变化的,因此中间留有空隙,heap向上增长,stack向下增长,因为不知道heap和stack哪个会用的多一些,这样设置可以最大限度的利用中间的空隙空间。
还有一个段比较特殊,是mmap()系统调用映射出来的。mmap映射的大小也是不确定的。3GB的虚拟地址空间已经很大了,但heap段, stack段,mmap段在动态增长的过程还是有重叠(碰撞)的可能。为了避免重叠发生,通常将mmap映射段的起始地址选在TASK_SIZE/3(也就是1GB)的位置。如果是64位系统,则虚拟地址空间更加巨大,几乎不可能发生重叠。
如果stack段和mmap段都采用固定的起始地址,这样实现起来简单,而且所有Linux系统都能保持统一,但是真实的世界不是那么简单纯洁的,正邪双方的较量一直存在。对于攻击者来说,如果他知道你的这些segments的起始地址,那么他构建恶意代码(比如通过缓冲区溢出获得栈内存区域的访问权,进而恶意操纵栈的内容)就变得容易了。
一个可以采用的反制措施就是不为这些segments的起点选择固定位置,而是在每次新进程启动时(通过设置PF_RANDOMIZE标志)随机改变这些值的设置。
那这些segments的加载顺序是怎样的呢?以下图为例,首先通过execve()执行elf,则该可执行文件的text段,data段,stack段就建立了,在进程运行过程中,可能需要借助ld.so加载动态链接库,比如最常用的libc,则libc.so的text段,data段也建立了,而后可能通过mmap()的匿名映射来实现与其他进程的共享内存,还有可能通过brk()来扩大heap段的大小。
vm_area_struct
在Linux中,每个segment用一个vm_area_struct(以下简称vma)结构体表示。vma是通过一个双向链表(早期的内核实现是单向链表)串起来的,现存的vma按起始地址以递增次序被归入链表中,每个vma是这个链表里的一个节点。
在用户空间可通过"/proc/PID/maps"接口来查看一个进程的所有vma在虚拟地址空间的分布情况,其内部实现靠的就是对这个链表的遍历。
同时,vma又通过红黑树(red black tree)组织起来,每个vma又是这个红黑树里的一个节点。为什么要同时使用两种数据结构呢?使用链表管理固然简单方便,但是通过查找链表找到与特定地址关联的vma,其时间复杂度是O(N),而现实应用中,在进程地址空间中查找vma又是非常频繁的操作(比如发生page fault的时候)。
使用红黑树的话时间复杂度是O(
现在我们来看一下vm_area_struct结构体在Linux中是如何定义的(这里为了讲解的需要对结构体内元素的分布有所调整,事实上,结构体元素的分布是有讲究的,将相关的元素相邻放置并按cache line对齐,有利于它们在cache中处于同一条cache line上,提高效率):
struct vm_area_struct
{
unsigned long vm_start;
unsigned long vm_end;
struct vm_area_struct *vm_next, *vm_prev;
rb_node_t vm_rb;
unsigned long vm_flags;
struct file * vm_file;
unsigned long vm_pgoff;
struct mm_struct * vm_mm;
...
}
其中,vm_start和vm_end分别是这个vma所指向区域的起始地址和结束地址,虽然vma是虚拟地址空间,但最终毕竟是要映射到物理内存上去的,所以也要求是4KB对齐的。
vm_next是指向链表的下一个vma,vm_rb是作为红黑树的一个节点。
vm_flags描述的是vma的属性,flag可以是VM_READ、VM_WRITE、VM_EXEC、VM_SHARED,分别指定vma的内容是否可以读、写、执行,或者由几个进程共享。前面介绍的页表PTE中也有类似的Read/Write权限限制位,那它和vma中的这些标志位是什么关系呢?
vma由许多的虚拟pages组成,每个虚拟page需要经过page table的转换才能找到对应的物理页面。PTE中的Read/Write位是由软件设置的,设置依据就是这个page所属的vma,因此一个vma设置的VM_READ/VM_WRITE属性会复制到这个vma所含pages的PTE中。
之后,硬件MMU就可以在地址翻译的过程中根据PTE的标志位来检测访问是否合法,这也是为什么PTE是一个软件实现的东西,但又必须按照处理器定义的格式去填充,这可以理解为软硬件之间的一种约定。那可以用软件去检测PTE么?当然可以,但肯定没有用专门的硬件单元来处理更快嘛。
可执行文件和动态链接库的text段和data段是基于elf文件的,mmap对文件的映射也是对应外部存储介质中这个被映射的文件的,这两种情况下,vm_file指向这个被映射的文件,进而可获得该文件的inode信息,而"vm_pgoff"是这个段在该文件内的偏移。
对于text段,一般偏移就是0。对于heap段,stack段以及mmap的匿名映射,没有与之相对应的文件实体,此时"vm_file"就为NULL,"vm_pgoff"的值没有意义。
那一个进程是怎么找到它的这些vma的呢?请看下文分解。
参考:
How The Kernel Manages Your Memory
原创文章,转载请注明出处。
Checking Database Object Sizes andDisk SpaceThe gp_size_* family of views can be usedto determine the disk space usage for a distributed Greenplum Database, schema,table, or index. The following vie
**************************************//index .jsp 默认登录,查看信息页面 %>信息查詢系統 function openwin(id){ window.open("view.jsp?id="+id,"","height=450,width=550,resizable=yes,scrollbars=yes,status=no,toolbar=no
【导语】计算机四级网络工程师是通过学习和训练,掌握网络技术的理论知识和操作技能的网络技术人员。为了让大家掌握相关考点,下面无忧考网为您精心整理了2020年计算机四级网络工程师考试复习要点:标记环网,供大家的查阅学习。如想获取更多计算机四级考试的备考资讯,请关注无忧考网的更新。2020年计算机四级网络工程师考试复习要点:标记环网1、标记的工作过程标记环网又称权标网,这种介质访问使用一个标记沿着环循环...
平时写代码很少用到HTML的特殊字符,最常用的可能是 了,但有时在移动端为了节省时间,可能会用这些字符实现某种特殊效果,现整理如下:使用方法:这些字符属于unicode字符集,所以,你的文档需要声明为UTF-8;编号用在HTML中时,需要在前面加上&#符号;用于CSS文件中,但是需要用反斜杠\转义;用于JavaScript,和CSS用法一样,不过要用\u来转义。需
<br />有人说聪明的程序员用Delphi,我承认我并不聪明,虽然Delphi确实很好用,但实在是受不了Delphi的那个编译器,在编辑器中鼠标光标到处乱跑,除非需要的程序是急用,否则我的第一选择不是Delphi。有人也说真正的程序员用VC,当然,我也不得不承认自己压根儿就不是一个程序员,只是一个喜欢编程又上不了档次的准菜鸟,不过我偶尔也会拿起VC玩玩。<br /> <br />在Delphi中要画一个界面,只需要鼠标一拖一拉就搞定了,而VC呢?让我们来画一个简单的界面吧!界面很简单,一个按钮,一个支持多
crontab设置的定时任务,执行脚本报错命令找不到和乱码,使用crontab时的运行环境已经不是用户环境了,因此原本用户下的一些环境变量的设 置就失效了,因为我的命令path设置到了/etc/profile里了,所以在crontab运行不生效就找不到命令,所以命令要写全路径就可以了,字符集也是一样,写到脚本的中就可以了export LANG=en_US.UTF-8...
http://developer.51cto.com2007-02-03 11:56 刘纳新IT168一、国内银行软件项目外包的几个阶段1、20世纪80年代,手工操作向电算化迈进,基本上自己开发自己实施。2、20世纪90年代,建设城域联网系统,集成商开发实施。3、20世纪90年代末期,建设省域集中的系统,集成商与银行合作开发实施。4、21世纪开始,建设全国集中...
基本技能点1:发送SURFALERT ON到8080,这样就关掉了余额扣费的上网方式,防止因为套餐耗尽后疯狂扣话费。2:用Coins.ph充个15Pisos(也就2元人民币),或则充多点钱都可以。方案一:发送GoSURF15到8080,只要15P就开通了2天有效的100M流量。对于流量用的比较省的人来说最适合。一个月下来只要225Pisos方案二:发送GoSURF299...
我们使用scikit-opt工具箱来实现遗传算法:https://github.com/guofei9987/scikit-opt 下载后,我们只需要其中的ga.py文件首先,定义一个目标函数def demo_func2(p): x, y, z = p return -(x ** 2 + y ** 2 + z ** 2)我们想用遗传算法找出目标函数的最大值,这样做: func是你
今天读开源代码,发现下面一段代码,弄得我一头雾水:class XXX{... ...public: class QtDoublePropertyManager *doubleManager; //前面需要加上关键字 class 吗? class QtStringPropertyManager *stringManager; //前面需要加上关键字 class 吗?... ...
一、通过配置实现1、编写Java类文件,如下两个Java类文件。import java.util.Date;public class QuartzJob { public void work() { System.out.println("QuartzJob is time to run :" + new Date().toString()); }}impor...
用VMwareware虚拟机安装的Red HatEnterprise Linux系统剩余空间不足,造成软件无法正常安装。如果重新装一遍系统就需要重新配置好开发环境和软件的安装配置。通过上网搜集的资料,结合自己的实践,总结了如下扩大硬盘空间的详细步骤,希望对大家有帮助。(1)打开VMware,选择Edit Virtual mache settings,Utilities下拉框...