linux虚拟空间划分

一般操作系统为了提供远超实际物理内存的空间,提供了虚拟空间概念。即虽然实际系统中的物理内存比较小,但是通过将整个空间进行一个虚拟抽象能够为每个进程提供远远超过实际物理内存的空间,这样就给每个进程提供了一个假象 :“每个进程都拥有整个系统的空间”。虚拟空间的好处就不必多说,一般操作系统的课程上都是着重讲解。linux内核中将整个虚拟空间划分为内核空间和用户空间,每个进程的用户空间是相互隔离,而内核空间是每个进程都相互共享。X86 64系统的地址空间划分在Documentation\x86\x86_64\mm.rst文档中有说明,x86 64位空间划分有两种形式如下:

两种形式主要是因为page table 分别为4级 或 5级数划分不同,x86 64系统下默认方式为 4级划分方式。用户空间和内核空间为分开管理,在两个空间之间有一段常常的hole 空间用于预留。

内核空间划分

linux将内核空间按照不同的使用用途,分别划分成不同段进行管理,Documentation\x86\x86_64\mm.rst文档中详细描述了内核空间,以 4 level page table为例:

  • 0xffff800000000000 ~0xffff87ffffffffff :即可以作为guard hole 以防止内核空间越界,又可以作为 hypervisor 使用
  • 0x0xfff880000000000 ~ 0xffff887fffffffff:local descriptor table(LDT)局部描述表存放空间
  • 0xffff888000000000 ~0xffffc87fffffffff:物理内存直接映射区,大小为64TB 即物理内存小于64TB的都是直接映射到该区域,由于目前暂时还很少有大于64TB的物理内存,故在64位系统下暂时没有high zone的划分。
  • 0xffffc88000000000 ~0xffffc8ffffffffff:空洞
  • 0xffffc90000000000 ~0xffffe8ffffffffff :vmalloc或者ioremap 空间
  • 0xffffe90000000000 ~0xffffe9ffffffffff: 空洞
  • 0xffffea0000000000 ~0xffffeaffffffffff: vmemp存放地址。
  • 0xffffeb0000000000 ~0xffffebffffffffff: 空洞
  • 0xffffec0000000000 ~ 0xfffffbffffffffff: KASAN使用
  • 0xfffffc0000000000 ~ 0xfffffdffffffffff:空洞
  • 0xfffffe0000000000 ~ 0xfffffe7fffffffff :cpu_entry_area 映射,关于cpu_entry_area解释,查到了下面一个解释,(水平有限还是没有理解,做个记录linux kernel - What is cpu_entry_area? - Unix & Linux Stack Exchange):

cpu_entry_area contains all the data and code needed to allow the CPU to hand control over to the kernel. When KPTI is enabled, only that part of the kernel is mapped when user-space is running. You can see its definition in arch/x86/include/asm/cpu_entry_area.h: it contains

  • the GDT;
  • the entry stack;
  • the TSS;
  • a set of trampolines;
  • the exception stacks;
  • debug stores and buffers.
  • 0xfffffe8000000000 ~ 0xfffffeffffffffff 空洞
  • 0xffffff0000000000 ~ 0xffffff7fffffffff :%esp fixup stacks 。
  • 0xffffff8000000000 ~0xffffffeeffffffff:空洞
  • 0xffffffef00000000 ~0x fffffffeffffffff:EFI 映射区域
  • ... ...

64位系统内,划分太多不再一一详细描述,上述每划分一段意味着都需要单独做空间分配等一系列管理动作,所以内核空间被切分成一段段进行管理。以后再详细描述各个内核空间管理。

用户空间划分

linux 的用户空间划分主要有以下几个部分:

地址从0x00007fffffffffff ~0x0000000000000000从高地址向地址依次划分如下:

  • stack:栈 空间 从高地址向地地址增长
  • mapping are: map 映射区域,主要是调用系统调用maping
  • heap:堆划分区域,主要调用malloc 申请的区域
  • BSS: 程序BSS 段
  • Data: 程序数据段
  • CODE:程序代码段

用户空间中 由程序中经常分配和使用的区域主要是mapping映射区和 heap 堆区域。 stack 区域在程序运行由系统加载和使用。BSS,Data 以及代码段大小由程序编译后都已经固定,在程序运行前由加载器加载到各自区域。

内核和用户空间的各自管理方法不同,需要分别看待,再分析内核代码之前需要首先树立这样一个观念 便于从整理理解内核对整个空间管理。

用户空间分布关键宏定义

在内核代码中有几个关键通用宏用于定义各个空间分布大小

用户空间可以访问的最高地址宏

用户空间可以访问的最高地址宏TASK_SIZE_MAX

#define TASK_SIZE_MAX    ((1UL << __VIRTUAL_MASK_SHIFT) - PAGE_SIZE)

可以看到可以访问的最高用户空间地址为 最高虚拟地址(1<<__VIRTUAL_MASK_SHIFT) 减去一个page,   该预留的page 主要是为了防止内核和用户空间相互溢出而预留的一个保护页,__VIRTUAL_MASK_SHIF为虚拟地址的最高位,与具体的cpu框架有关系, 其中以amd 64为用例,64位系统虚拟默认最高位为为47(arch\x86\include\asm\page_64_types.h)

#ifdef CONFIG_X86_5LEVEL
#define __VIRTUAL_MASK_SHIFT    (pgtable_l5_enabled() ? 56 : 47)
#else
#define __VIRTUAL_MASK_SHIFT    47
#endif

最高为虚拟地址为47位 (此时是page table是按照4级查找),则最高虚拟地址用户空间为0x00007FFFFFFFF000。 如果cpu 是按照5级查找page table,则虚拟地址最高位可以是56.

用户虚拟空间大小

用户虚拟空间大小宏位TASK_SIZE

#define TASK_SIZE        (test_thread_flag(TIF_ADDR32) ? \IA32_PAGE_OFFSET : TASK_SIZE_MAX)

TIF_ADDR32 表示cpu是否是32位。 64位cpu 架构下TASK_SIZE大小为TASK_SIZE_MAX

栈空间分布

栈空间分布使用STACK_TOP STACK_TOP_MAX

其中STACK_TOP_MAX 指定的是栈最高地址,栈的最高位置即是用户空间虚拟地址的最高位置

#define STACK_TOP_MAX        TASK_SIZE_MAX

STACK_TOP 栈顶top位置

#define STACK_TOP        TASK_SIZE_LOW

由于栈顶top位置与具体使用情况有关,此时表明的只是一个初始值,一般与TASK_SIZE_LOW:

#define TASK_SIZE_LOW        (test_thread_flag(TIF_ADDR32) ? \IA32_PAGE_OFFSET : DEFAULT_MAP_WINDOW)

64为系统下  TASK_SIZE_LOW 等于DEFAULT_MAP_WINDOW

#define DEFAULT_MAP_WINDOW   ((1UL << 47) - PAGE_SIZE)

mmap映射区域

mmap映射区域宏为

#define __TASK_UNMAPPED_BASE(task_size)  (PAGE_ALIGN(task_size / 3))
#define TASK_UNMAPPED_BASE      __TASK_UNMAPPED_BASE(TASK_SIZE_LOW)

默认mmap映射区域起始地址是以 (TASK_SIZE/3)位置开始

堆区域

堆区域的起始地址与程序大小有关,不是固定的,起始与程序数据段结束位置 ,堆结束地址为mmap映射的起始位置TASK_UNMAPPED_BASE

地址空间随机化Address Space Layout Randomization(ASLR)

由上述地址空间分布可知,在不同的程序之前,其实每个程序大部分地址空间都是固定的除了堆和栈与程序有关,这样就会造成一个很严重的安全问题。一个黑客很容易从固定空间映射中猜出每个程序的空间分布进而很容易获取到程序充的关键信息。为了增加整个系统安全行,内核开发出了地址空间分布随机化(ASLR)功能,即每台机器的空间分布并不完全一样,从而增加系统安全性。

Address space layout randomization is based upon the low chance of an attacker guessing the locations of randomly placed areas. Security is increased by increasing the search space. Thus, address space randomization is more effective when more entropy is present in the random offsets. Entropy is increased by either raising the amount of virtual memory area space over which the randomization occurs or reducing the period over which the randomization occurs. The period is typically implemented as small as possible, so most systems must increase VMA space randomization.

linux 内核增加了一个系统配置文件/proc/sys/kernel/randomize_va_space, 来控制是否开启ASLR功能:

Address Space Layout Randomization (ASLR) can help defeat certain types of buffer overflow attacks. ASLR can locate the base, libraries, heap, and stack at random positions in a process's address space, which makes it difficult for an attacking program to predict the memory address of the next instruction. ASLR is built into the Linux kernel and is controlled by the parameter /proc/sys/kernel/randomize_va_space. The randomize_va_space parameter can take the following values

其中 randomize_va_space可是设置为以下:

  • 0: 关闭 ASLR功能,采用固定映射空间分布
  • 1: 开启ASLR功能,将stack(栈) 共享动态库(virtual synmaic shared object)以及共享内存(share memory regions)随机化。其中 程序数据段地址位于 程序可执行代码段之后。
  • 2:可以称为完全随机化,将stack(栈) 共享动态库(virtual synmaic shared object)、共享内存(share memory regions)以及程序数据段随机化。

一般默认randomize_va_space值为2, 可以通过修改randomize_va_space 值改变地址空间随机化策略:

# echo 1 > /proc/sys/kernel/randomize_va_space

地址随机化功能自内核2。6版本中引入。随机化功能开启后,用户可的mmap空间起始地址也将会随机化,故每台机器的mmap空间起始地址并不相同 。

With these patches applied, each process's stack will begin at a random location, and the beginning of the memory area used for mmap()

参考资料

Linux mem 2.2 内核地址空间布局详解_pwl999的博客-CSDN博客

Address space randomization in 2.6 [LWN.net]

https://en.wikipedia.org/wiki/Address_space_layout_randomization

https://docs.oracle.com/cd/E37670_01/E36387/html/ol_aslr_sec.html

linux内核那些事之虚拟空间划分相关推荐

  1. linux内核那些事之buddy(anti-fragment机制)(4)

    程序运行过程中,有些内存是短暂的驻留 用完一段时间之后就可以将内存释放以供后面再次使用,但是有些内存一旦申请之后,会长期使用而得不到释放.长久运行有可能造成碎片.以<professional l ...

  2. linux内核那些事之mmap_region流程梳理

    承接<linux内核那些事之mmap>,mmap_region()是申请一个用户进程虚拟空间 并根据匿名映射或者文件映射做出相应动作,是实现mmap关键函数,趁这几天有空闲时间 整理下mm ...

  3. linux内核那些事之buddy

    buddy算法是内核中比较古老的一个模块,很好的解决了相邻物理内存碎片的问题即"内碎片问题",同时有兼顾内存申请和释放效率问题,内核从引入该算法之后一直都能够在各种设备上完好运行, ...

  4. linux内核那些事之pg_data_t、zone结构初始化

    free_area_init 继续接着<linux内核那些事之ZONE>,分析内核物理内存初始化过程,zone_sizes_init()在开始阶段主要负责对各个类型zone 大小进行计算, ...

  5. linux内核那些事之Sparse vmemmap

    <inux内核那些事之物理内存模型之SPARCE(3)>中指出在传统的sparse 内存模型中,每个mem_section都有一个属于自己的section_mem_map,如下图所示: 而 ...

  6. linux内核那些事之buddy(慢速申请内存__alloc_pages_slowpath)(5)

    内核提供__alloc_pages_nodemask接口申请物理内存主要分为两个部分:快速申请物理内存get_page_from_freelist(linux内核那些事之buddy(快速分配get_p ...

  7. linux内核那些事之buddy(anti-fragment机制-steal page)(5)

    继<linux内核那些事之buddy(anti-fragment机制)(4)>,在同一个zone内指定的migrate type中没有足够内存,会启动fallback机制,从fallbac ...

  8. linux内核那些事之用户空间管理

    内核主要数据结构 linux内核将用户空间抽象成struct vm_area_struct进行管理,每申请以个用户空间在内核中都会抽象成对应的vm_are_struct进行管理,同时为了区别不同进程的 ...

  9. linux内核那些事之struct page

    struct page page(页)是linux内核管理物理内存的最小单位,内核将整个物理内存按照页对齐方式划分成千上万个页进行管理,内核为了管理这些页将每个页抽象成struct page结构管理每 ...

最新文章

  1. windows和linux添加引导文件,Linux与Windows 10用grub引导教程-Go语言中文社区
  2. 小程序 reduce_使用reduce制作的10个更多实用程序功能
  3. arm linux 显示屏 10钟黑屏
  4. 惨绝人寰的日期函数,用的方便
  5. springsecurity不拦截某个接口_SpringSecurity 默认表单登录页展示流程源码
  6. 写一个判断素数的函数,在主函数输入一个整数,输出是否是素数的消息。
  7. vue mxgraph渲染xml页面_Vue的两个版本
  8. html代码如何查看视频,Web前端
  9. centos 网卡状态
  10. 为什么有的锂电保护板需要激活之锂电池保护板怎么激活
  11. mysql自学完整_MySQL自学篇(三)
  12. 华为novia3i鸿蒙,华为nova3i一马当先:值得年轻人购买的智能手机推荐
  13. 微信40125错误的坑
  14. 计算机图形化编程命令,第三课图形化编程教学设计
  15. c语言随机数字密码生成器,在线随机数生成器,批量随机数生成工具 - dute.org
  16. springboot 成员变量_SpringBoot就是这么简单
  17. [Markdown编辑器推荐] - 这个MarkText有点东西啊
  18. 转:vue+canvas如何实现b站萌系登录界面
  19. 2020-12-22 ACM集训一(二维数组与结构体)
  20. 洛谷 P3387 【模板】缩点(scc 缩点)

热门文章

  1. linux redhat 下让redis以服务方式运行
  2. Linux进程实践(2) --僵尸进程与文件共享
  3. Django数据查询方法总结
  4. adb-常用命令记录
  5. Java读取Propertity文件
  6. SVG.js 颜色渐变使用
  7. “企业知识产权管理与预警”培训活动在省技术产权交易市场成功举办
  8. matlab 将一堆文件名读到一个文本里面windows版本里
  9. Composer fails to download http json files on update, not a network issue, https fine
  10. 桌面虚拟化之用户评估指南 (翻译)