Xen Test Framework
main.c
Go to the documentation of this file.
1
32#include <xtf.h>
33
34const char test_title[] = "Test PV FSGSBASE behaviour";
35
36static exinfo_t stub_rdfsbase(unsigned long unused)
37{
38 unsigned long tmp;
39 exinfo_t fault = 0;
40
41 asm volatile ("1: rdfsbase %[val]; 2:"
42 _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
43 : "+a" (fault), [val] "=r" (tmp)
44 : [rec] "p" (ex_record_fault_eax));
45
46 return fault;
47}
48
49static exinfo_t stub_rdgsbase(unsigned long unused)
50{
51 unsigned long tmp;
52 exinfo_t fault = 0;
53
54 asm volatile ("1: rdgsbase %[val]; 2:"
55 _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
56 : "+a" (fault), [val] "=r" (tmp)
57 : [rec] "p" (ex_record_fault_eax));
58
59 return fault;
60}
61
62static exinfo_t stub_wrfsbase(unsigned long val)
63{
64 exinfo_t fault = 0;
65
66 asm volatile ("1: wrfsbase %[val]; 2:"
67 _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
68 : "+a" (fault)
69 : [val] "r" (val), [rec] "p" (ex_record_fault_eax));
70
71 return fault;
72}
73
74static exinfo_t stub_wrgsbase(unsigned long val)
75{
76 exinfo_t fault = 0;
77
78 asm volatile ("1: wrgsbase %[val]; 2:"
79 _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
80 : "+a" (fault)
81 : [val] "r" (val), [rec] "p" (ex_record_fault_eax));
82
83 return fault;
84}
85
86static void test_fsgsbase_insns(bool should_ud)
87{
88 static const struct test {
89 const char *name;
90 exinfo_t (*fn)(unsigned long);
91 } tests[] = {
92 { "rdfsbase", stub_rdfsbase },
93 { "rdgsbase", stub_rdgsbase },
94 { "wrfsbase", stub_wrfsbase },
95 { "wrgsbase", stub_wrgsbase },
96 };
97 unsigned int i;
98 exinfo_t exp = should_ud ? EXINFO_SYM(UD, 0) : 0;
99
100 for ( i = 0; i < ARRAY_SIZE(tests); ++i )
101 {
102 const struct test *t = &tests[i];
103 exinfo_t res = t->fn(0);
104
105 if ( res != exp )
106 xtf_failure("Fail: Testing '%s'\n"
107 " expected %pe, got %pe\n",
108 t->name, _p(exp), _p(res));
109 }
110}
111
112static void test_wrfsbase_values(void)
113{
114 static const struct test {
115 unsigned long val;
116 exinfo_t fault;
117 } tests[] = {
118 { 0x0000000000000000ul, 0 },
119 { 0x00007ffffffffffful, 0 },
120 { 0x0000800000000000ul, EXINFO_SYM(GP, 0) },
121 { 0x7ffffffffffffffful, EXINFO_SYM(GP, 0) },
122 { 0x8000000000000000ul, EXINFO_SYM(GP, 0) },
123 { 0xffff7ffffffffffful, EXINFO_SYM(GP, 0) },
124 { 0xffff800000000000ul, 0 },
125 { 0xfffffffffffffffful, 0 },
126 };
127 unsigned int i;
128
129 for ( i = 0; i < ARRAY_SIZE(tests); ++i )
130 {
131 const struct test *t = &tests[i];
132 exinfo_t res = stub_wrfsbase(t->val);
133
134 if ( res != t->fault )
135 xtf_failure("Fail: Testing WRFSBASE %016lx \n"
136 " expected %pe, got %pe\n",
137 t->val , _p(t->fault), _p(res));
138 }
139}
140
141/*
142 * Bad updates to CR4 should fault, but at the time of writing, Xen squashes
143 * all faults and breaks the use of the *_safe() functions, and drops the
144 * feature.
145 *
146 * Wrap write_cr4_safe() with a variant which reads cr4 back, to see if write
147 * fully took effect.
148 */
149static bool pv_write_cr4_safe(unsigned long val)
150{
151 unsigned long old = read_cr4(), changed = old ^ val;
152 bool fault = write_cr4_safe(val);
153
154 if ( !fault )
155 {
156 unsigned long new = read_cr4();
157
158 fault = (old ^ new) != changed;
159 }
160
161 return fault;
162}
163
164void test_main(void)
165{
166 unsigned long cr4;
167
168 if ( !cpu_has_fsgsbase )
169 xtf_skip("FSGSBASE support not detected\n");
170
171 /* Check that CR4.FSGSBASE is clear to begin with. */
172 cr4 = read_cr4();
173 if ( cr4 & X86_CR4_FSGSBASE )
174 {
175 xtf_failure("Fail: Initial CR4.FSGSBASE state should be clear\n");
176
177 /* Try turning CR4.FSGSBASE off, to continue the test. */
178 cr4 &= ~X86_CR4_FSGSBASE;
179 if ( pv_write_cr4_safe(cr4) )
180 return xtf_failure("Fail: Fault while trying to clear CR4.FSGSBASE\n");
181 }
182
183 /*
184 * Check that the {RD,WR}{FS,GS}BASE instructions are disabled. When
185 * vulnerable to XSA-293, this check will fail.
186 */
188
189 if ( !cpu_has_fsgsbase )
190 {
191 /* If the FSGSBASE feature isn't visible, check we can't turn it on. */
193 xtf_failure("Fail: Able to set CR4.FSGSBASE without the feature\n");
194
195 return;
196 }
197
198 /* Check we can turn CR4.FSGSBASE on. */
200 xtf_failure("Fail: Unable to enable CR4.FSGSBASE\n");
201
202 /* Check that {RD,WR}{FS,GS}BASE instructions are enabled. */
203 test_fsgsbase_insns(false);
204
205 /* Check that WRFSBASE faults on appropriate values. */
207
208 /* Check we can turn CR4.FSGSBASE off again. */
209 if ( pv_write_cr4_safe(cr4) )
210 xtf_failure("Fail: Unable to enable CR4.FSGSBASE\n");
211
212 /* Check that {RD,WR}{FS,GS}BASE instructions are disabled again. */
214
216}
217
218/*
219 * Local variables:
220 * mode: C
221 * c-file-style: "BSD"
222 * c-basic-offset: 4
223 * tab-width: 4
224 * indent-tabs-mode: nil
225 * End:
226 */
bool ex_record_fault_eax(struct cpu_regs *regs, const struct extable_entry *ex)
Record the current fault in %eax.
Definition: extable.c:8
#define cpu_has_fsgsbase
Definition: cpuid.h:93
static unsigned long read_cr4(void)
Definition: lib.h:252
static bool write_cr4_safe(unsigned long cr4)
Definition: lib.h:290
void test_main(void)
To be implemented by each test, as its entry point.
Definition: main.c:110
const char test_title[]
The title of the test.
Definition: main.c:24
#define EXINFO_SYM(exc, ec)
Definition: exinfo.h:29
unsigned int exinfo_t
Packed exception and error code information.
Definition: exinfo.h:19
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38
#define ARRAY_SIZE(a)
Definition: lib.h:8
#define GP
static const struct test tests[]
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
#define X86_CR4_FSGSBASE
Definition: processor.h:58
static bool pv_write_cr4_safe(unsigned long val)
Definition: main.c:149
static exinfo_t stub_wrfsbase(unsigned long val)
Definition: main.c:62
static void test_wrfsbase_values(void)
Definition: main.c:112
static exinfo_t stub_rdgsbase(unsigned long unused)
Definition: main.c:49
static exinfo_t stub_rdfsbase(unsigned long unused)
Definition: main.c:36
static void test_fsgsbase_insns(bool should_ud)
Definition: main.c:86
static exinfo_t stub_wrgsbase(unsigned long val)
Definition: main.c:74
void xtf_failure(const char *fmt,...)
Report a test failure.
Definition: report.c:94
void xtf_skip(const char *fmt,...)
Report a test skip.
Definition: report.c:66
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
#define NULL
Definition: stddef.h:12
Definition: main.c:39
exinfo_t exp
Definition: main.c:42
unsigned long(* fn)(unsigned long)
Definition: main.c:40
const char * name
Definition: main.c:41