内存虚拟化是一个很大的话题,最近安全部门发现了一个qemu内存虚拟化的安全漏洞,反馈给云平台让解决,感觉很棘手,引起了我对内存虚拟化的思考,想到什么问题就把思考记录下来。
x86虚拟内存
问题是由学习qemu MemoryRegion想到的,文档memory.rst中有一句话“memory banks used when the guest address space is smaller than the amount of RAM addressed”,说是alias类型MemoryRegion适用于这种场景,大概意思就是qemu给guest提供的物理内存超过了guest的address space,这时就得用alias类型的MemoryRegion了,那这儿的memory banks是什么意思,物理内存条有rank/bank,这儿的bank应当理解成岸,类似于一个岸把湖分成两半,和真正的内存条中的rank/bank没关系。qemu中有below_4g_mem_size和above_4g_mem_size两个MemoryRegion Alias,我觉得这个命名不好,如果加上userspce和kernelspace就好理解了,进程的虚拟地址空间分为用户空间和内核空间,两者执行权限不一样。所有进程内核空间都一样,只是用户空间不一样,这样所有进程就可以共享内核,所以需要在4G空间有一条线分成两部分。每个进程有自己的页目录,其中page table中关于内核部分指向相同,借用网上的这张图说明一下,假设CPU是32位,内核空间1G,用户态空间3G。
再想想虚拟地址空间是如果生成的,gcc编译源代码生成elf格式, linux内核load可执行程序elf格式文件生成虚拟地址空间,虚拟地址空间由段和页构成,段有code,data,heap和stack等, stack是固定大小,linux中的段都指向0,主要是page发挥作用。执行时大概是这样IP指令寄存器告诉MMU要加载的指令,如果page fault, 增加page然后建立映射关系, load指令到内存,其它load指令告诉MMU,要把数据放到内存中,不知道还区分数据总线和地址总线不,课本中学过,程序执行用的都是虚拟地址,反汇编可以看到虚拟地址。
虚拟地址空间设计成这样是因为内核不能发生pagefault,如果内核处理page