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