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