179e53994SYang Weijiang 279e53994SYang Weijiang #include "libcflat.h" 379e53994SYang Weijiang #include "x86/desc.h" 479e53994SYang Weijiang #include "x86/processor.h" 579e53994SYang Weijiang #include "x86/vm.h" 679e53994SYang Weijiang #include "x86/msr.h" 779e53994SYang Weijiang #include "vmalloc.h" 879e53994SYang Weijiang #include "alloc_page.h" 979e53994SYang Weijiang #include "fault_test.h" 1079e53994SYang Weijiang 1179e53994SYang Weijiang static int cp_count; 12*96add4abSYang Weijiang static unsigned long invalid_offset = 0xffffffffffffff; 1379e53994SYang Weijiang 1479e53994SYang Weijiang static u64 cet_shstk_func(void) 1579e53994SYang Weijiang { 1679e53994SYang Weijiang unsigned long *ret_addr, *ssp; 1779e53994SYang Weijiang 1879e53994SYang Weijiang /* rdsspq %rax */ 1979e53994SYang Weijiang asm volatile (".byte 0xf3, 0x48, 0x0f, 0x1e, 0xc8" : "=a"(ssp)); 2079e53994SYang Weijiang 2179e53994SYang Weijiang asm("movq %%rbp,%0" : "=r"(ret_addr)); 2279e53994SYang Weijiang printf("The return-address in shadow-stack = 0x%lx, in normal stack = 0x%lx\n", 2379e53994SYang Weijiang *ssp, *(ret_addr + 1)); 2479e53994SYang Weijiang 2579e53994SYang Weijiang /* 2679e53994SYang Weijiang * In below line, it modifies the return address, it'll trigger #CP 2779e53994SYang Weijiang * while function is returning. The error-code is 0x1, meaning it's 2879e53994SYang Weijiang * caused by a near RET instruction, and the execution is terminated 2979e53994SYang Weijiang * when HW detects the violation. 3079e53994SYang Weijiang */ 3179e53994SYang Weijiang printf("Try to temper the return-address, this causes #CP on returning...\n"); 3279e53994SYang Weijiang *(ret_addr + 1) = 0xdeaddead; 3379e53994SYang Weijiang 3479e53994SYang Weijiang return 0; 3579e53994SYang Weijiang } 3679e53994SYang Weijiang 3779e53994SYang Weijiang static u64 cet_ibt_func(void) 3879e53994SYang Weijiang { 3979e53994SYang Weijiang /* 4079e53994SYang Weijiang * In below assembly code, the first instruction at lable 2 is not 4179e53994SYang Weijiang * endbr64, it'll trigger #CP with error code 0x3, and the execution 4279e53994SYang Weijiang * is terminated when HW detects the violation. 4379e53994SYang Weijiang */ 4479e53994SYang Weijiang printf("No endbr64 instruction at jmp target, this triggers #CP...\n"); 4579e53994SYang Weijiang asm volatile ("movq $2, %rcx\n" 4679e53994SYang Weijiang "dec %rcx\n" 477bf8144eSZixuan Wang "leaq 2f(%rip), %rax\n" 4879e53994SYang Weijiang "jmp *%rax \n" 4979e53994SYang Weijiang "2:\n" 5079e53994SYang Weijiang "dec %rcx\n"); 5179e53994SYang Weijiang return 0; 5279e53994SYang Weijiang } 5379e53994SYang Weijiang 5479e53994SYang Weijiang #define ENABLE_SHSTK_BIT 0x1 5579e53994SYang Weijiang #define ENABLE_IBT_BIT 0x4 5679e53994SYang Weijiang 5779e53994SYang Weijiang static void handle_cp(struct ex_regs *regs) 5879e53994SYang Weijiang { 5979e53994SYang Weijiang cp_count++; 6079e53994SYang Weijiang printf("In #CP exception handler, error_code = 0x%lx\n", 6179e53994SYang Weijiang regs->error_code); 62*96add4abSYang Weijiang /* Below jmp is expected to trigger #GP */ 63*96add4abSYang Weijiang asm("jmp %0": :"m"(invalid_offset)); 6479e53994SYang Weijiang } 6579e53994SYang Weijiang 6679e53994SYang Weijiang int main(int ac, char **av) 6779e53994SYang Weijiang { 6879e53994SYang Weijiang char *shstk_virt; 6979e53994SYang Weijiang unsigned long shstk_phys; 7079e53994SYang Weijiang unsigned long *ptep; 7179e53994SYang Weijiang pteval_t pte = 0; 72*96add4abSYang Weijiang bool rvc; 7379e53994SYang Weijiang 7479e53994SYang Weijiang cp_count = 0; 7579e53994SYang Weijiang if (!this_cpu_has(X86_FEATURE_SHSTK)) { 7679e53994SYang Weijiang printf("SHSTK not enabled\n"); 7779e53994SYang Weijiang return report_summary(); 7879e53994SYang Weijiang } 7979e53994SYang Weijiang 8079e53994SYang Weijiang if (!this_cpu_has(X86_FEATURE_IBT)) { 8179e53994SYang Weijiang printf("IBT not enabled\n"); 8279e53994SYang Weijiang return report_summary(); 8379e53994SYang Weijiang } 8479e53994SYang Weijiang 8579e53994SYang Weijiang setup_vm(); 8679e53994SYang Weijiang handle_exception(21, handle_cp); 8779e53994SYang Weijiang 8879e53994SYang Weijiang /* Allocate one page for shadow-stack. */ 8979e53994SYang Weijiang shstk_virt = alloc_vpage(); 9079e53994SYang Weijiang shstk_phys = (unsigned long)virt_to_phys(alloc_page()); 9179e53994SYang Weijiang 9279e53994SYang Weijiang /* Install the new page. */ 9379e53994SYang Weijiang pte = shstk_phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK; 9479e53994SYang Weijiang install_pte(current_page_table(), 1, shstk_virt, pte, 0); 9579e53994SYang Weijiang memset(shstk_virt, 0x0, PAGE_SIZE); 9679e53994SYang Weijiang 9779e53994SYang Weijiang /* Mark it as shadow-stack page. */ 9879e53994SYang Weijiang ptep = get_pte_level(current_page_table(), shstk_virt, 1); 9979e53994SYang Weijiang *ptep &= ~PT_WRITABLE_MASK; 10079e53994SYang Weijiang *ptep |= PT_DIRTY_MASK; 10179e53994SYang Weijiang 10279e53994SYang Weijiang /* Flush the paging cache. */ 10379e53994SYang Weijiang invlpg((void *)shstk_phys); 10479e53994SYang Weijiang 10579e53994SYang Weijiang /* Enable shadow-stack protection */ 10679e53994SYang Weijiang wrmsr(MSR_IA32_U_CET, ENABLE_SHSTK_BIT); 10779e53994SYang Weijiang 10879e53994SYang Weijiang /* Store shadow-stack pointer. */ 10979e53994SYang Weijiang wrmsr(MSR_IA32_PL3_SSP, (u64)(shstk_virt + 0x1000)); 11079e53994SYang Weijiang 11179e53994SYang Weijiang /* Enable CET master control bit in CR4. */ 11279e53994SYang Weijiang write_cr4(read_cr4() | X86_CR4_CET); 11379e53994SYang Weijiang 114*96add4abSYang Weijiang printf("Unit test for CET user mode...\n"); 115*96add4abSYang Weijiang run_in_user((usermode_func)cet_shstk_func, GP_VECTOR, 0, 0, 0, 0, &rvc); 11679e53994SYang Weijiang report(cp_count == 1, "Completed shadow-stack protection test successfully."); 11779e53994SYang Weijiang cp_count = 0; 11879e53994SYang Weijiang 11979e53994SYang Weijiang /* Enable indirect-branch tracking */ 12079e53994SYang Weijiang wrmsr(MSR_IA32_U_CET, ENABLE_IBT_BIT); 12179e53994SYang Weijiang 122*96add4abSYang Weijiang run_in_user((usermode_func)cet_ibt_func, GP_VECTOR, 0, 0, 0, 0, &rvc); 12379e53994SYang Weijiang report(cp_count == 1, "Completed Indirect-branch tracking test successfully."); 12479e53994SYang Weijiang 12579e53994SYang Weijiang write_cr4(read_cr4() & ~X86_CR4_CET); 12679e53994SYang Weijiang wrmsr(MSR_IA32_U_CET, 0); 12779e53994SYang Weijiang 12879e53994SYang Weijiang return report_summary(); 12979e53994SYang Weijiang } 130