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
製作的線性映射的虛擬位址也就被隨機化了。