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