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