1 2 #include "x86/msr.h" 3 #include "x86/processor.h" 4 #include "x86/apic-defs.h" 5 #include "x86/apic.h" 6 #include "x86/desc.h" 7 #include "x86/isr.h" 8 #include "alloc.h" 9 #include "vmalloc.h" 10 #include "setjmp.h" 11 #include "usermode.h" 12 #include "fault_test.h" 13 14 #include "libcflat.h" 15 #include <stdint.h> 16 17 #define VMWARE_BACKDOOR_PMC_HOST_TSC 0x10000 18 #define VMWARE_BACKDOOR_PMC_REAL_TIME 0x10001 19 #define VMWARE_BACKDOOR_PMC_APPARENT_TIME 0x10002 20 21 #define VMWARE_BACKDOOR_PORT 0x5658 22 #define VMWARE_MAGIC 0x564D5868 23 24 #define VMPORT_CMD_GETVERSION 0x0a 25 #define VMPORT_CMD_ILLEGAL 0xfff 26 27 #define VMPORT_DEFAULT_RETVAL 0xdeadbeef 28 29 #define RANDOM_IO_PORT 0x1234 30 31 struct backdoor_port_result { 32 uint64_t rax; 33 uint64_t rbx; 34 uint64_t rcx; 35 uint64_t rdx; 36 }; 37 38 static bool vmware_backdoor_port_callback(struct fault_test_arg *arg) 39 { 40 struct backdoor_port_result *res = 41 (struct backdoor_port_result *) arg->retval; 42 43 switch (arg->arg[2]) { 44 case VMPORT_CMD_GETVERSION: 45 return (res->rbx == VMWARE_MAGIC); 46 case VMPORT_CMD_ILLEGAL: 47 return (res->rbx == VMPORT_DEFAULT_RETVAL); 48 } 49 return false; 50 } 51 52 static uint64_t vmware_backdoor_port(uint64_t vmport, uint64_t vmport_magic, 53 uint64_t command) 54 { 55 struct backdoor_port_result *res = 56 (struct backdoor_port_result *) 57 malloc(sizeof(struct backdoor_port_result)); 58 59 res->rax = VMPORT_DEFAULT_RETVAL; 60 res->rbx = VMPORT_DEFAULT_RETVAL; 61 res->rcx = VMPORT_DEFAULT_RETVAL; 62 res->rdx = VMPORT_DEFAULT_RETVAL; 63 64 asm volatile( 65 "mov %[rax], %%rax\n\t" 66 "mov %[rdx], %%rdx\n\t" 67 "mov %[rcx], %%rcx\n\t" 68 "inl %%dx, %%eax\n\t" 69 : 70 "+a"(res->rax), 71 "+b"(res->rbx), 72 "+c"(res->rcx), 73 "+d"(res->rdx) 74 : 75 [rax]"m"(vmport_magic), 76 [rdx]"m"(vmport), 77 [rcx]"m"(command) 78 ); 79 80 return (uint64_t) res; 81 } 82 83 #define FAULT true 84 #define NO_FAULT false 85 #define USER_MODE true 86 #define KERNEL_MODE false 87 88 #define RDPMC_ARG(n, m, sf) {.usermode = m, \ 89 .func = (test_fault_func) rdpmc, .fault_vector = GP_VECTOR, \ 90 .should_fault = sf, .arg = {n, 0, 0, 0}, .callback = NULL} 91 92 #define RDPMC_TEST(name, a, m, sf) FAULT_TEST("rdpmc_test: "name, \ 93 RDPMC_ARG(a, m, sf)) 94 95 #define PORT_ARG(a, b, c, m, sf) {.usermode = m, \ 96 .func = (test_fault_func) vmware_backdoor_port, \ 97 .fault_vector = GP_VECTOR, .should_fault = sf, .arg = {a, b, c, 0}, \ 98 .callback = vmware_backdoor_port_callback} 99 100 #define PORT_TEST(name, a, b, c, m, sf) FAULT_TEST("port_test: "name, \ 101 PORT_ARG(a, b, c, m, sf)) 102 103 104 struct fault_test vmware_backdoor_tests[] = { 105 RDPMC_TEST("HOST_TSC kernel", VMWARE_BACKDOOR_PMC_HOST_TSC, 106 KERNEL_MODE, NO_FAULT), 107 RDPMC_TEST("REAL_TIME kernel", VMWARE_BACKDOOR_PMC_REAL_TIME, 108 KERNEL_MODE, NO_FAULT), 109 RDPMC_TEST("APPARENT_TIME kernel", VMWARE_BACKDOOR_PMC_APPARENT_TIME, 110 KERNEL_MODE, NO_FAULT), 111 RDPMC_TEST("HOST_TSC user", VMWARE_BACKDOOR_PMC_HOST_TSC, 112 USER_MODE, NO_FAULT), 113 RDPMC_TEST("REAL_TIME user", VMWARE_BACKDOOR_PMC_REAL_TIME, 114 USER_MODE, NO_FAULT), 115 RDPMC_TEST("APPARENT_TIME user", VMWARE_BACKDOOR_PMC_APPARENT_TIME, 116 USER_MODE, NO_FAULT), 117 RDPMC_TEST("RANDOM PMC user", 0xfff, USER_MODE, FAULT), 118 119 PORT_TEST("CMD_GETVERSION user", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, 120 VMPORT_CMD_GETVERSION, USER_MODE, NO_FAULT), 121 PORT_TEST("CMD_GETVERSION kernel", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, 122 VMPORT_CMD_GETVERSION, KERNEL_MODE, NO_FAULT), 123 PORT_TEST("CMD_ILLEGAL user", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, 124 VMPORT_CMD_ILLEGAL, USER_MODE, NO_FAULT), 125 PORT_TEST("RANDOM port user", RANDOM_IO_PORT, VMWARE_MAGIC, 0xfff, 126 USER_MODE, FAULT), 127 { NULL }, 128 }; 129 130 /* 131 * Set TSS IO Perm to throw GP on RANDOM_IO_PORT and VMWARE_BACKDOOR_PORT 132 * from User Mode 133 */ 134 static void set_tss_ioperm(void) 135 { 136 gdt_entry_t *tss_entry; 137 tss64_t *tss; 138 unsigned char *ioperm_bitmap; 139 u16 tr = str(); 140 141 tss_entry = get_tss_descr(); 142 tss = (tss64_t *)get_gdt_entry_base(tss_entry); 143 tss->iomap_base = sizeof(*tss); 144 ioperm_bitmap = ((unsigned char *)tss+tss->iomap_base); 145 146 /* We want GP on RANDOM_IO_PORT and VMWARE_BACKDOOR_PORT */ 147 ioperm_bitmap[RANDOM_IO_PORT / 8] |= 148 1 << (RANDOM_IO_PORT % 8); 149 ioperm_bitmap[VMWARE_BACKDOOR_PORT / 8] |= 150 1 << (VMWARE_BACKDOOR_PORT % 8); 151 tss_entry->type &= ~DESC_BUSY; 152 153 /* Update TSS */ 154 ltr(tr); 155 } 156 157 static void check_vmware_backdoors(void) 158 { 159 int i; 160 161 /* Disable Permissions for IO PORTS */ 162 set_tss_ioperm(); 163 /* Disable Permission to run rdpmc from user mode */ 164 write_cr4(read_cr4() & ~X86_CR4_PCE); 165 166 report_prefix_push("vmware_backdoors"); 167 168 for (i = 0; vmware_backdoor_tests[i].name != NULL; i++) 169 test_run(&vmware_backdoor_tests[i]); 170 171 report_prefix_pop(); 172 } 173 174 int main(int ac, char **av) 175 { 176 setup_vm(); 177 178 check_vmware_backdoors(); 179 180 return report_summary(); 181 } 182