Xen Test Framework
main.c
Go to the documentation of this file.
1 
32 #include <xtf.h>
33 
34 const char test_title[] = "Test PV FSGSBASE behaviour";
35 
36 static 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 
49 static 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 
62 static 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 
74 static 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 
86 static 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 
112 static 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  */
149 static 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 
164 void 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  */
187  test_fsgsbase_insns(true);
188 
189  if ( !cpu_has_fsgsbase )
190  {
191  /* If the FSGSBASE feature isn't visible, check we can't turn it on. */
192  if ( !pv_write_cr4_safe(cr4 | X86_CR4_FSGSBASE) )
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. */
199  if ( pv_write_cr4_safe(cr4 | X86_CR4_FSGSBASE) )
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. */
213  test_fsgsbase_insns(true);
214 
215  xtf_success(NULL);
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  */
unsigned int exinfo_t
Packed exception and error code information.
Definition: exinfo.h:19
static exinfo_t stub_rdfsbase(unsigned long unused)
Definition: main.c:36
static exinfo_t stub_wrgsbase(unsigned long val)
Definition: main.c:74
#define X86_CR4_FSGSBASE
Definition: processor.h:58
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 ARRAY_SIZE(a)
Definition: lib.h:8
exinfo_t exp
Definition: main.c:42
#define cpu_has_fsgsbase
Definition: cpuid.h:92
static bool pv_write_cr4_safe(unsigned long val)
Definition: main.c:149
#define NULL
Definition: stddef.h:12
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
static exinfo_t stub_wrfsbase(unsigned long val)
Definition: main.c:62
void test_main(void)
To be implemented by each test, as its entry point.
Definition: main.c:137
void xtf_failure(const char *fmt,...)
Report a test failure.
Definition: report.c:94
#define GP
static void test_fsgsbase_insns(bool should_ud)
Definition: main.c:86
void xtf_skip(const char *fmt,...)
Report a test skip.
Definition: report.c:66
static unsigned long read_cr4(void)
Definition: lib.h:252
const char test_title[]
The title of the test.
Definition: main.c:14
static bool write_cr4_safe(unsigned long cr4)
Definition: lib.h:290
const char * name
Definition: main.c:41
Definition: main.c:38
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
#define EXINFO_SYM(exc, ec)
Definition: exinfo.h:29
static exinfo_t stub_rdgsbase(unsigned long unused)
Definition: main.c:49
static void test_wrfsbase_values(void)
Definition: main.c:112
unsigned long(* fn)(unsigned long)
Definition: main.c:40
static const struct test tests[]
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38