make menuconfig kernel hacking Export kernel pagetable layout
設定核心 • make menuconfig • 進入kernel hacking,並選擇下面二個選項 • <*> Export kernel pagetable layout to userspace via debugfs • [*] Dump the EFI pagetable • 這二個選項預設不會打開,因為打開以後可能會造成系統漏洞 • 再次確認 • > cat. config | grep CONFIG_X 86_PTDUMP • CONFIG_X 86_PTDUMP_CORE=y • CONFIG_X 86_PTDUMP=y 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 3
預備編譯核心的環境 $ sudo apt install git flex bison bc libssl-dev gawk libudev-dev ocl-icd-opencl-dev libpci-dev libelf-dev python 2. 7 libncursesdev fakeroot kernel-wedge binfmt-support ksh lsscsi binfmtsupport libpcre 16 -3 libpcre 3 -dev libpcre 32 -3 libpcrecpp 0 v 5 libsepol 1 -dev libattr 1 -dev libblkid-dev libpcre 16 -3 libpcre 3 dev libpcre 32 -3 libpcrecpp 0 v 5 libselinux 1 -dev libsepol 1 -dev uuid-dev debugedit libarchive 13 libdw 1 liblua 5. 2 -0 liblzo 2 -2 libnspr 4 libnss 3 librpm 8 librpmbuild 8 librpmio 8 librpmsign 8 rpm-common rpm 2 cpio spl-dkms kernel-package 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 4
cat /sys/kernel/debug/kernel_page_tables 核心記憶體 ---[ User Space ]--0 x 00000000 -0 xffff 8000000 16777088 T pgd ---[ Kernel Space ]--0 xffff 8000000 -0 xffff 8800000 ---[ Low Kernel Mapping ]--- • 如果是kernel 4. 0請使 用右方的指令 • pgd是 512 GB的映射 • pud是 1 GB的映射 • pmd是 2 MB的映射 • pte是 4 KB的映射 0 xffff 8800000 -0 xffff 880000099000 612 K RW GLB NX pte 0 xffff 880000099000 -0 xffff 88000009 a 000 4 K ro GLB NX pte 0 xffff 88000009 a 000 -0 xffff 88000009 b 000 4 K ro GLB x 0 xffff 88000009 b 000 -0 xffff 880000200000 1428 K RW GLB NX pte 0 xffff 880000200000 -0 xffff 880001000000 14 M RW PSE GLB NX pmd 0 xffff 880001000000 -0 xffff 880001 c 00000 12 M ro PSE GLB NX pmd 0 xffff 880001 c 00000 -0 xffff 880001 d 12000 1096 K ro GLB NX pte 0 xffff 880001 d 12000 -0 xffff 880001 e 00000 952 K RW GLB NX pte 0 xffff 880001 e 00000 -0 xffff 880002000000 2 M ro 0 xffff 880002000000 -0 xffff 8800021 d 2000 1864 K ro GLB NX pte 0 xffff 8800021 d 2000 -0 xffff 880002600000 4280 K RW GLB NX pte 0 xffff 880002600000 -0 xffff 88000 fc 00000 214 M RW 0 xffff 88000 fc 00000 -0 xffff 88000 ffe 0000 3968 K RW 0 xffff 88000 ffe 0000 -0 xffff 880010000000 128 K pte 0 xffff 880010000000 -0 xffff 880040000000 768 M pmd 0 xffff 880040000000 -0 xffff 88800000 511 G pud 0 xffff 88800000 -0 xffffc 900000 66048 G pgd PSE pte GLB NX pmd GLB NX pte /*後面有些被截斷*/ 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 6
cat /sys/kernel/debug/page_tables/kernel 核心記憶體 ---[ User Space ]--0 x 00000000 -0 xffff 8000000 16777088 T pgd ---[ Kernel Space ]--0 xffff 8000000 -0 xffff 8800000 ---[ Low Kernel Mapping ]--- • 如果是kernel 4. 19請 使用右方的指令 • pud是 1 GB的映射 • pmd是 2 MB的映射 • pte是 4 KB的映射 0 xffff 8800000 -0 xffff 880000099000 612 K RW GLB NX pte 0 xffff 880000099000 -0 xffff 88000009 a 000 4 K ro GLB NX pte 0 xffff 88000009 a 000 -0 xffff 88000009 b 000 4 K ro GLB x 0 xffff 88000009 b 000 -0 xffff 880000200000 1428 K RW GLB NX pte 0 xffff 880000200000 -0 xffff 880001000000 14 M RW PSE GLB NX pmd 0 xffff 880001000000 -0 xffff 880001 c 00000 12 M ro PSE GLB NX pmd 0 xffff 880001 c 00000 -0 xffff 880001 d 12000 1096 K ro GLB NX pte 0 xffff 880001 d 12000 -0 xffff 880001 e 00000 952 K RW GLB NX pte 0 xffff 880001 e 00000 -0 xffff 880002000000 2 M ro 0 xffff 880002000000 -0 xffff 8800021 d 2000 1864 K ro GLB NX pte 0 xffff 8800021 d 2000 -0 xffff 880002600000 4280 K RW GLB NX pte 0 xffff 880002600000 -0 xffff 88000 fc 00000 214 M RW 0 xffff 88000 fc 00000 -0 xffff 88000 ffe 0000 3968 K RW 0 xffff 88000 ffe 0000 -0 xffff 880010000000 128 K pte 0 xffff 880010000000 -0 xffff 880040000000 768 M pmd 0 xffff 880040000000 -0 xffff 88800000 511 G pud 0 xffff 88800000 -0 xffffc 900000 66048 G pgd PSE pte GLB NX pmd GLB NX pte /*後面有些被截斷*/ 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 7
paging with multiple page size: x 86 -Linux,pte page pgd_offset, 9 bits pud_offset, 9 bits pmd_offset, 9 bits pte_offset, 9 bits offset, 12 bits 4 k data page cr 3 task_struct->mm->pgd 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 8 8
paging with multiple page size: x 86 -Linux,pmd page pgd_offset, 9 bits pud_offset, 9 bits pmd_offset, 9 bits offset, 12+9 = 21 bits 2 M data page cr 3 task_struct->mm->pgd 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 9 9
paging with multiple page size: x 86 -Linux,pud page pgd_offset, 9 bits pud_offset, 9 bits offset, 12+9+9 = 30 bits 1 GB data page cr 3 task_struct->mm->pgd 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 10 10
paging with multiple page size: x 86 -Linux ,pgd page (軟體上存在,硬體上沒有) pgd_offset, 9 bits offset, 12+9+9+9 = 39 bits 512 GB data page cr 3 task_struct->mm->pgd 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 11 11
dump_pagetables. c的初始化 /arch/x 86/mm/dump_pagetables. c 1. static int __init pt_dump_init(void) { 2. //PAGE_OFFSET就是核心的開始位址,注意是virtual address 3. address_markers[LOW_KERNEL_NR]. start_address = PAGE_OFFSET; 4. address_markers[VMALLOC_START_NR]. start_address = VMALLOC_START; 5. address_markers[VMEMMAP_START_NR]. start_address = VMEMMAP_START; 6. } 7. //告訴核心,使用pt_dump_init這個函數初始化這個「功能模組」 8. __initcall(pt_dump_init); 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 13
註冊檔案操作 /arch/x 86/mm/debug_pagetables. c 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. static const struct file_operations ptdump_fops = {. owner = THIS_MODULE, . open = ptdump_open, /*當有人要打開這個檔案,就呼叫ptdump_open*/ . read = seq_read, /*當要read*/ . llseek = seq_lseek, /*當要lseek*/ . release = single_release, /*不需要這個檔案時,例如:close*/ /*沒有. write,表示這個檔案不支援寫入*/ }; static int __init pt_dump_debug_init(void){ /*告訴核心當有人要打開kernel_page_tables這個檔案時應該呼叫哪些函數,函數定義在ptdump_fops*/ pe = debugfs_create_file("kernel_page_tables", S_IRUSR, NULL, &ptdump_fops); } module_init(pt_dump_debug_init); 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 14
(gdb) b ptdump_show (QEMU) $ cat /sys/kernel/debug/kernel_page_tables 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 15
附錄:記憶體位址轉換 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. //for kernel mapping only phys_addr = virt_to_phys(virt_addr); virt_addr = phys_to_virt(phys_addr); bus_addr = virt_to_bus(virt_addr); virt_addr = bus_to_virt(bus_addr); #define virt_to_bus virt_to_phys #define bus_to_virt phys_to_virt void *phys_to_virt(phys_addr_t address) { return __va(address); } #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) phys_addr_t virt_to_phys(volatile void *address) { return __pa(address); } #define __pa(x) __phys_addr((unsigned long)(x)) 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 16
• cr 2 = read_cr 2(); • cr 3 = read_cr 3(); • https: //elixir. bootlin. com/linux/v 4. 0/source/arch/x 86/mm/d ump_pagetables. c 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 17
control registers • https: //en. wikipedia. org/wiki/Control_register • 我們只用到CR 2與CR 3 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 18
Default handlers • • • do_anonymous_page: no page and no file do_linear_fault: vm_ops registered? do_swap_page: page backed by swap do_nonlinear_fault: page backed by file do_wp_page: write protected page (Co. W) 中正大學 – 羅習五 創作共用-姓名 標示-非商業性-相同方式分享 CC-BY-NC-SA 26
- Slides: 26