Linux版本:v6.0
處理器架構:ARMv8
這篇接續Linux ARM64 KASLR 實作分析(1): 內核映像位址隨機化
線性位址隨機化實作機制
memstart_offset_seed 的來由
上篇說到在__primary_switch 中,程式呼叫了__pi_kaslr_early_init 來獲得KASLR使用的隨機偏移,並且把低20位存在暫存器x24中。接著在 __primary_switched 中把x24的值存到memstart_offset_seed:
1 | SYM_FUNC_START_LOCAL(__primary_switched) |
memstart_offset_seed 在arch/arm64/kernel/kaslr.c 中被定義:
1 | u16 __initdata memstart_offset_seed; |
可以看到它是個u16,所以上面使用strh,使得其剩下16位的隨機值。
arm64_memblock_init
接下來的初始化流程會執行到arm64_memblock_init 函式
1 | start_kernel |
擷取與KASLR有關的部份:
1 | void __init arm64_memblock_init(void) |
那為何改變memstart_addr 就會改變線性空間位址呢?
線性映射隨機化
我們來看一下真正要隨機化線性空間的頁表操作。線性空間的頁表是在paging_init → map_mem中建立的:
1 | static void __init map_mem(pgd_t *pgdp) |
__map_memblock
1 | static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start, |
__create_pgd_mapping 在 Linux ARM64 __create_pgd_mapping 分析 有詳細的介紹,這邊重點在於[start - end) 這段物理位址區間在這裡被建立了一個到[__phys_to_virt(start) - __phys_to_virt(end)) 的頁表映射,也就是說__phys_to_virt 決定了線性映射的虛擬位址
__phys_to_virt
macro定義在arch/arm64/include/asm/memory.h 中:
1 |
而在同個檔案中 PHYS_OFFSET 基本被定義為memstart_addr
1 | extern s64 memstart_addr; |
這樣子就接回memstart_addr 了,memstart_addr 在arm64_memblock_init 中被減去一個隨機值,導致PHYS_OFFSET 和__phys_to_virt 被隨機化,所以paging_init → map_mem → ___map_memblock → __create_pgd_mapping 製作的線性映射的虛擬位址也就被隨機化了。