目錄
1.虛擬地址和物理地址映射完成后,才可以設置虛擬地址對應的memory tag ?
2.各種memory allocator中的address tag從哪來,怎么產生?
2.1 vmalloc allocator
2.2 slub分配器
2.3 用戶可以指定IRG指令產生的address tag
3.kasan_unpoison? 標記的內存地址需要16byte對齊,該對齊由誰保證?
4.被標記過的內存,釋放時會執行哪些特定動作?
?
?????? 前面幾篇文章是在介紹為什么需要MTE功能、MTE功能邏輯和硬件實現。從這篇文件起,結合之前MTE邏輯和硬件實現,開始介紹MTE功能在軟件中的實現。首先我要通過調查推理回答自己的幾個問題。
1.虛擬地址和物理地址映射完成后,才可以設置虛擬地址對應的memory tag ?
?????????Documentation – Arm Developer 根據文章描述和文章中圖的示意,memory tag 是與16 字節的物理內存空間是關聯的,存放memory tag的tag storage空間大小取決于物理內存空間大小。而且通過調查發現:系統在設置por_mtu_tag_addr_base 寄存器時使用的物理地址。
??????? 結合如上推斷例如指令 stg x0, [x0] 要設置x0[59 - 56]的address tag到[x0]對應的tag storage空間時,是在x0寄存器中的虛擬地址轉換為物理地址后,再找到物理地址在tag storage中對應的位置,最后將address tag做為memory tag存放到該對應空間。
??????? 按照如上邏輯:虛擬地址需要完成其和物理地址的映射后才可以設置或則讀取其對應的memory tag。
????????從代碼邏輯也可以推斷此行為,如下代碼邏輯。首先進行虛擬空間分配,在進行虛擬和物理地址空間之間的映射,只有在虛擬和物理地址空間成功建立映射后才會對該內存空間進行unpoison操作(即標記該部分空間已分配)。
void *vm_map_ram(struct page **pages, unsigned int count, int node)
{unsigned long size = (unsigned long)count << PAGE_SHIFT;unsigned long addr;void *mem;//獲取虛擬地址空間if (likely(count <= VMAP_MAX_ALLOC)) {mem = vb_alloc(size, GFP_KERNEL);if (IS_ERR(mem))return NULL;addr = (unsigned long)mem;} else {struct vmap_area *va;va = alloc_vmap_area(size, PAGE_SIZE,VMALLOC_START, VMALLOC_END,node, GFP_KERNEL, VMAP_RAM,NULL);if (IS_ERR(va))return NULL;addr = va->va_start;mem = (void *)addr;}//建議虛擬空間和物理內存空間之間的映射if (vmap_pages_range(addr, addr + size, PAGE_KERNEL,pages, PAGE_SHIFT) < 0) {vm_unmap_ram(mem, count);return NULL;}/** Mark the pages as accessible, now that they are mapped.* With hardware tag-based KASAN, marking is skipped for* non-VM_ALLOC mappings, see __kasan_unpoison_vmalloc().*///MTE使能時,進行tag標記mem = kasan_unpoison_vmalloc(mem, size, KASAN_VMALLOC_PROT_NORMAL);return mem;
}
? 2.各種memory allocator中的address tag從哪來,怎么產生?
2.1 vmalloc allocator
????????以vmalloc分配器為例,從 __kasan_unpoison_vmalloc 函數可以獲知 address tag來自于kasan_random_tag函數,通過IRG指令產生。
2.2 slub分配器
????????從slab分配器可知,address tag同樣來自kasan_random_tag,由IRG指令產生。
2.3 用戶可以指定IRG指令產生的address tag
??????? 如前文《Linux Mem -- MTE in AArch64 Linux-CSDN博客》介紹用戶進程可以通過prctl(PR_SET_TAGGED_ADDR_CTRL, flags, 0, 0, 0)系統函數指定特定的tag值。其內核層相關代碼如下:
static void mte_update_gcr_excl(struct task_struct *task)
{/** SYS_GCR_EL1 will be set to current->thread.mte_ctrl value by* mte_set_user_gcr() in kernel_exit, but only if KASAN is enabled.*/if (kasan_hw_tags_enabled())return;// thread.mte_ctrl中的tag字段來自于用戶程序設定,即prctl(PR_SET_TAGGED_ADDR_CTRL)參數設定write_sysreg_s(((task->thread.mte_ctrl >> MTE_CTRL_GCR_USER_EXCL_SHIFT) &SYS_GCR_EL1_EXCL_MASK) | SYS_GCR_EL1_RRND,SYS_GCR_EL1);
}
????????Tag相關寄存器說明:
GCR_EL1 : tag control register , 用于控制IRG(隨機tag生成指令)生成tag值。
SYS_GCR_EL1_RRND : GCR_EL1.bit16? =? 1 表示使用指定tag值,即IRG生成的tag為特定值
3.kasan_unpoison? 標記的內存地址需要16byte對齊,該對齊由誰保證?
??????? 如上是slub分配器分配內存的函數片段。MTE使能時,arch_slab_minalign()函數獲取到的slub內存分配器最小對齊要求為MTE_GRANULE_SIZE(16字節,MTE對齊粒度)。因為系統內存分配器設置的對齊粒度最小為MTE_GRANULE_SIZE,所以獲取到的內存空間起始地址也為MTE_GRANULE_SIZE對齊,故kasan_unpoison函數執行時判讀入參object可以滿足MTE_GRANULE_SIZE對齊要求。
4.被標記過的內存,釋放時會執行哪些特定動作?
??????? 如上是slub分配器的free函數調用片段。此處只關注MTE功能的影響,上slub分配器的kfree函數,最終會調用到kasan_slab_free -->poison_slab_object函數。Poision_slab_object函數只會對釋放內存正確性和可訪問性進行判斷,如果正確、可訪問則將該內存區域標記為KASAN_SLAB_FREE(0xFE)便于后續該內存的再分配。否則調用kasan_report_invalid_free函數,上報kasan檢測異常。