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

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



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


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

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

kaslr特性使能和调试
使能条件
kaslr功能通过CONFIG_RANDOMIZE_BASE进行控制。 cmdline中不能存在nokaslr参数,否则kaslr不被使能。
随机种子
通过dts指定随机种子,如下:

验证测试
通过内核符号地址信息,可以观察内核符号加载状态,以此判断kaslr特性是否生效,命令如下:
echo 0 > /proc/sys/kernel/kptr_restrict
head /proc/kallsyms

kaslr开源社区参考资料
https://lwn.net/Articles/569635/
openEuler Kernel SIG
openEuler kernel 源代码仓库:https://gitee.com/openeuler/kernel 欢迎大家多多 star、fork,多多参与社区开发,多多贡献补丁。关于贡献补丁请参考:如何参与 openEuler 内核开发
openEuler kernel 微信技术交流群 请扫描下方二维码添加小助手微信,或者直接添加小助手微信(微信号:openeuler-kernel),备注“交流群”或“技术交流”,加入 openEuler kernel SIG 技术交流群。





