首页 > 系统相关 >内存管理-22-KASLR

内存管理-22-KASLR

时间:2024-07-24 14:53:20浏览次数:12  
标签:__ 映射 22 KASLR kaslr 内存 offset 内核

基于msm-5.4


一、简介

1. 什么是KASLR

KASLR是 kernel address space layout randomization 的缩写,直译过来就是内核地址空间布局随机化。KASLR技术允许将kernel image映射到 vmalloc 区域的任何位置(待确认哦)。

2. 引入KASLR的原因

没有KASLR的时候,kernel image都会映射到一个固定的链接地址,安全性得不到保证。KASLR技术可以让kernel image映射的地址相对于链接地址有个偏移。这个偏移可以通过dts设置,如果bootloader支持每次开机随机生成偏移数值,那么可以做到每次开机kernel image映射的虚拟地址都不一样。因此在安全性上有一定的提升。

3. 主要实现文件

arch/arm64/kernel/kaslr.c
arch/arm64/kernel/head.S


二、实现逻辑

1. 偏移对内核镜像映射的影响

//arch/arm64/kernel/head.S

__primary_switched:
    mov    x0, x21                //pass FDT address in x0
    bl    kaslr_early_init    //parse FDT for KASLR options
    cbz    x0, 0f                //KASLR disabled? just proceed 若返回0则跳转到下面标签0:处运行,若返回的offset非0则继续执行
    orr    x23, x23, x0            //record KASLR offset x23或上返回的offsets
    ret                            // to __primary_switch() 返回到上一级函数中
0:
    b    start_kernel        //若返回offset非0就不会从这里启动内核了
ENDPROC(__primary_switched)

这里调用 kaslr_early_init(), 将设备树做为参数,返回值保存在x0中,然后位或给x23, 由于x23初始值是0,因此x23=x0=返回值offset.

若返回值offset不为0,要在内核虚拟基地址上加上这个offset,重新映射一遍内核镜像:

__primary_switch:
    adrp    x1, init_pg_dir
    bl    __enable_mmu  //这里就使能了MMU
#ifdef CONFIG_RELOCATABLE
    bl    __relocate_kernel
#ifdef CONFIG_RANDOMIZE_BASE
    ldr    x8, =__primary_switched
    adrp    x0, __PHYS_OFFSET
    blr    x8  //若kaslr_early_init()返回的offset非0,才会返回到这里继续往下执行
    /* 若执行到这里,在 x23 中有一个 KASLR 偏移,需要丢弃当前内核映射并创建一个新的内核映射来考虑到它 */
    pre_disable_mmu_workaround
    bl    __create_page_tables        //recreate kernel mapping 重新创建内核映射页表
#endif
#endif
    ldr    x8, =__primary_switched //在这里执行 start_kernel()
    adrp    x0, __PHYS_OFFSET
    br    x8
ENDPROC(__primary_switch)

返回offset!=0会返回到生成函数,导致 blr x8 被执行,之后disable掉之前的映射,重新创建内核镜像的页表。

__create_page_tables:
    /* Map the kernel image (starting with PHYS_OFFSET). */
    adrp    x0, init_pg_dir
    mov_q    x5, KIMAGE_VADDR + TEXT_OFFSET    // compile time __va(_text)
    add    x5, x5, x23            //add KASLR displacement 在内核镜像虚拟地址上再加上保存在x23中的kaslr的offset
    mov    x4, PTRS_PER_PGD
    adrp    x6, _end        // runtime __pa(_end)
    adrp    x3, _text        // runtime __pa(_text)
    sub    x6, x6, x3            // _end - _text
    add    x6, x6, x5            // runtime __va(_end)

    map_memory x0, x1, x5, x6, x7, x3, x4, x10, x11, x12, x13, x14
ENDPROC(__create_page_tables)
    .ltorg

再次创建内核镜像页表,要映射到的虚拟地址为 KIMAGE_VADDR + TEXT_OFFSET + offset.


2. 随机偏移获取方法

u64 __init kaslr_early_init(u64 dt_phys) //kaslr.c
{
    void *fdt;
    u64 seed, offset, mask, module_range;
    const u8 *cmdline, *str;
    int size;

    /* 为 module_alloc_base 设置一个合理的默认值,以防我们最终在禁用模块随机化的情况下运行 */
    module_alloc_base = (u64)_etext - MODULES_VSIZE;

    /*
     * 尝试尽早映射 FDT。如果失败,我们只需放弃,然后禁用 KASLR。我们将在 setup_machine() 中
     * 再次尝试映射 FDT. msm-5.4上没有这个函数,msm-4.14在 /external/u-boot/common/board_f.c 中
     * 此时MMU还远没有开启。
     */
    early_fixmap_init();
    fdt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
    if (!fdt)
        return 0;

    /* 解析设备树 "/chosen" 节点的 "kaslr-seed" 属性的值,得到随机种子,若没有配置则直接返回0 */
    seed = get_kaslr_seed(fdt);
    if (!seed)
        return 0 //实验:替换为 seed = 0x800000;后,内核起不来

    /*  若是在“/chosen”的"bootargs"属性或cmdline中指定了“ nokaslr” 标签,则返回0,表示kaslr不生效。*/
    cmdline = kaslr_get_cmdline(fdt);
    str = strstr(cmdline, "nokaslr");
    if (str == cmdline || (str > cmdline && *(str - 1) == ' '))
        return 0;

    /*
     * 好的,我们继续启用 KASLR。计算与种子相距合适的内核映像偏移量。让我们将
     * 内核放置在 VMALLOC 区域的中间一半(VA_BITS_MIN - 2),并避开下四分之一
     * 和上四分之一以避免与其他分配发生冲突。
     * 即使我们可以在 16k 和 64k 页面的页面粒度上随机化,我们也要始终四舍五入
     * 到 2 MB,这样我们就不会干扰使用连续 PTE 进行映射的能力。
     *
     * 补充: 启动阶段内核镜像映射粒度是2M,4k宵页映射一个PMD页表也映射2M.
     */
    /* mask = (1<<37 - 1) & ~(2M-1) = 0x1fffe00000 */
    mask = ((1UL << (VA_BITS_MIN - 2)) - 1) & ~(SZ_2M - 1);
    /* 偏移是2M对齐,且要落在虚拟地址空间的[1/4, 3/8] 之间 */
    offset = BIT(VA_BITS_MIN - 3) + (seed & mask);

    /* 随机种子是64bit的,这里保留高16bit的值,来随机化线性映射区的地址 */
    memstart_offset_seed = seed >> 48;

    if (IS_ENABLED(CONFIG_KASAN)) //默认关闭
        /*
         * KASAN 不希望模块区域与 vmalloc 区域相交,因为影子内存是在加载时为每个模块分配的,
         * 而 vmalloc 区域则被 KASAN 零页所遮蔽。因此,如果启用了 KASAN,请将模块置于 vmalloc 
         * 区域之外,并将内核置于模块区域的 4 GB 以内。
         */
        return offset % SZ_2G;

    if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) { //默认使能
        /*
         * 在覆盖内核的 2 GB 窗口上随机化模块区域(启动汇编中内核段映射最大支持2GB)。
         * 这降低了模块泄露有关内核本身地址信息的风险,但会导致模块和核心内核之间的分支通过 PLT 解析。
         */
        module_range = SZ_2G - (u64)(_end - _stext); //delta=0x3707000
        /* _end + offset - SZ_2G = 0xffffffbf937be000 + offset 与 MODULES_VADDR=0xffffffc008000000 取较大值 */
        module_alloc_base = max((u64)_end + offset - SZ_2G, (u64)MODULES_VADDR);
    } else {
        module_range = MODULES_VSIZE - (u64)(_etext - _stext);
        module_alloc_base = (u64)_etext + offset - MODULES_VSIZE;
    }

    /* 使用低21位随机化模块区域的基地址 */
    module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21;
    module_alloc_base &= PAGE_MASK; //4k对齐

    pr_info("HAM: %s: offset=0x%lx", offset); //调用过早,这里无法打印出来

    return offset;
}

可以看到,这个随机化除了内核镜像虚拟基地址随机化外,还对线性映射区的虚拟地址、module_alloc区的虚拟基地址进行了随机化。返回的offset用于随机内核镜像的虚拟基地址,返回的offset偏移是2M对齐,且要落在虚拟地址空间的[1/4, 3/8]之间。

KASLR使能开关:CONFIG_RANDOMIZE_BASE,它选中编译 kaslr.c, 从head.S中看它还依赖 CONFIG_RELOCATABLE, 所以这两个都需要使能。

使能后生效的条件(不是返回0)是在/chosen节点中配置了kaslr-seed随机种子,这个随机种子虽然看似在设备树中静态配置的,但是可以由bootloader进行填充,并且可以做到每次开机都不一样。其次是在 /chosen 节点的 bootargs 和 default_cmdline 中没有没有指定 “ nokaslr” 标签。

/ {
    chosen {
        kaslr-seed = <0x10000000>;
    };
}; 


三、实验

将 seed = 0x800000; 后内核起不来,若要使能,还需要进一步调试。


四、总结

1. KASLR就是在映射内核镜像的时候,在虚拟基地址上加上一个偏移。利用随机种子,可以让每次启动偏移都不一样。

2. 通过 CONFIG_RANDOMIZE_BASE 和 CONFIG_RELOCATABLE 使能此功能,若是想生效,还需要在 /chosen 节点中配置 kaslr-seed 随机种子,并且不能在 bootargs 和 cmdline 中指定 “ nokaslr”标签。

3. 算KASLR加的这个偏移,对内核镜像的映射一共有两个加偏移的位置了。另一个是 _text 要映射的虚拟基地址和Makefile中指定的 TEXT_OFFSET 决定的。

#define __PHYS_OFFSET    (KERNEL_START - TEXT_OFFSET) //_text - TEXT_OFFSET
ENTRY(stext)
    adrp    x23, __PHYS_OFFSET
ENDPROC(stext)

 

 

参考:
KASLR: http://www.wowotech.net/memory_management/441.html //蜗蜗

 

标签:__,映射,22,KASLR,kaslr,内存,offset,内核
From: https://www.cnblogs.com/hellokitty2/p/18320872

相关文章

  • OSError(22, '无效参数') - 无法打开任何 `.ipynb` 和 `.py` 文件
    我无法打开我过去拥有的任何Jupyernotebook或python文件,并且收到此错误:UnreadableNotebook:C:\Users\[mypath]\main\main.ipynbOSError(22,'Invalidargument')[mypath]是我从上面删除的目录的一部分。我尝试通过解决方案这篇文章,但仍然有同样......
  • 代码随想录算法训练营第41天 |322.零钱兑换、279.完全平方数、139.单词拆分、多重背包
    322.零钱兑换https://leetcode.cn/problems/coin-change/description/代码随想录https://programmercarl.com/0322.零钱兑换.html#算法公开课279.完全平方数https://leetcode.cn/problems/perfect-squares/description/代码随想录https://programmercarl.com/0279.完全平......
  • 【UDS诊断协议:ISO-14229中文】【嵌入式车载测试收徒】
    每日直播时间:(直播方式:腾讯会议)周一到周五:20:00-23:00周六与周日:9:00-17:00                 进腾讯会议学习的,可以关注我并后台留言直播内容:(车厂真实项目实操测试)HIL(硬件在环)测试、UDS功能诊断、UDS自动化诊断、数据库制作、DTC故障制造、CAN......
  • 什么是闭包,闭包的使用场景、闭包的优缺点,以及解决内存泄露的方法
    1、定义:闭包是指有权访问另一个函数作用域中变量的函数。有局部变量才会有闭包。简单理解:如果一个函数内部访问了外部的变量,那么就是闭包2、举个闭包的例子:displayName() 没有自己的局部变量。然而,由于闭包的特性,它可以访问到外部函数的变量3、使用场景一、创建私有变量......
  • 既然内存不值钱,为什么java还要搞一个压缩指针?
    尽管当前内存的价格可能相对较为亲民,但Java引入压缩指针技术的原因并不单纯基于内存成本,而是出于优化内存使用、提升程序性能以及适应不同应用场景的综合考虑。在64位Java虚拟机(JVM)中,传统的指针占用8个字节(64位)。然而,对于大多数Java应用程序来说,实际上并不需要如此大的内存地......
  • SQL 命令在手动运行时工作正常(SQL Developer),但在 Python 的 oracledb 模块中给出 ORA-
    我正在使用OracleSQL数据库,并且我想运行该命令ALTERSESSIONSETNLS_DATE_FORMAT='YYYY-MM-DD';当我从SQLDeveloper应用程序手动运行它时,它工作正常。但是,当我使用oracledb模块从Python运行它时,出现以下错误:ErrorrunningSQLscript:ORA-00922:mi......
  • 2024.7.22每日笔记,有错望指出
    //5、求125之内自然数中偶数之和。#include<stdio.h>intmain(){inti=0;intsum=0;for(i=0;i<=125;i++){if(i%2==0){sum=sum+i;printf("%d\n",sum);}}return0;}//7、编程计算1......
  • 深入理解Java虚拟机:JVM高级特性与最佳实践-第三章-垃圾收集器与内存分配策略
    在java内存运行时区域中的各个部分中,程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭,因此这几个区域的内存分配和回收都具备确定性,在这几个区域内就不需要过多考虑如何回收的问题,当方法结束或者线程结束时,内存自然就跟随着回收了。但是Java堆和方法区这两个区域具有......
  • 7.22 第一次听客户需求
    1.背景        身为大一学生,很荣幸可以参与果园管理的项目制作。由于我有做产品经理的打算,老师也有意培养,中午11点开始了腾讯会议的项目需求会。         M总,即为我们的客户,为我们展示需求。M总是一位值得敬佩的新型农民,虽然没上大学,但通过自学VB,给所在地的......
  • 深入理解Java内存模型及其在多线程编程中的应用
    深入理解Java内存模型及其在多线程编程中的应用大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来深入探讨Java内存模型(JavaMemoryModel,JMM)及其在多线程编程中的应用。一、Java内存模型概述Java内存模型(JMM)是Java虚拟机规范的一部分,定义了变......