本文共 2976 字,大约阅读时间需要 9 分钟。
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 就可以了转载地址:http://ennmi.baihongyu.com/