openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区-51CTO.COM

openEuler Kernel技术解读 | kaslr内核安全特性

top_tony
发布于 2022-8-17 18:13
浏览
0收藏

kaslr实现原理
   Linux内核支持arm、x86_64、PowerPC等多种不同的架构,不同的架构下,kaslr的实现方式各不相同,但核心思想均在于增加随机偏移。在内核启动阶段,通过获取一个随机值,并对内核加载地址进行相应的随机偏移。该偏移值既可以通过dtb传递,也可以基于随机源生成,在完成内核数据随机映射之后,还需要对符号地址进行重定位,校正内核代码的符号寻址,以此确保内核代码的正常执行。以arm64 5.10内核为例,kaslr在实现时主要通过改变原先固定的内存布局来提升内核安全性,因此在代码实现过程中,kaslr与内存功能存在比较强的耦合关系,Linux内存的虚拟地址空间布局与内核编译配置有关,不同的配置会产生不同的地址空间模型,以4KB pages + 4 levels (48-bit)为例,其虚拟地址空间模型如下:(详细的内存布局信息可参考内核文档:Documentation/arm64/memory.rst)

openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区

如图所示,Arm64的虚拟地址空间整体可划分为两个部分:内核地址空间和用户地址空间,通常内核地址空间由内核代码分配使用,所有进程共享内核地址空间,而用户地址空间则为用户态进程独占。内核启动阶段,内核镜像的加载、解压和运行均在内核地址空间完成,kaslr也主要在这里对内核内存布局进行随机调整,arm64的内存布局随机主要分为三部分:内核镜像随机、线性映射区随机以及module随机,在随机过程中需要提供随机种子,随机种子生成如下:

openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区

Arm64的随机种子通过dtb文件获取,因此会为dtb区域建立映射,从dtb文件解析kaslr-seed的属性配置,同时会获取dtb里面的command line配置,判断是否存在nokaslr配置参数,当不存在随机种子或者配置了nokaslr参数时,kaslr功能会被关闭,并修改相应的kaslr_status状态变量为KASLR_DISABLED_CMDLINE或者KASLR_DISABLED_NO_SEED。  由dtb文件获取到kaslr-seed配置后,会对种子进行处理,基于不同的处理方式,分别用于镜像、线性区和module区域的随机,如下图:
 openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区

offset为镜像随机偏移值,内核需要保证偏移地址2M对齐,同时通过(VA_BITS_MIN - 2)限制内核随机范围在vmalloc区域中间的一半,避免使用头部和尾部的1/4区域,以避免跟其他的内存分配特性冲突。memstart_offset_seed为线性区的随机种子,内核使用seed的高16位作为线性区域的随机值。  Arm64在内存初始化时,内核会将物理内存通过线性映射的方式完整映射到虚拟地址空间的线性映射区域,如下图:
 openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区

随机范围是线性区减去物理内存的大小,同时限制偏移粒度ARM64_MEMSTART_ALIGN(256MB),线性区的使用主要涉及virt_to_phys和phys_to_virt两个地址转换接口,其代码实现如下:

openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区

以virt_to_phys为例,通过virt_to_phys的接口实现,可以看出memstart_addr为物理地址的起始值,PAGE_OFFSET为虚拟地址中内核地址空间的起始位置,物理地址与虚拟地址之间存在以下转换关系:物理地址 = 虚拟地址 – PAGE_OFFSET + memstart_addr 因此内核可以通过调整memstart_addr的值来进行线性区的映射关系的随机偏移。  Kernel系统启动初期,__primary_switched函数调用kaslr_early_init函数初始化随机偏移值,并保存在x23寄存器当中,实现如下图: 

openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区

后续进行kernel image虚拟地址映射,会将内核映射的虚拟地址加上kaslr随机偏移(x23寄存器),如下图:

openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区

完成kernel image虚拟地址映射以后,需要调用__relocate_kernel进行重定位,函数实现如下:

openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区

__relocate_kernel主要对重定位段进行符号重定位,重定位段包含了内核执行过程中需要用到的变量符号,比如_stext、_etext,这些符号对应的地址在链接时确定的,使能kaslr之后,kernel image经过偏移映射,运行时的虚拟地址与编译确定的原始虚拟地址不同,如果不进行重定位操作,则内核无法正常执行。


kaslr特性使能和调试
使能条件

kaslr功能通过CONFIG_RANDOMIZE_BASE进行控制。
cmdline中不能存在nokaslr参数,否则kaslr不被使能。
随机种子

通过dts指定随机种子,如下:
 openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区

验证测试

通过内核符号地址信息,可以观察内核符号加载状态,以此判断kaslr特性是否生效,命令如下:

echo 0 > /proc/sys/kernel/kptr_restrict
head /proc/kallsyms

openEuler Kernel技术解读 | kaslr内核安全特性-鸿蒙开发者社区(文章转载自公众号:架构与思维)

已于2022-8-17 18:13:09修改
收藏
回复
举报
回复
    相关推荐