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
vmware_backdoor_port_callback(struct fault_test_arg * arg)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
vmware_backdoor_port(uint64_t vmport,uint64_t vmport_magic,uint64_t command)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 */
set_tss_ioperm(void)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
check_vmware_backdoors(void)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
main(int ac,char ** av)174 int main(int ac, char **av)
175 {
176 setup_vm();
177
178 check_vmware_backdoors();
179
180 return report_summary();
181 }
182