• Linux - 内核 - 安全机制 - 内存页表安全


    说明

    • 内核页表安全的最终目标是:将内核使用到的内存页(内核与module占用)的属性(读/写/可执行)配置成安全的,即:代码段和rodata段只读,非代码段不能执行等,用来防御堆栈执行和代码段被修改的攻击。

    内核页表安全

    相关选项

    CONFIG_DEBUG_KERNEL=y (4.11版本之前)
    CONFIG_DEBUG_RODATA=y (4.11版本)
    CONFIG_STRICT_KERNEL_RWX=y (4.11至最新版本)
    
    • 1
    • 2
    • 3
    • 开启该选项后,内核的text段和rodata段内存将会变成只读,并且非代码段的内存将会变成不可执行。

    影响

    1. kernel code, init等占用的预留内存会变大。
    • 开启配置后,编译使用的链接脚本中会对kernel的代码段等内存做size对齐操作(默认2MB对齐),预留内存占用会多3~4MB,如下:
    * 开启配置,启动log (kernel code,init大小2M对齐)
    Memory: 32360K/131072K available (4096K kernel code, 277K rwdata, 1240K rodata, 2048K init, 139K bss, 98712K reserved, 0K cma-reserved)
    * 未开启配置,启动log
    Memory: 35788K/131072K available (3122K kernel code, 282K rwdata, 1304K rodata, 144K init, 140K bss, 95284K reserved, 0K cma-reserved)
    
    • 1
    • 2
    • 3
    • 4
    • 链接脚本
    file: arch/arm/include/asm/pgtable-2level.h:
    #define SECTION_SHIFT		20
    ...
    
    file: arch/arm/kernel/vmlinux.lds.S
    ...
    #ifdef CONFIG_STRICT_KERNEL_RWX
            . = ALIGN(1<
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. 阻止使用gdb调试软件断点,jtag硬件断点可用,blog 说明

    module页表安全

    相关选项

    CONFIG_STRICT_MODULE_RWX
    
    • 1
    • 作用和CONFIG_STRICT_KERNEL_RWX一样,只是作用对象变成了module。

    实现原理

    1. 初始化 rodata_enabled值,开启配置后,默认为true。
    //file: init/main.c
    ...
    #if defined(CONFIG_STRICT_KERNEL_RWX) || defined(CONFIG_STRICT_MODULE_RWX)
    bool rodata_enabled __ro_after_init = true;
    static int __init set_debug_rodata(char *str)
    {
            return strtobool(str, &rodata_enabled);
    }
    __setup("rodata=", set_debug_rodata);
    #endif
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. mmap
    //file: arch/arm64/mm/mmu.c
    static void __init map_kernel(pgd_t *pgdp)
    {
        static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_inittext,
                                vmlinux_initdata, vmlinux_data;
        
        /*
         * External debuggers may need to write directly to the text
         * mapping to install SW breakpoints. Allow this (only) when
         * explicitly requested with rodata=off.
         */
        pgprot_t text_prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
        
        /*
         * If we have a CPU that supports BTI and a kernel built for
         * BTI then mark the kernel executable text as guarded pages
         * now so we don't have to rewrite the page tables later.
         */
        if (arm64_early_this_cpu_has_bti())
                text_prot = __pgprot_modify(text_prot, PTE_GP, PTE_GP);
        
        /*
         * Only rodata will be remapped with different permissions later on,
         * all other segments are allowed to use contiguous mappings.
         */
        map_kernel_segment(pgdp, _text, _etext, text_prot, &vmlinux_text, 0,
                           VM_NO_GUARD);
        .....
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    现状

    • 未开启相关配置的Linux内核,内存页权限没做什么限制。
    • 以上选项对于较新的CPU架构和kernel版本,已经是默认开启,Linux内核中会根据ARCH(CPU架构)来确定是否默认支持,如下:
    //file: arch/Kconfig
    config ARCH_OPTIONAL_KERNEL_RWX
        def_bool n
    
    config ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
        def_bool n
    
    config ARCH_HAS_STRICT_KERNEL_RWX
        def_bool n
    
    config STRICT_KERNEL_RWX
        bool "Make kernel text and rodata read-only" if ARCH_OPTIONAL_KERNEL_RWX
        depends on ARCH_HAS_STRICT_KERNEL_RWX
        default !ARCH_OPTIONAL_KERNEL_RWX || ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
        ...
    
    //file: arch/riscv/Kconfig   // riscv架构cpu配置
    config RISCV
        def_bool y
        ...
        select ARCH_HAS_STRICT_KERNEL_RWX if MMU
        ...
        select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX
        select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 也可以手动对以上选项进行配置,如下:
    General architecture-dependent options  --->
        [*] Make kernel text and rodata read-only (NEW)
        [*] Set loadable kernel module data as NX and text as RO (NEW)
    
    • 1
    • 2
    • 3
    • 对于服务器产品是默认开启选项,但是在封闭的小型嵌入式设备上的Linux时常会选择不开启该配置,来节省内存。
  • 相关阅读:
    Python爬虫教程12:从b站获取神仙姐姐的视频弹幕内容
    虚拟局域网VLAN_基础知识
    java this用法
    前端开发核心知识进阶 —— 宏任务和微任务
    NativeScaler()与loss_scaler【loss.backward()和 optimizer.step()】
    VirtualLab专题实验教程-3.二维分束超表面光栅
    new的空间能否用realloc扩容?
    postgresql中uuid的使用
    Tensorflow实现手写数字识别
    tab点击切换不使用判断条件进行不同tab的切换刷新
  • 原文地址:https://blog.csdn.net/qazw9600/article/details/134438620