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