1907bb0b6SArbel Moshe 2907bb0b6SArbel Moshe #include "x86/msr.h" 3907bb0b6SArbel Moshe #include "x86/processor.h" 4907bb0b6SArbel Moshe #include "x86/apic-defs.h" 5907bb0b6SArbel Moshe #include "x86/apic.h" 6907bb0b6SArbel Moshe #include "x86/desc.h" 7907bb0b6SArbel Moshe #include "x86/isr.h" 8907bb0b6SArbel Moshe #include "alloc.h" 9907bb0b6SArbel Moshe #include "setjmp.h" 10907bb0b6SArbel Moshe #include "usermode.h" 11907bb0b6SArbel Moshe #include "fault_test.h" 12907bb0b6SArbel Moshe 13907bb0b6SArbel Moshe #include "libcflat.h" 14907bb0b6SArbel Moshe #include <stdint.h> 15907bb0b6SArbel Moshe 16907bb0b6SArbel Moshe #define VMWARE_BACKDOOR_PMC_HOST_TSC 0x10000 17907bb0b6SArbel Moshe #define VMWARE_BACKDOOR_PMC_REAL_TIME 0x10001 18907bb0b6SArbel Moshe #define VMWARE_BACKDOOR_PMC_APPARENT_TIME 0x10002 19907bb0b6SArbel Moshe 20907bb0b6SArbel Moshe #define VMWARE_BACKDOOR_PORT 0x5658 21907bb0b6SArbel Moshe #define VMWARE_MAGIC 0x564D5868 22907bb0b6SArbel Moshe 23907bb0b6SArbel Moshe #define VMPORT_CMD_GETVERSION 0x0a 24907bb0b6SArbel Moshe #define VMPORT_CMD_ILLEGAL 0xfff 25907bb0b6SArbel Moshe 26907bb0b6SArbel Moshe #define VMPORT_DEFAULT_RETVAL 0xdeadbeef 27907bb0b6SArbel Moshe 28907bb0b6SArbel Moshe #define RANDOM_IO_PORT 0x1234 29907bb0b6SArbel Moshe 30907bb0b6SArbel Moshe struct backdoor_port_result { 31907bb0b6SArbel Moshe uint64_t rax; 32907bb0b6SArbel Moshe uint64_t rbx; 33907bb0b6SArbel Moshe uint64_t rcx; 34907bb0b6SArbel Moshe uint64_t rdx; 35907bb0b6SArbel Moshe }; 36907bb0b6SArbel Moshe 37907bb0b6SArbel Moshe static bool vmware_backdoor_port_callback(struct fault_test_arg *arg) 38907bb0b6SArbel Moshe { 39907bb0b6SArbel Moshe struct backdoor_port_result *res = 40907bb0b6SArbel Moshe (struct backdoor_port_result *) arg->retval; 41907bb0b6SArbel Moshe 42907bb0b6SArbel Moshe switch (arg->arg[2]) { 43907bb0b6SArbel Moshe case VMPORT_CMD_GETVERSION: 44907bb0b6SArbel Moshe return (res->rbx == VMWARE_MAGIC); 45907bb0b6SArbel Moshe case VMPORT_CMD_ILLEGAL: 46907bb0b6SArbel Moshe return (res->rbx == VMPORT_DEFAULT_RETVAL); 47907bb0b6SArbel Moshe } 48907bb0b6SArbel Moshe return false; 49907bb0b6SArbel Moshe } 50907bb0b6SArbel Moshe 51907bb0b6SArbel Moshe static uint64_t vmware_backdoor_port(uint64_t vmport, uint64_t vmport_magic, 52907bb0b6SArbel Moshe uint64_t command) 53907bb0b6SArbel Moshe { 54907bb0b6SArbel Moshe struct backdoor_port_result *res = 55907bb0b6SArbel Moshe (struct backdoor_port_result *) 56907bb0b6SArbel Moshe malloc(sizeof(struct backdoor_port_result)); 57907bb0b6SArbel Moshe 58907bb0b6SArbel Moshe res->rax = VMPORT_DEFAULT_RETVAL; 59907bb0b6SArbel Moshe res->rbx = VMPORT_DEFAULT_RETVAL; 60907bb0b6SArbel Moshe res->rcx = VMPORT_DEFAULT_RETVAL; 61907bb0b6SArbel Moshe res->rdx = VMPORT_DEFAULT_RETVAL; 62907bb0b6SArbel Moshe 63907bb0b6SArbel Moshe asm volatile( 64907bb0b6SArbel Moshe "mov %[rax], %%rax\n\t" 65907bb0b6SArbel Moshe "mov %[rdx], %%rdx\n\t" 66907bb0b6SArbel Moshe "mov %[rcx], %%rcx\n\t" 67907bb0b6SArbel Moshe "inl %%dx, %%eax\n\t" 68907bb0b6SArbel Moshe : 69907bb0b6SArbel Moshe "+a"(res->rax), 70907bb0b6SArbel Moshe "+b"(res->rbx), 71907bb0b6SArbel Moshe "+c"(res->rcx), 72907bb0b6SArbel Moshe "+d"(res->rdx) 73907bb0b6SArbel Moshe : 74907bb0b6SArbel Moshe [rax]"m"(vmport_magic), 75907bb0b6SArbel Moshe [rdx]"m"(vmport), 76907bb0b6SArbel Moshe [rcx]"m"(command) 77907bb0b6SArbel Moshe ); 78907bb0b6SArbel Moshe 79907bb0b6SArbel Moshe return (uint64_t) res; 80907bb0b6SArbel Moshe } 81907bb0b6SArbel Moshe 82907bb0b6SArbel Moshe #define FAULT true 83907bb0b6SArbel Moshe #define NO_FAULT false 84907bb0b6SArbel Moshe #define USER_MODE true 85907bb0b6SArbel Moshe #define KERNEL_MODE false 86907bb0b6SArbel Moshe 87907bb0b6SArbel Moshe #define RDPMC_ARG(n, m, sf) {.usermode = m, \ 88907bb0b6SArbel Moshe .func = (test_fault_func) rdpmc, .fault_vector = GP_VECTOR, \ 89907bb0b6SArbel Moshe .should_fault = sf, .arg = {n, 0, 0, 0}, .callback = NULL} 90907bb0b6SArbel Moshe 91907bb0b6SArbel Moshe #define RDPMC_TEST(name, a, m, sf) FAULT_TEST("rdpmc_test: "name, \ 92907bb0b6SArbel Moshe RDPMC_ARG(a, m, sf)) 93907bb0b6SArbel Moshe 94907bb0b6SArbel Moshe #define PORT_ARG(a, b, c, m, sf) {.usermode = m, \ 95907bb0b6SArbel Moshe .func = (test_fault_func) vmware_backdoor_port, \ 96907bb0b6SArbel Moshe .fault_vector = GP_VECTOR, .should_fault = sf, .arg = {a, b, c, 0}, \ 97907bb0b6SArbel Moshe .callback = vmware_backdoor_port_callback} 98907bb0b6SArbel Moshe 99907bb0b6SArbel Moshe #define PORT_TEST(name, a, b, c, m, sf) FAULT_TEST("port_test: "name, \ 100907bb0b6SArbel Moshe PORT_ARG(a, b, c, m, sf)) 101907bb0b6SArbel Moshe 102907bb0b6SArbel Moshe 103907bb0b6SArbel Moshe struct fault_test vmware_backdoor_tests[] = { 104907bb0b6SArbel Moshe RDPMC_TEST("HOST_TSC kernel", VMWARE_BACKDOOR_PMC_HOST_TSC, 105907bb0b6SArbel Moshe KERNEL_MODE, NO_FAULT), 106907bb0b6SArbel Moshe RDPMC_TEST("REAL_TIME kernel", VMWARE_BACKDOOR_PMC_REAL_TIME, 107907bb0b6SArbel Moshe KERNEL_MODE, NO_FAULT), 108907bb0b6SArbel Moshe RDPMC_TEST("APPARENT_TIME kernel", VMWARE_BACKDOOR_PMC_APPARENT_TIME, 109907bb0b6SArbel Moshe KERNEL_MODE, NO_FAULT), 110907bb0b6SArbel Moshe RDPMC_TEST("HOST_TSC user", VMWARE_BACKDOOR_PMC_HOST_TSC, 111907bb0b6SArbel Moshe USER_MODE, NO_FAULT), 112907bb0b6SArbel Moshe RDPMC_TEST("REAL_TIME user", VMWARE_BACKDOOR_PMC_REAL_TIME, 113907bb0b6SArbel Moshe USER_MODE, NO_FAULT), 114907bb0b6SArbel Moshe RDPMC_TEST("APPARENT_TIME user", VMWARE_BACKDOOR_PMC_APPARENT_TIME, 115907bb0b6SArbel Moshe USER_MODE, NO_FAULT), 116907bb0b6SArbel Moshe RDPMC_TEST("RANDOM PMC user", 0xfff, USER_MODE, FAULT), 117907bb0b6SArbel Moshe 118907bb0b6SArbel Moshe PORT_TEST("CMD_GETVERSION user", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, 119907bb0b6SArbel Moshe VMPORT_CMD_GETVERSION, USER_MODE, NO_FAULT), 120907bb0b6SArbel Moshe PORT_TEST("CMD_GETVERSION kernel", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, 121907bb0b6SArbel Moshe VMPORT_CMD_GETVERSION, KERNEL_MODE, NO_FAULT), 122907bb0b6SArbel Moshe PORT_TEST("CMD_ILLEGAL user", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, 123907bb0b6SArbel Moshe VMPORT_CMD_ILLEGAL, USER_MODE, NO_FAULT), 124907bb0b6SArbel Moshe PORT_TEST("RANDOM port user", RANDOM_IO_PORT, VMWARE_MAGIC, 0xfff, 125907bb0b6SArbel Moshe USER_MODE, FAULT), 126907bb0b6SArbel Moshe { NULL }, 127907bb0b6SArbel Moshe }; 128907bb0b6SArbel Moshe 129907bb0b6SArbel Moshe /* 130907bb0b6SArbel Moshe * Set TSS IO Perm to throw GP on RANDOM_IO_PORT and VMWARE_BACKDOOR_PORT 131907bb0b6SArbel Moshe * from User Mode 132907bb0b6SArbel Moshe */ 133907bb0b6SArbel Moshe static void set_tss_ioperm(void) 134907bb0b6SArbel Moshe { 135*a7f32d87SPaolo Bonzini gdt_entry_t *tss_entry; 136907bb0b6SArbel Moshe tss64_t *tss; 137907bb0b6SArbel Moshe unsigned char *ioperm_bitmap; 138*a7f32d87SPaolo Bonzini u16 tr = str(); 139907bb0b6SArbel Moshe 140*a7f32d87SPaolo Bonzini tss_entry = get_tss_descr(); 141*a7f32d87SPaolo Bonzini tss = (tss64_t *)get_gdt_entry_base(tss_entry); 142907bb0b6SArbel Moshe tss->iomap_base = sizeof(*tss); 143907bb0b6SArbel Moshe ioperm_bitmap = ((unsigned char *)tss+tss->iomap_base); 144907bb0b6SArbel Moshe 145907bb0b6SArbel Moshe /* We want GP on RANDOM_IO_PORT and VMWARE_BACKDOOR_PORT */ 146907bb0b6SArbel Moshe ioperm_bitmap[RANDOM_IO_PORT / 8] |= 147907bb0b6SArbel Moshe 1 << (RANDOM_IO_PORT % 8); 148907bb0b6SArbel Moshe ioperm_bitmap[VMWARE_BACKDOOR_PORT / 8] |= 149907bb0b6SArbel Moshe 1 << (VMWARE_BACKDOOR_PORT % 8); 150*a7f32d87SPaolo Bonzini tss_entry->type &= ~DESC_BUSY; 151907bb0b6SArbel Moshe 152907bb0b6SArbel Moshe /* Update TSS */ 153907bb0b6SArbel Moshe ltr(tr); 154907bb0b6SArbel Moshe } 155907bb0b6SArbel Moshe 156907bb0b6SArbel Moshe static void check_vmware_backdoors(void) 157907bb0b6SArbel Moshe { 158907bb0b6SArbel Moshe int i; 159907bb0b6SArbel Moshe 160907bb0b6SArbel Moshe /* Disable Permissions for IO PORTS */ 161907bb0b6SArbel Moshe set_tss_ioperm(); 162907bb0b6SArbel Moshe /* Disable Permission to run rdpmc from user mode */ 163907bb0b6SArbel Moshe write_cr4(read_cr4() & ~X86_CR4_PCE); 164907bb0b6SArbel Moshe 165907bb0b6SArbel Moshe report_prefix_push("vmware_backdoors"); 166907bb0b6SArbel Moshe 167907bb0b6SArbel Moshe for (i = 0; vmware_backdoor_tests[i].name != NULL; i++) 168907bb0b6SArbel Moshe test_run(&vmware_backdoor_tests[i]); 169907bb0b6SArbel Moshe 170907bb0b6SArbel Moshe report_prefix_pop(); 171907bb0b6SArbel Moshe } 172907bb0b6SArbel Moshe 173907bb0b6SArbel Moshe int main(int ac, char **av) 174907bb0b6SArbel Moshe { 175907bb0b6SArbel Moshe setup_vm(); 176907bb0b6SArbel Moshe 177907bb0b6SArbel Moshe check_vmware_backdoors(); 178907bb0b6SArbel Moshe 179907bb0b6SArbel Moshe return report_summary(); 180907bb0b6SArbel Moshe } 181