kernel address space layout randomization

kaslr的全称是kernel address space layout randomization,主要是通过每次开机将kernel image 加载到不同的
的地址来增强安全性。
其源码分析如下:
__primary_switched:


#ifdef CONFIG_RANDOMIZE_BASE
        tst     x23, ~(MIN_KIMG_ALIGN - 1)      // already running randomized?
        b.ne    0f
        mov     x0, x21                         // pass FDT address in x0
        bl      kaslr_early_init                // parse FDT for KASLR options
        cbz     x0, 0f                          // KASLR disabled? just proceed
        orr     x23, x23, x0                    // record KASLR offset
        ldp     x29, x30, [sp], #16             // we must enable KASLR, return
        ret                                     // to __primary_switch()
0:
#endif
        add     sp, sp, #16
        mov     x29, #0
        mov     x30, #0
        b       start_kernel
ENDPROC(__primary_switched)
从这段code 中可以看到将调用kasan_early_init 函数得到一个要加载kernel的地址,并将这个地址
保存到x32中
这样在__create_page_tables 中就可以将要加载kernel的地址从x23中取出来


__create_page_tables:


   /*
         * Map the kernel image (starting with PHYS_OFFSET).
         */
        adrp    x0, swapper_pg_dir
        mov_q   x5, KIMAGE_VADDR + TEXT_OFFSET  // compile time __va(_text)
        add     x5, x5, x23                     // add KASLR displacement
        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)

我们下来重点看看是如何从bios中得到kernel 加载地址的
u64 __init kaslr_early_init(u64 dt_phys)
{
void *fdt;
u64 seed, offset, mask, module_range;
const u8 *cmdline, *str;
int size;




module_alloc_base = (u64)_etext - MODULES_VSIZE;




early_fixmap_init();
fdt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
if (!fdt)
return 0;


/*
* Retrieve (and wipe) the seed from the FDT
*/
#从通过device tree 传递的地址
seed = get_kaslr_seed(fdt);
if (!seed)
return 0;


/*
* Check if 'nokaslr' appears on the command line, and
* return 0 if that is the case.
*/
cmdline = get_cmdline(fdt);
#从这里知道如果在commandline中添加nokaslr的话,则会关闭这个功能
str = strstr(cmdline, "nokaslr");
if (str == cmdline || (str > cmdline && *(str - 1) == ' '))
return 0;




mask = ((1UL << (VA_BITS - 2)) - 1) & ~(SZ_2M - 1);
offset = seed & mask;


/* use the top 16 bits to randomize the linear region */
memstart_offset_seed = seed >> 48;


if ((((u64)_text + offset) >> SWAPPER_TABLE_SHIFT) !=
    (((u64)_end + offset) >> SWAPPER_TABLE_SHIFT))
offset = round_down(offset, 1 << SWAPPER_TABLE_SHIFT);
#如果定义了kasan的话,则模块的加载地址不能是随机
if (IS_ENABLED(CONFIG_KASAN))
return offset;
#从这里知道ko加载的地址也可以是随机的
if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) {

module_range = VMALLOC_END - VMALLOC_START - MODULES_VSIZE;
module_alloc_base = VMALLOC_START;
} else {
module_range = MODULES_VSIZE - (u64)(_etext - _stext);
module_alloc_base = (u64)_etext + offset - MODULES_VSIZE;
}


/* use the lower 21 bits to randomize the base of the module region */
module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21;
module_alloc_base &= PAGE_MASK;


return offset;
}
我们下来看看如何通过fdt来传递地址
static __init u64 get_kaslr_seed(void *fdt)
{
int node, len;
fdt64_t *prop;
u64 ret;


node = fdt_path_offset(fdt, "/chosen");
if (node < 0)
return 0;


prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
if (!prop || len != sizeof(u64))
return 0;


ret = fdt64_to_cpu(*prop);
*prop = 0;
return ret;
}
原来在chosen节点下写kaslr-seed 就可以了

猜你喜欢

转载自blog.csdn.net/tiantao2012/article/details/80689963
今日推荐