1*79e53994SYang Weijiang 2*79e53994SYang Weijiang #include "libcflat.h" 3*79e53994SYang Weijiang #include "x86/desc.h" 4*79e53994SYang Weijiang #include "x86/processor.h" 5*79e53994SYang Weijiang #include "x86/vm.h" 6*79e53994SYang Weijiang #include "x86/msr.h" 7*79e53994SYang Weijiang #include "vmalloc.h" 8*79e53994SYang Weijiang #include "alloc_page.h" 9*79e53994SYang Weijiang #include "fault_test.h" 10*79e53994SYang Weijiang 11*79e53994SYang Weijiang 12*79e53994SYang Weijiang static unsigned char user_stack[0x400]; 13*79e53994SYang Weijiang static unsigned long rbx, rsi, rdi, rsp, rbp, r8, r9, 14*79e53994SYang Weijiang r10, r11, r12, r13, r14, r15; 15*79e53994SYang Weijiang 16*79e53994SYang Weijiang static unsigned long expected_rip; 17*79e53994SYang Weijiang static int cp_count; 18*79e53994SYang Weijiang typedef u64 (*cet_test_func)(void); 19*79e53994SYang Weijiang 20*79e53994SYang Weijiang cet_test_func func; 21*79e53994SYang Weijiang 22*79e53994SYang Weijiang static u64 cet_shstk_func(void) 23*79e53994SYang Weijiang { 24*79e53994SYang Weijiang unsigned long *ret_addr, *ssp; 25*79e53994SYang Weijiang 26*79e53994SYang Weijiang /* rdsspq %rax */ 27*79e53994SYang Weijiang asm volatile (".byte 0xf3, 0x48, 0x0f, 0x1e, 0xc8" : "=a"(ssp)); 28*79e53994SYang Weijiang 29*79e53994SYang Weijiang asm("movq %%rbp,%0" : "=r"(ret_addr)); 30*79e53994SYang Weijiang printf("The return-address in shadow-stack = 0x%lx, in normal stack = 0x%lx\n", 31*79e53994SYang Weijiang *ssp, *(ret_addr + 1)); 32*79e53994SYang Weijiang 33*79e53994SYang Weijiang /* 34*79e53994SYang Weijiang * In below line, it modifies the return address, it'll trigger #CP 35*79e53994SYang Weijiang * while function is returning. The error-code is 0x1, meaning it's 36*79e53994SYang Weijiang * caused by a near RET instruction, and the execution is terminated 37*79e53994SYang Weijiang * when HW detects the violation. 38*79e53994SYang Weijiang */ 39*79e53994SYang Weijiang printf("Try to temper the return-address, this causes #CP on returning...\n"); 40*79e53994SYang Weijiang *(ret_addr + 1) = 0xdeaddead; 41*79e53994SYang Weijiang 42*79e53994SYang Weijiang return 0; 43*79e53994SYang Weijiang } 44*79e53994SYang Weijiang 45*79e53994SYang Weijiang static u64 cet_ibt_func(void) 46*79e53994SYang Weijiang { 47*79e53994SYang Weijiang /* 48*79e53994SYang Weijiang * In below assembly code, the first instruction at lable 2 is not 49*79e53994SYang Weijiang * endbr64, it'll trigger #CP with error code 0x3, and the execution 50*79e53994SYang Weijiang * is terminated when HW detects the violation. 51*79e53994SYang Weijiang */ 52*79e53994SYang Weijiang printf("No endbr64 instruction at jmp target, this triggers #CP...\n"); 53*79e53994SYang Weijiang asm volatile ("movq $2, %rcx\n" 54*79e53994SYang Weijiang "dec %rcx\n" 55*79e53994SYang Weijiang "leaq 2f, %rax\n" 56*79e53994SYang Weijiang "jmp *%rax \n" 57*79e53994SYang Weijiang "2:\n" 58*79e53994SYang Weijiang "dec %rcx\n"); 59*79e53994SYang Weijiang return 0; 60*79e53994SYang Weijiang } 61*79e53994SYang Weijiang 62*79e53994SYang Weijiang void test_func(void); 63*79e53994SYang Weijiang void test_func(void) { 64*79e53994SYang Weijiang asm volatile ( 65*79e53994SYang Weijiang /* IRET into user mode */ 66*79e53994SYang Weijiang "pushq %[user_ds]\n\t" 67*79e53994SYang Weijiang "pushq %[user_stack_top]\n\t" 68*79e53994SYang Weijiang "pushfq\n\t" 69*79e53994SYang Weijiang "pushq %[user_cs]\n\t" 70*79e53994SYang Weijiang "pushq $user_mode\n\t" 71*79e53994SYang Weijiang "iretq\n" 72*79e53994SYang Weijiang 73*79e53994SYang Weijiang "user_mode:\n\t" 74*79e53994SYang Weijiang "call *%[func]\n\t" 75*79e53994SYang Weijiang :: 76*79e53994SYang Weijiang [func]"m"(func), 77*79e53994SYang Weijiang [user_ds]"i"(USER_DS), 78*79e53994SYang Weijiang [user_cs]"i"(USER_CS), 79*79e53994SYang Weijiang [user_stack_top]"r"(user_stack + 80*79e53994SYang Weijiang sizeof(user_stack))); 81*79e53994SYang Weijiang } 82*79e53994SYang Weijiang 83*79e53994SYang Weijiang #define SAVE_REGS() \ 84*79e53994SYang Weijiang asm ("movq %%rbx, %0\t\n" \ 85*79e53994SYang Weijiang "movq %%rsi, %1\t\n" \ 86*79e53994SYang Weijiang "movq %%rdi, %2\t\n" \ 87*79e53994SYang Weijiang "movq %%rsp, %3\t\n" \ 88*79e53994SYang Weijiang "movq %%rbp, %4\t\n" \ 89*79e53994SYang Weijiang "movq %%r8, %5\t\n" \ 90*79e53994SYang Weijiang "movq %%r9, %6\t\n" \ 91*79e53994SYang Weijiang "movq %%r10, %7\t\n" \ 92*79e53994SYang Weijiang "movq %%r11, %8\t\n" \ 93*79e53994SYang Weijiang "movq %%r12, %9\t\n" \ 94*79e53994SYang Weijiang "movq %%r13, %10\t\n" \ 95*79e53994SYang Weijiang "movq %%r14, %11\t\n" \ 96*79e53994SYang Weijiang "movq %%r15, %12\t\n" :: \ 97*79e53994SYang Weijiang "m"(rbx), "m"(rsi), "m"(rdi), "m"(rsp), "m"(rbp), \ 98*79e53994SYang Weijiang "m"(r8), "m"(r9), "m"(r10), "m"(r11), "m"(r12), \ 99*79e53994SYang Weijiang "m"(r13), "m"(r14), "m"(r15)); 100*79e53994SYang Weijiang 101*79e53994SYang Weijiang #define RESTOR_REGS() \ 102*79e53994SYang Weijiang asm ("movq %0, %%rbx\t\n" \ 103*79e53994SYang Weijiang "movq %1, %%rsi\t\n" \ 104*79e53994SYang Weijiang "movq %2, %%rdi\t\n" \ 105*79e53994SYang Weijiang "movq %3, %%rsp\t\n" \ 106*79e53994SYang Weijiang "movq %4, %%rbp\t\n" \ 107*79e53994SYang Weijiang "movq %5, %%r8\t\n" \ 108*79e53994SYang Weijiang "movq %6, %%r9\t\n" \ 109*79e53994SYang Weijiang "movq %7, %%r10\t\n" \ 110*79e53994SYang Weijiang "movq %8, %%r11\t\n" \ 111*79e53994SYang Weijiang "movq %9, %%r12\t\n" \ 112*79e53994SYang Weijiang "movq %10, %%r13\t\n" \ 113*79e53994SYang Weijiang "movq %11, %%r14\t\n" \ 114*79e53994SYang Weijiang "movq %12, %%r15\t\n" ::\ 115*79e53994SYang Weijiang "m"(rbx), "m"(rsi), "m"(rdi), "m"(rsp), "m"(rbp), \ 116*79e53994SYang Weijiang "m"(r8), "m"(r9), "m"(r10), "m"(r11), "m"(r12), \ 117*79e53994SYang Weijiang "m"(r13), "m"(r14), "m"(r15)); 118*79e53994SYang Weijiang 119*79e53994SYang Weijiang #define RUN_TEST() \ 120*79e53994SYang Weijiang do { \ 121*79e53994SYang Weijiang SAVE_REGS(); \ 122*79e53994SYang Weijiang asm volatile ("pushq %%rax\t\n" \ 123*79e53994SYang Weijiang "leaq 1f(%%rip), %%rax\t\n" \ 124*79e53994SYang Weijiang "movq %%rax, %0\t\n" \ 125*79e53994SYang Weijiang "popq %%rax\t\n" \ 126*79e53994SYang Weijiang "call test_func\t\n" \ 127*79e53994SYang Weijiang "1:" ::"m"(expected_rip) : "rax", "rdi"); \ 128*79e53994SYang Weijiang RESTOR_REGS(); \ 129*79e53994SYang Weijiang } while (0) 130*79e53994SYang Weijiang 131*79e53994SYang Weijiang #define ENABLE_SHSTK_BIT 0x1 132*79e53994SYang Weijiang #define ENABLE_IBT_BIT 0x4 133*79e53994SYang Weijiang 134*79e53994SYang Weijiang static void handle_cp(struct ex_regs *regs) 135*79e53994SYang Weijiang { 136*79e53994SYang Weijiang cp_count++; 137*79e53994SYang Weijiang printf("In #CP exception handler, error_code = 0x%lx\n", 138*79e53994SYang Weijiang regs->error_code); 139*79e53994SYang Weijiang asm("jmp *%0" :: "m"(expected_rip)); 140*79e53994SYang Weijiang } 141*79e53994SYang Weijiang 142*79e53994SYang Weijiang int main(int ac, char **av) 143*79e53994SYang Weijiang { 144*79e53994SYang Weijiang char *shstk_virt; 145*79e53994SYang Weijiang unsigned long shstk_phys; 146*79e53994SYang Weijiang unsigned long *ptep; 147*79e53994SYang Weijiang pteval_t pte = 0; 148*79e53994SYang Weijiang 149*79e53994SYang Weijiang cp_count = 0; 150*79e53994SYang Weijiang if (!this_cpu_has(X86_FEATURE_SHSTK)) { 151*79e53994SYang Weijiang printf("SHSTK not enabled\n"); 152*79e53994SYang Weijiang return report_summary(); 153*79e53994SYang Weijiang } 154*79e53994SYang Weijiang 155*79e53994SYang Weijiang if (!this_cpu_has(X86_FEATURE_IBT)) { 156*79e53994SYang Weijiang printf("IBT not enabled\n"); 157*79e53994SYang Weijiang return report_summary(); 158*79e53994SYang Weijiang } 159*79e53994SYang Weijiang 160*79e53994SYang Weijiang setup_vm(); 161*79e53994SYang Weijiang setup_idt(); 162*79e53994SYang Weijiang handle_exception(21, handle_cp); 163*79e53994SYang Weijiang 164*79e53994SYang Weijiang /* Allocate one page for shadow-stack. */ 165*79e53994SYang Weijiang shstk_virt = alloc_vpage(); 166*79e53994SYang Weijiang shstk_phys = (unsigned long)virt_to_phys(alloc_page()); 167*79e53994SYang Weijiang 168*79e53994SYang Weijiang /* Install the new page. */ 169*79e53994SYang Weijiang pte = shstk_phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK; 170*79e53994SYang Weijiang install_pte(current_page_table(), 1, shstk_virt, pte, 0); 171*79e53994SYang Weijiang memset(shstk_virt, 0x0, PAGE_SIZE); 172*79e53994SYang Weijiang 173*79e53994SYang Weijiang /* Mark it as shadow-stack page. */ 174*79e53994SYang Weijiang ptep = get_pte_level(current_page_table(), shstk_virt, 1); 175*79e53994SYang Weijiang *ptep &= ~PT_WRITABLE_MASK; 176*79e53994SYang Weijiang *ptep |= PT_DIRTY_MASK; 177*79e53994SYang Weijiang 178*79e53994SYang Weijiang /* Flush the paging cache. */ 179*79e53994SYang Weijiang invlpg((void *)shstk_phys); 180*79e53994SYang Weijiang 181*79e53994SYang Weijiang /* Enable shadow-stack protection */ 182*79e53994SYang Weijiang wrmsr(MSR_IA32_U_CET, ENABLE_SHSTK_BIT); 183*79e53994SYang Weijiang 184*79e53994SYang Weijiang /* Store shadow-stack pointer. */ 185*79e53994SYang Weijiang wrmsr(MSR_IA32_PL3_SSP, (u64)(shstk_virt + 0x1000)); 186*79e53994SYang Weijiang 187*79e53994SYang Weijiang /* Enable CET master control bit in CR4. */ 188*79e53994SYang Weijiang write_cr4(read_cr4() | X86_CR4_CET); 189*79e53994SYang Weijiang 190*79e53994SYang Weijiang func = cet_shstk_func; 191*79e53994SYang Weijiang RUN_TEST(); 192*79e53994SYang Weijiang report(cp_count == 1, "Completed shadow-stack protection test successfully."); 193*79e53994SYang Weijiang cp_count = 0; 194*79e53994SYang Weijiang 195*79e53994SYang Weijiang /* Do user-mode indirect-branch-tracking test.*/ 196*79e53994SYang Weijiang func = cet_ibt_func; 197*79e53994SYang Weijiang /* Enable indirect-branch tracking */ 198*79e53994SYang Weijiang wrmsr(MSR_IA32_U_CET, ENABLE_IBT_BIT); 199*79e53994SYang Weijiang 200*79e53994SYang Weijiang RUN_TEST(); 201*79e53994SYang Weijiang report(cp_count == 1, "Completed Indirect-branch tracking test successfully."); 202*79e53994SYang Weijiang 203*79e53994SYang Weijiang write_cr4(read_cr4() & ~X86_CR4_CET); 204*79e53994SYang Weijiang wrmsr(MSR_IA32_U_CET, 0); 205*79e53994SYang Weijiang 206*79e53994SYang Weijiang return report_summary(); 207*79e53994SYang Weijiang } 208