xref: /kvm-unit-tests/x86/vmware_backdoors.c (revision 2c96b77ec9d3b1fcec7525174e23a6240ee05949)
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