1*19c3b8c2SApple OSS Distributions #include <darwintest.h>
2*19c3b8c2SApple OSS Distributions #include <darwintest_utils.h>
3*19c3b8c2SApple OSS Distributions
4*19c3b8c2SApple OSS Distributions #include <sys/types.h>
5*19c3b8c2SApple OSS Distributions #include <sys/sysctl.h>
6*19c3b8c2SApple OSS Distributions #include <mach/mach.h>
7*19c3b8c2SApple OSS Distributions #include <mach/mach_vm.h>
8*19c3b8c2SApple OSS Distributions #include <mach/vm_types.h>
9*19c3b8c2SApple OSS Distributions #include <sys/mman.h>
10*19c3b8c2SApple OSS Distributions #include <unistd.h>
11*19c3b8c2SApple OSS Distributions #include <TargetConditionals.h>
12*19c3b8c2SApple OSS Distributions
13*19c3b8c2SApple OSS Distributions T_GLOBAL_META(
14*19c3b8c2SApple OSS Distributions T_META_NAMESPACE("xnu.vm"),
15*19c3b8c2SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
16*19c3b8c2SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("VM")
17*19c3b8c2SApple OSS Distributions );
18*19c3b8c2SApple OSS Distributions
19*19c3b8c2SApple OSS Distributions struct child_rc {
20*19c3b8c2SApple OSS Distributions int ret;
21*19c3b8c2SApple OSS Distributions int sig;
22*19c3b8c2SApple OSS Distributions };
23*19c3b8c2SApple OSS Distributions
24*19c3b8c2SApple OSS Distributions static struct child_rc
25*19c3b8c2SApple OSS Distributions fork_child_test(void (^block)(void))
26*19c3b8c2SApple OSS Distributions {
27*19c3b8c2SApple OSS Distributions struct child_rc rc = { };
28*19c3b8c2SApple OSS Distributions pid_t child_pid;
29*19c3b8c2SApple OSS Distributions
30*19c3b8c2SApple OSS Distributions child_pid = fork();
31*19c3b8c2SApple OSS Distributions
32*19c3b8c2SApple OSS Distributions if (child_pid == 0) {
33*19c3b8c2SApple OSS Distributions block();
34*19c3b8c2SApple OSS Distributions exit(0);
35*19c3b8c2SApple OSS Distributions }
36*19c3b8c2SApple OSS Distributions
37*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(child_pid, "fork process");
38*19c3b8c2SApple OSS Distributions
39*19c3b8c2SApple OSS Distributions /* wait for child process to exit */
40*19c3b8c2SApple OSS Distributions dt_waitpid(child_pid, &rc.ret, &rc.sig, 30);
41*19c3b8c2SApple OSS Distributions return rc;
42*19c3b8c2SApple OSS Distributions }
43*19c3b8c2SApple OSS Distributions
44*19c3b8c2SApple OSS Distributions static mach_vm_address_t
get_permanent_mapping(mach_vm_size_t size)45*19c3b8c2SApple OSS Distributions get_permanent_mapping(mach_vm_size_t size)
46*19c3b8c2SApple OSS Distributions {
47*19c3b8c2SApple OSS Distributions kern_return_t kr;
48*19c3b8c2SApple OSS Distributions mach_vm_address_t addr;
49*19c3b8c2SApple OSS Distributions
50*19c3b8c2SApple OSS Distributions kr = mach_vm_allocate(mach_task_self(), &addr, size,
51*19c3b8c2SApple OSS Distributions VM_FLAGS_ANYWHERE | VM_FLAGS_PERMANENT);
52*19c3b8c2SApple OSS Distributions
53*19c3b8c2SApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "mach_vm_allocate(%lld, PERMANENT) == %p",
54*19c3b8c2SApple OSS Distributions size, (void *)addr);
55*19c3b8c2SApple OSS Distributions
56*19c3b8c2SApple OSS Distributions *(int *)addr = 42;
57*19c3b8c2SApple OSS Distributions
58*19c3b8c2SApple OSS Distributions kr = mach_vm_protect(mach_task_self(), addr, size, FALSE, VM_PROT_READ);
59*19c3b8c2SApple OSS Distributions
60*19c3b8c2SApple OSS Distributions T_EXPECT_MACH_SUCCESS(kr, "mach_vm_protect(PERMANENT, READ)");
61*19c3b8c2SApple OSS Distributions
62*19c3b8c2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(*(int *)addr, 42, "we can still read what we wrote");
63*19c3b8c2SApple OSS Distributions
64*19c3b8c2SApple OSS Distributions return addr;
65*19c3b8c2SApple OSS Distributions }
66*19c3b8c2SApple OSS Distributions
67*19c3b8c2SApple OSS Distributions T_DECL(permanent_mapping, "check permanent mappings semantics")
68*19c3b8c2SApple OSS Distributions {
69*19c3b8c2SApple OSS Distributions kern_return_t kr;
70*19c3b8c2SApple OSS Distributions mach_vm_size_t size = 1 << 20;
71*19c3b8c2SApple OSS Distributions struct child_rc rc;
72*19c3b8c2SApple OSS Distributions
73*19c3b8c2SApple OSS Distributions T_LOG("try to bypass permanent mappings with VM_FLAGS_OVERWRITE");
74*19c3b8c2SApple OSS Distributions rc = fork_child_test(^{
75*19c3b8c2SApple OSS Distributions mach_vm_address_t addr, addr2;
76*19c3b8c2SApple OSS Distributions kern_return_t kr2;
77*19c3b8c2SApple OSS Distributions
78*19c3b8c2SApple OSS Distributions addr = get_permanent_mapping(size);
79*19c3b8c2SApple OSS Distributions
80*19c3b8c2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(*(int *)addr, 42, "we can still read what we wrote");
81*19c3b8c2SApple OSS Distributions
82*19c3b8c2SApple OSS Distributions addr2 = addr;
83*19c3b8c2SApple OSS Distributions kr2 = mach_vm_allocate(mach_task_self(), &addr2, size,
84*19c3b8c2SApple OSS Distributions VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE);
85*19c3b8c2SApple OSS Distributions
86*19c3b8c2SApple OSS Distributions /*
87*19c3b8c2SApple OSS Distributions * because the permanent mapping wasn't removed,
88*19c3b8c2SApple OSS Distributions * we should get an error.
89*19c3b8c2SApple OSS Distributions */
90*19c3b8c2SApple OSS Distributions T_ASSERT_MACH_ERROR(kr2, KERN_NO_SPACE,
91*19c3b8c2SApple OSS Distributions "mach_vm_allocate(VM_FLAGS_OVERWRITE)");
92*19c3b8c2SApple OSS Distributions
93*19c3b8c2SApple OSS Distributions /*
94*19c3b8c2SApple OSS Distributions * because the permanent mapping was neutered,
95*19c3b8c2SApple OSS Distributions * accessing it should crash.
96*19c3b8c2SApple OSS Distributions */
97*19c3b8c2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(*(int *)addr, 42, "we can still read what we wrote");
98*19c3b8c2SApple OSS Distributions });
99*19c3b8c2SApple OSS Distributions T_EXPECT_EQ(rc.sig, SIGBUS, "accessing the mapping caused a SIGBUS");
100*19c3b8c2SApple OSS Distributions
101*19c3b8c2SApple OSS Distributions T_LOG("try to bypass permanent mappings with a VM_PROT_COPY mprotect");
102*19c3b8c2SApple OSS Distributions rc = fork_child_test(^{
103*19c3b8c2SApple OSS Distributions kern_return_t kr2;
104*19c3b8c2SApple OSS Distributions mach_vm_address_t addr;
105*19c3b8c2SApple OSS Distributions
106*19c3b8c2SApple OSS Distributions addr = get_permanent_mapping(size);
107*19c3b8c2SApple OSS Distributions
108*19c3b8c2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(*(int *)addr, 42, "we can still read what we wrote");
109*19c3b8c2SApple OSS Distributions
110*19c3b8c2SApple OSS Distributions kr2 = mach_vm_protect(mach_task_self(), addr, size, TRUE,
111*19c3b8c2SApple OSS Distributions VM_PROT_COPY | VM_PROT_DEFAULT);
112*19c3b8c2SApple OSS Distributions
113*19c3b8c2SApple OSS Distributions /*
114*19c3b8c2SApple OSS Distributions * because the permanent mapping wasn't removed,
115*19c3b8c2SApple OSS Distributions * we should get an error.
116*19c3b8c2SApple OSS Distributions */
117*19c3b8c2SApple OSS Distributions T_ASSERT_MACH_ERROR(kr2, KERN_NO_SPACE,
118*19c3b8c2SApple OSS Distributions "mach_vm_protect(VM_PROT_COPY)");
119*19c3b8c2SApple OSS Distributions
120*19c3b8c2SApple OSS Distributions /*
121*19c3b8c2SApple OSS Distributions * because the permanent mapping was neutered,
122*19c3b8c2SApple OSS Distributions * accessing it should crash.
123*19c3b8c2SApple OSS Distributions */
124*19c3b8c2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(*(int *)addr, 42, "we can still read what we wrote");
125*19c3b8c2SApple OSS Distributions });
126*19c3b8c2SApple OSS Distributions T_EXPECT_EQ(rc.sig, SIGBUS, "accessing the mapping caused a SIGBUS");
127*19c3b8c2SApple OSS Distributions
128*19c3b8c2SApple OSS Distributions T_LOG("try to bypass permanent mappings with a vm_remap");
129*19c3b8c2SApple OSS Distributions rc = fork_child_test(^{
130*19c3b8c2SApple OSS Distributions kern_return_t kr2;
131*19c3b8c2SApple OSS Distributions mach_vm_address_t addr, remap_addr, addr2;
132*19c3b8c2SApple OSS Distributions vm_prot_t cur_prot, max_prot;
133*19c3b8c2SApple OSS Distributions
134*19c3b8c2SApple OSS Distributions addr = get_permanent_mapping(size);
135*19c3b8c2SApple OSS Distributions
136*19c3b8c2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(*(int *)addr, 42, "we can still read what we wrote");
137*19c3b8c2SApple OSS Distributions
138*19c3b8c2SApple OSS Distributions addr2 = 0;
139*19c3b8c2SApple OSS Distributions kr2 = mach_vm_allocate(mach_task_self(), &addr2, size,
140*19c3b8c2SApple OSS Distributions VM_FLAGS_ANYWHERE);
141*19c3b8c2SApple OSS Distributions T_QUIET; T_EXPECT_MACH_SUCCESS(kr, "vm_allocate()");
142*19c3b8c2SApple OSS Distributions
143*19c3b8c2SApple OSS Distributions remap_addr = addr;
144*19c3b8c2SApple OSS Distributions kr2 = mach_vm_remap(mach_task_self(), &remap_addr, size, 0,
145*19c3b8c2SApple OSS Distributions VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
146*19c3b8c2SApple OSS Distributions mach_task_self(), addr2, TRUE,
147*19c3b8c2SApple OSS Distributions &cur_prot, &max_prot, VM_INHERIT_DEFAULT);
148*19c3b8c2SApple OSS Distributions
149*19c3b8c2SApple OSS Distributions /*
150*19c3b8c2SApple OSS Distributions * because the permanent mapping wasn't removed,
151*19c3b8c2SApple OSS Distributions * we should get an error.
152*19c3b8c2SApple OSS Distributions */
153*19c3b8c2SApple OSS Distributions T_ASSERT_MACH_ERROR(kr2, KERN_NO_SPACE,
154*19c3b8c2SApple OSS Distributions "mach_vm_remap()");
155*19c3b8c2SApple OSS Distributions
156*19c3b8c2SApple OSS Distributions /*
157*19c3b8c2SApple OSS Distributions * because the permanent mapping was neutered,
158*19c3b8c2SApple OSS Distributions * accessing it should crash.
159*19c3b8c2SApple OSS Distributions */
160*19c3b8c2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(*(int *)addr, 42, "we can still read what we wrote");
161*19c3b8c2SApple OSS Distributions });
162*19c3b8c2SApple OSS Distributions T_EXPECT_EQ(rc.sig, SIGBUS, "accessing the mapping caused a SIGBUS");
163*19c3b8c2SApple OSS Distributions
164*19c3b8c2SApple OSS Distributions T_LOG("try to bypass permanent mappings with a vm_deallocate");
165*19c3b8c2SApple OSS Distributions rc = fork_child_test(^{
166*19c3b8c2SApple OSS Distributions kern_return_t kr2;
167*19c3b8c2SApple OSS Distributions mach_vm_address_t addr;
168*19c3b8c2SApple OSS Distributions
169*19c3b8c2SApple OSS Distributions addr = get_permanent_mapping(size);
170*19c3b8c2SApple OSS Distributions
171*19c3b8c2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(*(int *)addr, 42, "we can still read what we wrote");
172*19c3b8c2SApple OSS Distributions
173*19c3b8c2SApple OSS Distributions kr2 = mach_vm_deallocate(mach_task_self(), addr, size);
174*19c3b8c2SApple OSS Distributions
175*19c3b8c2SApple OSS Distributions /*
176*19c3b8c2SApple OSS Distributions * the permanent mapping wasn't removed but was made
177*19c3b8c2SApple OSS Distributions * inaccessible; we should not get an error.
178*19c3b8c2SApple OSS Distributions */
179*19c3b8c2SApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr2, "mach_vm_deallocate()");
180*19c3b8c2SApple OSS Distributions
181*19c3b8c2SApple OSS Distributions /*
182*19c3b8c2SApple OSS Distributions * because the permanent mapping was neutered,
183*19c3b8c2SApple OSS Distributions * accessing it should crash.
184*19c3b8c2SApple OSS Distributions */
185*19c3b8c2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(*(int *)addr, 42, "we can still read what we wrote");
186*19c3b8c2SApple OSS Distributions });
187*19c3b8c2SApple OSS Distributions T_EXPECT_EQ(rc.sig, SIGBUS, "accessing the mapping caused a SIGBUS");
188*19c3b8c2SApple OSS Distributions }
189