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