]> git.saurik.com Git - apple/xnu.git/blame - bsd/vm/vm_unix.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / vm / vm_unix.c
CommitLineData
1c79356b 1/*
f427ee49 2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
0a7de745 28/*
1c79356b
A
29 * Mach Operating System
30 * Copyright (c) 1987 Carnegie-Mellon University
31 * All rights reserved. The CMU software License Agreement specifies
32 * the terms and conditions for use and redistribution.
33 */
1c79356b 34/*
2d21ac55
A
35 * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
36 * support for mandatory and extensible security protections. This notice
37 * is included in support of clause 2.2 (b) of the Apple Public License,
38 * Version 2.0.
1c79356b 39 */
fe8ab488
A
40#include <vm/vm_options.h>
41
1c79356b
A
42#include <kern/task.h>
43#include <kern/thread.h>
44#include <kern/debug.h>
6d2010ae 45#include <kern/extmod_statistics.h>
91447636 46#include <mach/mach_traps.h>
2d21ac55 47#include <mach/port.h>
39037602 48#include <mach/sdt.h>
2d21ac55
A
49#include <mach/task.h>
50#include <mach/task_access.h>
51#include <mach/task_special_ports.h>
1c79356b 52#include <mach/time_value.h>
91447636 53#include <mach/vm_map.h>
1c79356b
A
54#include <mach/vm_param.h>
55#include <mach/vm_prot.h>
f427ee49 56#include <machine/machine_routines.h>
1c79356b 57
91447636 58#include <sys/file_internal.h>
1c79356b
A
59#include <sys/param.h>
60#include <sys/systm.h>
61#include <sys/dir.h>
62#include <sys/namei.h>
91447636
A
63#include <sys/proc_internal.h>
64#include <sys/kauth.h>
1c79356b
A
65#include <sys/vm.h>
66#include <sys/file.h>
91447636 67#include <sys/vnode_internal.h>
1c79356b 68#include <sys/mount.h>
f427ee49 69#include <sys/xattr.h>
1c79356b
A
70#include <sys/trace.h>
71#include <sys/kernel.h>
91447636
A
72#include <sys/ubc_internal.h>
73#include <sys/user.h>
0c530ab8 74#include <sys/syslog.h>
9bccf70c 75#include <sys/stat.h>
91447636
A
76#include <sys/sysproto.h>
77#include <sys/mman.h>
0c530ab8 78#include <sys/sysctl.h>
6d2010ae
A
79#include <sys/cprotect.h>
80#include <sys/kpi_socket.h>
316670eb 81#include <sys/kas_info.h>
fe8ab488
A
82#include <sys/socket.h>
83#include <sys/socketvar.h>
f427ee49 84#include <sys/random.h>
5ba3f43e
A
85#if NECP
86#include <net/necp.h>
87#endif /* NECP */
1c79356b 88
b0d623f7 89#include <security/audit/audit.h>
6d2010ae 90#include <security/mac.h>
e5568f75
A
91#include <bsm/audit_kevents.h>
92
1c79356b 93#include <kern/kalloc.h>
1c79356b
A
94#include <vm/vm_map.h>
95#include <vm/vm_kern.h>
b0d623f7 96#include <vm/vm_pageout.h>
1c79356b 97
2d21ac55
A
98#include <mach/shared_region.h>
99#include <vm/vm_shared_region.h>
9bccf70c 100
91447636 101#include <vm/vm_protos.h>
9bccf70c 102
6d2010ae 103#include <sys/kern_memorystatus.h>
cb323159 104#include <sys/kern_memorystatus_freeze.h>
f427ee49 105#include <sys/proc_internal.h>
6d2010ae 106
5ba3f43e
A
107#if CONFIG_MACF
108#include <security/mac_framework.h>
109#endif
6d2010ae 110
f427ee49
A
111#include <kern/bits.h>
112
d9a64523
A
113#if CONFIG_CSR
114#include <sys/csr.h>
115#endif /* CONFIG_CSR */
cb323159 116#include <IOKit/IOBSD.h>
d9a64523 117
39037602
A
118#if VM_MAP_DEBUG_APPLE_PROTECT
119SYSCTL_INT(_vm, OID_AUTO, map_debug_apple_protect, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_map_debug_apple_protect, 0, "");
120#endif /* VM_MAP_DEBUG_APPLE_PROTECT */
121
122#if VM_MAP_DEBUG_FOURK
123SYSCTL_INT(_vm, OID_AUTO, map_debug_fourk, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_map_debug_fourk, 0, "");
124#endif /* VM_MAP_DEBUG_FOURK */
125
126#if DEVELOPMENT || DEBUG
127
128static int
129sysctl_kmem_alloc_contig SYSCTL_HANDLER_ARGS
130{
131#pragma unused(arg1, arg2)
0a7de745
A
132 vm_offset_t kaddr;
133 kern_return_t kr;
134 int error = 0;
135 int size = 0;
39037602
A
136
137 error = sysctl_handle_int(oidp, &size, 0, req);
0a7de745
A
138 if (error || !req->newptr) {
139 return error;
140 }
39037602
A
141
142 kr = kmem_alloc_contig(kernel_map, &kaddr, (vm_size_t)size, 0, 0, 0, 0, VM_KERN_MEMORY_IOKIT);
143
0a7de745 144 if (kr == KERN_SUCCESS) {
39037602 145 kmem_free(kernel_map, kaddr, size);
0a7de745 146 }
39037602
A
147
148 return error;
149}
150
0a7de745
A
151SYSCTL_PROC(_vm, OID_AUTO, kmem_alloc_contig, CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_LOCKED | CTLFLAG_MASKED,
152 0, 0, &sysctl_kmem_alloc_contig, "I", "");
39037602
A
153
154extern int vm_region_footprint;
a39ff7e2 155SYSCTL_INT(_vm, OID_AUTO, region_footprint, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, &vm_region_footprint, 0, "");
f427ee49
A
156
157#endif /* DEVELOPMENT || DEBUG */
158
a39ff7e2
A
159static int
160sysctl_vm_self_region_footprint SYSCTL_HANDLER_ARGS
161{
162#pragma unused(arg1, arg2, oidp)
0a7de745
A
163 int error = 0;
164 int value;
a39ff7e2
A
165
166 value = task_self_region_footprint();
0a7de745 167 error = SYSCTL_OUT(req, &value, sizeof(int));
a39ff7e2
A
168 if (error) {
169 return error;
170 }
171
172 if (!req->newptr) {
173 return 0;
174 }
175
0a7de745 176 error = SYSCTL_IN(req, &value, sizeof(int));
a39ff7e2 177 if (error) {
0a7de745 178 return error;
a39ff7e2
A
179 }
180 task_self_region_footprint_set(value);
181 return 0;
182}
0a7de745 183SYSCTL_PROC(_vm, OID_AUTO, self_region_footprint, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED | CTLFLAG_MASKED, 0, 0, &sysctl_vm_self_region_footprint, "I", "");
39037602 184
f427ee49
A
185static int
186sysctl_vm_self_region_page_size SYSCTL_HANDLER_ARGS
187{
188#pragma unused(arg1, arg2, oidp)
189 int error = 0;
190 int value;
191
192 value = (1 << thread_self_region_page_shift());
193 error = SYSCTL_OUT(req, &value, sizeof(int));
194 if (error) {
195 return error;
196 }
39037602 197
f427ee49
A
198 if (!req->newptr) {
199 return 0;
200 }
201
202 error = SYSCTL_IN(req, &value, sizeof(int));
203 if (error) {
204 return error;
205 }
206
207 if (value != 0 && value != 4096 && value != 16384) {
208 return EINVAL;
209 }
210
211#if !__ARM_MIXED_PAGE_SIZE__
212 if (value != vm_map_page_size(current_map())) {
213 return EINVAL;
214 }
215#endif /* !__ARM_MIXED_PAGE_SIZE__ */
216
217 thread_self_region_page_shift_set(bit_first(value));
218 return 0;
219}
220SYSCTL_PROC(_vm, OID_AUTO, self_region_page_size, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED | CTLFLAG_MASKED, 0, 0, &sysctl_vm_self_region_page_size, "I", "");
39037602 221
5ba3f43e
A
222
223#if DEVELOPMENT || DEBUG
224extern int panic_on_unsigned_execute;
225SYSCTL_INT(_vm, OID_AUTO, panic_on_unsigned_execute, CTLFLAG_RW | CTLFLAG_LOCKED, &panic_on_unsigned_execute, 0, "");
226#endif /* DEVELOPMENT || DEBUG */
227
5ba3f43e 228extern int cs_executable_create_upl;
5ba3f43e 229extern int cs_executable_wire;
5ba3f43e 230SYSCTL_INT(_vm, OID_AUTO, cs_executable_create_upl, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_executable_create_upl, 0, "");
5ba3f43e 231SYSCTL_INT(_vm, OID_AUTO, cs_executable_wire, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_executable_wire, 0, "");
490019cf 232
c3c9b80d
A
233extern int apple_protect_pager_count;
234extern int apple_protect_pager_count_mapped;
235extern unsigned int apple_protect_pager_cache_limit;
236SYSCTL_INT(_vm, OID_AUTO, apple_protect_pager_count, CTLFLAG_RD | CTLFLAG_LOCKED, &apple_protect_pager_count, 0, "");
237SYSCTL_INT(_vm, OID_AUTO, apple_protect_pager_count_mapped, CTLFLAG_RD | CTLFLAG_LOCKED, &apple_protect_pager_count_mapped, 0, "");
238SYSCTL_UINT(_vm, OID_AUTO, apple_protect_pager_cache_limit, CTLFLAG_RW | CTLFLAG_LOCKED, &apple_protect_pager_cache_limit, 0, "");
239
3e170ce0
A
240#if DEVELOPMENT || DEBUG
241extern int radar_20146450;
242SYSCTL_INT(_vm, OID_AUTO, radar_20146450, CTLFLAG_RW | CTLFLAG_LOCKED, &radar_20146450, 0, "");
243
244extern int macho_printf;
245SYSCTL_INT(_vm, OID_AUTO, macho_printf, CTLFLAG_RW | CTLFLAG_LOCKED, &macho_printf, 0, "");
246
247extern int apple_protect_pager_data_request_debug;
248SYSCTL_INT(_vm, OID_AUTO, apple_protect_pager_data_request_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &apple_protect_pager_data_request_debug, 0, "");
249
5ba3f43e
A
250#if __arm__ || __arm64__
251/* These are meant to support the page table accounting unit test. */
252extern unsigned int arm_hardware_page_size;
253extern unsigned int arm_pt_desc_size;
254extern unsigned int arm_pt_root_size;
255extern unsigned int free_page_size_tt_count;
256extern unsigned int free_two_page_size_tt_count;
257extern unsigned int free_tt_count;
258extern unsigned int inuse_user_tteroot_count;
259extern unsigned int inuse_kernel_tteroot_count;
260extern unsigned int inuse_user_ttepages_count;
261extern unsigned int inuse_kernel_ttepages_count;
262extern unsigned int inuse_user_ptepages_count;
263extern unsigned int inuse_kernel_ptepages_count;
264SYSCTL_UINT(_vm, OID_AUTO, native_hw_pagesize, CTLFLAG_RD | CTLFLAG_LOCKED, &arm_hardware_page_size, 0, "");
265SYSCTL_UINT(_vm, OID_AUTO, arm_pt_desc_size, CTLFLAG_RD | CTLFLAG_LOCKED, &arm_pt_desc_size, 0, "");
266SYSCTL_UINT(_vm, OID_AUTO, arm_pt_root_size, CTLFLAG_RD | CTLFLAG_LOCKED, &arm_pt_root_size, 0, "");
267SYSCTL_UINT(_vm, OID_AUTO, free_1page_tte_root, CTLFLAG_RD | CTLFLAG_LOCKED, &free_page_size_tt_count, 0, "");
268SYSCTL_UINT(_vm, OID_AUTO, free_2page_tte_root, CTLFLAG_RD | CTLFLAG_LOCKED, &free_two_page_size_tt_count, 0, "");
269SYSCTL_UINT(_vm, OID_AUTO, free_tte_root, CTLFLAG_RD | CTLFLAG_LOCKED, &free_tt_count, 0, "");
270SYSCTL_UINT(_vm, OID_AUTO, user_tte_root, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_user_tteroot_count, 0, "");
271SYSCTL_UINT(_vm, OID_AUTO, kernel_tte_root, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_kernel_tteroot_count, 0, "");
272SYSCTL_UINT(_vm, OID_AUTO, user_tte_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_user_ttepages_count, 0, "");
273SYSCTL_UINT(_vm, OID_AUTO, kernel_tte_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_kernel_ttepages_count, 0, "");
274SYSCTL_UINT(_vm, OID_AUTO, user_pte_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_user_ptepages_count, 0, "");
275SYSCTL_UINT(_vm, OID_AUTO, kernel_pte_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_kernel_ptepages_count, 0, "");
cb323159
A
276#if DEVELOPMENT || DEBUG
277extern unsigned long pmap_asid_flushes;
278SYSCTL_ULONG(_vm, OID_AUTO, pmap_asid_flushes, CTLFLAG_RD | CTLFLAG_LOCKED, &pmap_asid_flushes, "");
f427ee49
A
279extern unsigned long pmap_asid_hits;
280SYSCTL_ULONG(_vm, OID_AUTO, pmap_asid_hits, CTLFLAG_RD | CTLFLAG_LOCKED, &pmap_asid_hits, "");
281extern unsigned long pmap_asid_misses;
282SYSCTL_ULONG(_vm, OID_AUTO, pmap_asid_misses, CTLFLAG_RD | CTLFLAG_LOCKED, &pmap_asid_misses, "");
cb323159 283#endif
5ba3f43e
A
284#endif /* __arm__ || __arm64__ */
285
286#if __arm64__
287extern int fourk_pager_data_request_debug;
288SYSCTL_INT(_vm, OID_AUTO, fourk_pager_data_request_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &fourk_pager_data_request_debug, 0, "");
289#endif /* __arm64__ */
3e170ce0
A
290#endif /* DEVELOPMENT || DEBUG */
291
fe8ab488
A
292SYSCTL_INT(_vm, OID_AUTO, vm_do_collapse_compressor, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.do_collapse_compressor, 0, "");
293SYSCTL_INT(_vm, OID_AUTO, vm_do_collapse_compressor_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.do_collapse_compressor_pages, 0, "");
294SYSCTL_INT(_vm, OID_AUTO, vm_do_collapse_terminate, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.do_collapse_terminate, 0, "");
295SYSCTL_INT(_vm, OID_AUTO, vm_do_collapse_terminate_failure, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.do_collapse_terminate_failure, 0, "");
296SYSCTL_INT(_vm, OID_AUTO, vm_should_cow_but_wired, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.should_cow_but_wired, 0, "");
297SYSCTL_INT(_vm, OID_AUTO, vm_create_upl_extra_cow, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.create_upl_extra_cow, 0, "");
298SYSCTL_INT(_vm, OID_AUTO, vm_create_upl_extra_cow_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.create_upl_extra_cow_pages, 0, "");
299SYSCTL_INT(_vm, OID_AUTO, vm_create_upl_lookup_failure_write, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.create_upl_lookup_failure_write, 0, "");
300SYSCTL_INT(_vm, OID_AUTO, vm_create_upl_lookup_failure_copy, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.create_upl_lookup_failure_copy, 0, "");
301#if VM_SCAN_FOR_SHADOW_CHAIN
302static int vm_shadow_max_enabled = 0; /* Disabled by default */
303extern int proc_shadow_max(void);
304static int
305vm_shadow_max SYSCTL_HANDLER_ARGS
306{
307#pragma unused(arg1, arg2, oidp)
308 int value = 0;
309
0a7de745 310 if (vm_shadow_max_enabled) {
fe8ab488 311 value = proc_shadow_max();
0a7de745 312 }
fe8ab488
A
313
314 return SYSCTL_OUT(req, &value, sizeof(value));
315}
0a7de745 316SYSCTL_PROC(_vm, OID_AUTO, vm_shadow_max, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
fe8ab488
A
317 0, 0, &vm_shadow_max, "I", "");
318
319SYSCTL_INT(_vm, OID_AUTO, vm_shadow_max_enabled, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_shadow_max_enabled, 0, "");
320
321#endif /* VM_SCAN_FOR_SHADOW_CHAIN */
6d2010ae 322
fe8ab488 323SYSCTL_INT(_vm, OID_AUTO, vm_debug_events, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_debug_events, 0, "");
6d2010ae 324
fe8ab488 325__attribute__((noinline)) int __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(
c3c9b80d 326 mach_port_t task_access_port, int32_t calling_pid, uint32_t calling_gid, int32_t target_pid, mach_task_flavor_t flavor);
2d21ac55
A
327/*
328 * Sysctl's related to data/stack execution. See osfmk/vm/vm_map.c
329 */
330
39037602 331#if DEVELOPMENT || DEBUG
2d21ac55
A
332extern int allow_stack_exec, allow_data_exec;
333
6d2010ae
A
334SYSCTL_INT(_vm, OID_AUTO, allow_stack_exec, CTLFLAG_RW | CTLFLAG_LOCKED, &allow_stack_exec, 0, "");
335SYSCTL_INT(_vm, OID_AUTO, allow_data_exec, CTLFLAG_RW | CTLFLAG_LOCKED, &allow_data_exec, 0, "");
3e170ce0 336
39037602 337#endif /* DEVELOPMENT || DEBUG */
2d21ac55 338
2d21ac55
A
339static const char *prot_values[] = {
340 "none",
341 "read-only",
342 "write-only",
343 "read-write",
344 "execute-only",
345 "read-execute",
346 "write-execute",
347 "read-write-execute"
348};
349
0c530ab8 350void
2d21ac55 351log_stack_execution_failure(addr64_t vaddr, vm_prot_t prot)
0c530ab8 352{
0a7de745
A
353 printf("Data/Stack execution not permitted: %s[pid %d] at virtual address 0x%qx, protections were %s\n",
354 current_proc()->p_comm, current_proc()->p_pid, vaddr, prot_values[prot & VM_PROT_ALL]);
0c530ab8
A
355}
356
39037602
A
357/*
358 * shared_region_unnest_logging: level of logging of unnesting events
359 * 0 - no logging
360 * 1 - throttled logging of unexpected unnesting events (default)
361 * 2 - unthrottled logging of unexpected unnesting events
362 * 3+ - unthrottled logging of all unnesting events
363 */
b0d623f7
A
364int shared_region_unnest_logging = 1;
365
6d2010ae 366SYSCTL_INT(_vm, OID_AUTO, shared_region_unnest_logging, CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 367 &shared_region_unnest_logging, 0, "");
b0d623f7
A
368
369int vm_shared_region_unnest_log_interval = 10;
370int shared_region_unnest_log_count_threshold = 5;
371
fe8ab488
A
372/*
373 * Shared cache path enforcement.
374 */
375
f427ee49
A
376#if XNU_TARGET_OS_OSX
377
378#if defined (__x86_64__)
fe8ab488 379static int scdir_enforce = 1;
f427ee49
A
380#else /* defined (__x86_64__) */
381static int scdir_enforce = 0; /* AOT caches live elsewhere */
382#endif /* defined (__x86_64__) */
383
384static char scdir_path[] = "/System/Library/dyld/";
385
386#else /* XNU_TARGET_OS_OSX */
387
5ba3f43e
A
388static int scdir_enforce = 0;
389static char scdir_path[] = "/System/Library/Caches/com.apple.dyld/";
f427ee49
A
390
391#endif /* XNU_TARGET_OS_OSX */
fe8ab488
A
392
393#ifndef SECURE_KERNEL
d9a64523
A
394static int sysctl_scdir_enforce SYSCTL_HANDLER_ARGS
395{
396#if CONFIG_CSR
397 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
398 printf("Failed attempt to set vm.enforce_shared_cache_dir sysctl\n");
399 return EPERM;
400 }
401#endif /* CONFIG_CSR */
402 return sysctl_handle_int(oidp, arg1, arg2, req);
403}
404
405SYSCTL_PROC(_vm, OID_AUTO, enforce_shared_cache_dir, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &scdir_enforce, 0, sysctl_scdir_enforce, "I", "");
fe8ab488
A
406#endif
407
b0d623f7
A
408/* These log rate throttling state variables aren't thread safe, but
409 * are sufficient unto the task.
410 */
0a7de745 411static int64_t last_unnest_log_time = 0;
b0d623f7
A
412static int shared_region_unnest_log_count = 0;
413
39037602
A
414void
415log_unnest_badness(
0a7de745 416 vm_map_t m,
3e170ce0 417 vm_map_offset_t s,
39037602 418 vm_map_offset_t e,
0a7de745
A
419 boolean_t is_nested_map,
420 vm_map_offset_t lowest_unnestable_addr)
39037602 421{
0a7de745 422 struct timeval tv;
b0d623f7 423
0a7de745 424 if (shared_region_unnest_logging == 0) {
b0d623f7 425 return;
0a7de745 426 }
b0d623f7 427
39037602
A
428 if (shared_region_unnest_logging <= 2 &&
429 is_nested_map &&
430 s >= lowest_unnestable_addr) {
431 /*
432 * Unnesting of writable map entries is fine.
433 */
434 return;
435 }
436
437 if (shared_region_unnest_logging <= 1) {
b0d623f7 438 microtime(&tv);
39037602
A
439 if ((tv.tv_sec - last_unnest_log_time) <
440 vm_shared_region_unnest_log_interval) {
441 if (shared_region_unnest_log_count++ >
0a7de745 442 shared_region_unnest_log_count_threshold) {
b0d623f7 443 return;
0a7de745 444 }
39037602 445 } else {
b0d623f7
A
446 last_unnest_log_time = tv.tv_sec;
447 shared_region_unnest_log_count = 0;
448 }
449 }
450
39037602 451 DTRACE_VM4(log_unnest_badness,
0a7de745
A
452 vm_map_t, m,
453 vm_map_offset_t, s,
454 vm_map_offset_t, e,
455 vm_map_offset_t, lowest_unnestable_addr);
3e170ce0 456 printf("%s[%d] triggered unnest of range 0x%qx->0x%qx of DYLD shared region in VM map %p. While not abnormal for debuggers, this increases system memory footprint until the target exits.\n", current_proc()->p_comm, current_proc()->p_pid, (uint64_t)s, (uint64_t)e, (void *) VM_KERNEL_ADDRPERM(m));
b0d623f7 457}
1c79356b 458
91447636
A
459int
460useracc(
0a7de745
A
461 user_addr_t addr,
462 user_size_t len,
463 int prot)
1c79356b 464{
0a7de745 465 vm_map_t map;
39236c6e
A
466
467 map = current_map();
0a7de745
A
468 return vm_map_check_protection(
469 map,
470 vm_map_trunc_page(addr,
471 vm_map_page_mask(map)),
472 vm_map_round_page(addr + len,
473 vm_map_page_mask(map)),
474 prot == B_READ ? VM_PROT_READ : VM_PROT_WRITE);
1c79356b
A
475}
476
91447636
A
477int
478vslock(
0a7de745
A
479 user_addr_t addr,
480 user_size_t len)
1c79356b 481{
0a7de745
A
482 kern_return_t kret;
483 vm_map_t map;
39236c6e
A
484
485 map = current_map();
5ba3f43e 486 kret = vm_map_wire_kernel(map,
0a7de745
A
487 vm_map_trunc_page(addr,
488 vm_map_page_mask(map)),
489 vm_map_round_page(addr + len,
490 vm_map_page_mask(map)),
491 VM_PROT_READ | VM_PROT_WRITE, VM_KERN_MEMORY_BSD,
492 FALSE);
0b4e3aa0
A
493
494 switch (kret) {
495 case KERN_SUCCESS:
0a7de745 496 return 0;
0b4e3aa0
A
497 case KERN_INVALID_ADDRESS:
498 case KERN_NO_SPACE:
0a7de745 499 return ENOMEM;
0b4e3aa0 500 case KERN_PROTECTION_FAILURE:
0a7de745 501 return EACCES;
0b4e3aa0 502 default:
0a7de745 503 return EINVAL;
0b4e3aa0 504 }
1c79356b
A
505}
506
91447636
A
507int
508vsunlock(
509 user_addr_t addr,
510 user_size_t len,
511 __unused int dirtied)
1c79356b 512{
1c79356b 513#if FIXME /* [ */
0a7de745
A
514 pmap_t pmap;
515 vm_page_t pg;
516 vm_map_offset_t vaddr;
517 ppnum_t paddr;
1c79356b 518#endif /* FIXME ] */
0a7de745
A
519 kern_return_t kret;
520 vm_map_t map;
39236c6e
A
521
522 map = current_map();
1c79356b
A
523
524#if FIXME /* [ */
525 if (dirtied) {
526 pmap = get_task_pmap(current_task());
39236c6e 527 for (vaddr = vm_map_trunc_page(addr, PAGE_MASK);
0a7de745
A
528 vaddr < vm_map_round_page(addr + len, PAGE_MASK);
529 vaddr += PAGE_SIZE) {
f427ee49 530 paddr = pmap_find_phys(pmap, vaddr);
1c79356b
A
531 pg = PHYS_TO_VM_PAGE(paddr);
532 vm_page_set_modified(pg);
533 }
534 }
535#endif /* FIXME ] */
0a7de745 536#ifdef lint
1c79356b 537 dirtied++;
0a7de745 538#endif /* lint */
39236c6e 539 kret = vm_map_unwire(map,
0a7de745
A
540 vm_map_trunc_page(addr,
541 vm_map_page_mask(map)),
542 vm_map_round_page(addr + len,
543 vm_map_page_mask(map)),
544 FALSE);
0b4e3aa0
A
545 switch (kret) {
546 case KERN_SUCCESS:
0a7de745 547 return 0;
0b4e3aa0
A
548 case KERN_INVALID_ADDRESS:
549 case KERN_NO_SPACE:
0a7de745 550 return ENOMEM;
0b4e3aa0 551 case KERN_PROTECTION_FAILURE:
0a7de745 552 return EACCES;
0b4e3aa0 553 default:
0a7de745 554 return EINVAL;
0b4e3aa0 555 }
1c79356b
A
556}
557
91447636
A
558int
559subyte(
560 user_addr_t addr,
561 int byte)
1c79356b
A
562{
563 char character;
0a7de745 564
1c79356b 565 character = (char)byte;
0a7de745 566 return copyout((void *)&(character), addr, sizeof(char)) == 0 ? 0 : -1;
1c79356b
A
567}
568
91447636
A
569int
570suibyte(
571 user_addr_t addr,
572 int byte)
1c79356b
A
573{
574 char character;
0a7de745 575
1c79356b 576 character = (char)byte;
0a7de745 577 return copyout((void *)&(character), addr, sizeof(char)) == 0 ? 0 : -1;
1c79356b
A
578}
579
0a7de745
A
580int
581fubyte(user_addr_t addr)
1c79356b
A
582{
583 unsigned char byte;
584
0a7de745
A
585 if (copyin(addr, (void *) &byte, sizeof(char))) {
586 return -1;
587 }
588 return byte;
1c79356b
A
589}
590
0a7de745
A
591int
592fuibyte(user_addr_t addr)
1c79356b
A
593{
594 unsigned char byte;
595
0a7de745
A
596 if (copyin(addr, (void *) &(byte), sizeof(char))) {
597 return -1;
598 }
599 return byte;
1c79356b
A
600}
601
91447636
A
602int
603suword(
604 user_addr_t addr,
605 long word)
1c79356b 606{
0a7de745 607 return copyout((void *) &word, addr, sizeof(int)) == 0 ? 0 : -1;
1c79356b
A
608}
609
0a7de745
A
610long
611fuword(user_addr_t addr)
1c79356b 612{
b0d623f7 613 long word = 0;
1c79356b 614
0a7de745
A
615 if (copyin(addr, (void *) &word, sizeof(int))) {
616 return -1;
617 }
618 return word;
1c79356b
A
619}
620
621/* suiword and fuiword are the same as suword and fuword, respectively */
622
91447636
A
623int
624suiword(
625 user_addr_t addr,
626 long word)
1c79356b 627{
0a7de745 628 return copyout((void *) &word, addr, sizeof(int)) == 0 ? 0 : -1;
1c79356b
A
629}
630
0a7de745
A
631long
632fuiword(user_addr_t addr)
1c79356b 633{
b0d623f7 634 long word = 0;
1c79356b 635
0a7de745
A
636 if (copyin(addr, (void *) &word, sizeof(int))) {
637 return -1;
638 }
639 return word;
1c79356b 640}
91447636
A
641
642/*
643 * With a 32-bit kernel and mixed 32/64-bit user tasks, this interface allows the
644 * fetching and setting of process-sized size_t and pointer values.
645 */
646int
647sulong(user_addr_t addr, int64_t word)
648{
91447636 649 if (IS_64BIT_PROCESS(current_proc())) {
0a7de745 650 return copyout((void *)&word, addr, sizeof(word)) == 0 ? 0 : -1;
91447636 651 } else {
0a7de745 652 return suiword(addr, (long)word);
91447636
A
653 }
654}
655
656int64_t
657fulong(user_addr_t addr)
658{
659 int64_t longword;
660
661 if (IS_64BIT_PROCESS(current_proc())) {
0a7de745
A
662 if (copyin(addr, (void *)&longword, sizeof(longword)) != 0) {
663 return -1;
664 }
665 return longword;
91447636 666 } else {
0a7de745 667 return (int64_t)fuiword(addr);
91447636
A
668 }
669}
1c79356b
A
670
671int
91447636
A
672suulong(user_addr_t addr, uint64_t uword)
673{
91447636 674 if (IS_64BIT_PROCESS(current_proc())) {
0a7de745 675 return copyout((void *)&uword, addr, sizeof(uword)) == 0 ? 0 : -1;
91447636 676 } else {
0a7de745 677 return suiword(addr, (uint32_t)uword);
91447636
A
678 }
679}
680
681uint64_t
682fuulong(user_addr_t addr)
1c79356b 683{
91447636
A
684 uint64_t ulongword;
685
686 if (IS_64BIT_PROCESS(current_proc())) {
0a7de745
A
687 if (copyin(addr, (void *)&ulongword, sizeof(ulongword)) != 0) {
688 return -1ULL;
689 }
690 return ulongword;
91447636 691 } else {
0a7de745 692 return (uint64_t)fuiword(addr);
91447636
A
693 }
694}
695
696int
2d21ac55 697swapon(__unused proc_t procp, __unused struct swapon_args *uap, __unused int *retval)
91447636 698{
0a7de745 699 return ENOTSUP;
1c79356b
A
700}
701
b0d623f7
A
702/*
703 * pid_for_task
704 *
0a7de745 705 * Find the BSD process ID for the Mach task associated with the given Mach port
b0d623f7
A
706 * name
707 *
708 * Parameters: args User argument descriptor (see below)
709 *
710 * Indirect parameters: args->t Mach port name
0a7de745 711 * args->pid Process ID (returned value; see below)
b0d623f7
A
712 *
713 * Returns: KERL_SUCCESS Success
0a7de745 714 * KERN_FAILURE Not success
b0d623f7
A
715 *
716 * Implicit returns: args->pid Process ID
717 *
718 */
1c79356b 719kern_return_t
91447636
A
720pid_for_task(
721 struct pid_for_task_args *args)
1c79356b 722{
0a7de745
A
723 mach_port_name_t t = args->t;
724 user_addr_t pid_addr = args->pid;
2d21ac55 725 proc_t p;
0a7de745
A
726 task_t t1;
727 int pid = -1;
728 kern_return_t err = KERN_SUCCESS;
1c79356b 729
e5568f75
A
730 AUDIT_MACH_SYSCALL_ENTER(AUE_PIDFORTASK);
731 AUDIT_ARG(mach_port1, t);
732
f427ee49 733 t1 = port_name_to_task_name(t);
1c79356b
A
734
735 if (t1 == TASK_NULL) {
736 err = KERN_FAILURE;
0b4e3aa0 737 goto pftout;
1c79356b
A
738 } else {
739 p = get_bsdtask_info(t1);
740 if (p) {
91447636 741 pid = proc_pid(p);
1c79356b 742 err = KERN_SUCCESS;
39037602
A
743 } else if (is_corpsetask(t1)) {
744 pid = task_pid(t1);
745 err = KERN_SUCCESS;
0a7de745 746 } else {
1c79356b
A
747 err = KERN_FAILURE;
748 }
749 }
750 task_deallocate(t1);
1c79356b 751pftout:
e5568f75 752 AUDIT_ARG(pid, pid);
91447636 753 (void) copyout((char *) &pid, pid_addr, sizeof(int));
e5568f75 754 AUDIT_MACH_SYSCALL_EXIT(err);
0a7de745 755 return err;
1c79356b
A
756}
757
0a7de745 758/*
2d21ac55
A
759 *
760 * tfp_policy = KERN_TFP_POLICY_DENY; Deny Mode: None allowed except for self
761 * tfp_policy = KERN_TFP_POLICY_DEFAULT; default mode: all posix checks and upcall via task port for authentication
762 *
763 */
764static int tfp_policy = KERN_TFP_POLICY_DEFAULT;
765
766/*
767 * Routine: task_for_pid_posix_check
768 * Purpose:
769 * Verify that the current process should be allowed to
0a7de745 770 * get the target process's task port. This is only
2d21ac55
A
771 * permitted if:
772 * - The current process is root
773 * OR all of the following are true:
774 * - The target process's real, effective, and saved uids
775 * are the same as the current proc's euid,
776 * - The target process's group set is a subset of the
777 * calling process's group set, and
778 * - The target process hasn't switched credentials.
779 *
780 * Returns: TRUE: permitted
781 * FALSE: denied
782 */
783static int
784task_for_pid_posix_check(proc_t target)
785{
786 kauth_cred_t targetcred, mycred;
787 uid_t myuid;
0a7de745 788 int allowed;
2d21ac55
A
789
790 /* No task_for_pid on bad targets */
316670eb 791 if (target->p_stat == SZOMB) {
2d21ac55
A
792 return FALSE;
793 }
794
795 mycred = kauth_cred_get();
796 myuid = kauth_cred_getuid(mycred);
797
798 /* If we're running as root, the check passes */
0a7de745 799 if (kauth_cred_issuser(mycred)) {
2d21ac55 800 return TRUE;
0a7de745 801 }
2d21ac55
A
802
803 /* We're allowed to get our own task port */
0a7de745 804 if (target == current_proc()) {
2d21ac55 805 return TRUE;
0a7de745 806 }
2d21ac55 807
0a7de745 808 /*
2d21ac55
A
809 * Under DENY, only root can get another proc's task port,
810 * so no more checks are needed.
811 */
0a7de745 812 if (tfp_policy == KERN_TFP_POLICY_DENY) {
2d21ac55
A
813 return FALSE;
814 }
815
816 targetcred = kauth_cred_proc_ref(target);
817 allowed = TRUE;
818
819 /* Do target's ruid, euid, and saved uid match my euid? */
0a7de745
A
820 if ((kauth_cred_getuid(targetcred) != myuid) ||
821 (kauth_cred_getruid(targetcred) != myuid) ||
822 (kauth_cred_getsvuid(targetcred) != myuid)) {
2d21ac55
A
823 allowed = FALSE;
824 goto out;
825 }
826
827 /* Are target's groups a subset of my groups? */
828 if (kauth_cred_gid_subset(targetcred, mycred, &allowed) ||
0a7de745 829 allowed == 0) {
2d21ac55
A
830 allowed = FALSE;
831 goto out;
832 }
833
834 /* Has target switched credentials? */
835 if (target->p_flag & P_SUGID) {
836 allowed = FALSE;
837 goto out;
838 }
0a7de745 839
2d21ac55
A
840out:
841 kauth_cred_unref(&targetcred);
842 return allowed;
843}
844
fe8ab488
A
845/*
846 * __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__
847 *
848 * Description: Waits for the user space daemon to respond to the request
849 * we made. Function declared non inline to be visible in
850 * stackshots and spindumps as well as debugging.
851 */
0a7de745
A
852__attribute__((noinline)) int
853__KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(
c3c9b80d 854 mach_port_t task_access_port, int32_t calling_pid, uint32_t calling_gid, int32_t target_pid, mach_task_flavor_t flavor)
fe8ab488 855{
c3c9b80d 856 return check_task_access_with_flavor(task_access_port, calling_pid, calling_gid, target_pid, flavor);
fe8ab488
A
857}
858
1c79356b
A
859/*
860 * Routine: task_for_pid
861 * Purpose:
862 * Get the task port for another "process", named by its
863 * process ID on the same host as "target_task".
864 *
865 * Only permitted to privileged processes, or processes
866 * with the same user ID.
91447636 867 *
b0d623f7
A
868 * Note: if pid == 0, an error is return no matter who is calling.
869 *
91447636 870 * XXX This should be a BSD system call, not a Mach trap!!!
1c79356b
A
871 */
872kern_return_t
91447636
A
873task_for_pid(
874 struct task_for_pid_args *args)
1c79356b 875{
0a7de745
A
876 mach_port_name_t target_tport = args->target_tport;
877 int pid = args->pid;
878 user_addr_t task_addr = args->t;
879 proc_t p = PROC_NULL;
880 task_t t1 = TASK_NULL;
881 task_t task = TASK_NULL;
882 mach_port_name_t tret = MACH_PORT_NULL;
883 ipc_port_t tfpport = MACH_PORT_NULL;
f427ee49
A
884 void * sright = NULL;
885 int error = 0;
886 boolean_t is_current_proc = FALSE;
887 struct proc_ident pident = {0};
1c79356b 888
e5568f75
A
889 AUDIT_MACH_SYSCALL_ENTER(AUE_TASKFORPID);
890 AUDIT_ARG(pid, pid);
891 AUDIT_ARG(mach_port1, target_tport);
892
b0d623f7
A
893 /* Always check if pid == 0 */
894 if (pid == 0) {
c3c9b80d 895 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
2d21ac55 896 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
0a7de745 897 return KERN_FAILURE;
2d21ac55 898 }
2d21ac55 899
1c79356b
A
900 t1 = port_name_to_task(target_tport);
901 if (t1 == TASK_NULL) {
c3c9b80d 902 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
e5568f75 903 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
0a7de745
A
904 return KERN_FAILURE;
905 }
1c79356b 906
91447636 907
2d21ac55 908 p = proc_find(pid);
316670eb
A
909 if (p == PROC_NULL) {
910 error = KERN_FAILURE;
911 goto tfpout;
912 }
f427ee49
A
913 pident = proc_ident(p);
914 is_current_proc = (p == current_proc());
316670eb 915
b0d623f7 916#if CONFIG_AUDIT
316670eb 917 AUDIT_ARG(process, p);
b0d623f7 918#endif
91447636 919
2d21ac55
A
920 if (!(task_for_pid_posix_check(p))) {
921 error = KERN_FAILURE;
922 goto tfpout;
923 }
0c530ab8 924
a39ff7e2
A
925 if (p->task == TASK_NULL) {
926 error = KERN_SUCCESS;
927 goto tfpout;
928 }
0c530ab8 929
f427ee49
A
930 /*
931 * Grab a task reference and drop the proc reference as the proc ref
932 * shouldn't be held accross upcalls.
933 */
934 task = p->task;
935 task_reference(task);
936
937 proc_rele(p);
938 p = PROC_NULL;
939
a39ff7e2 940#if CONFIG_MACF
c3c9b80d 941 error = mac_proc_check_get_task(kauth_cred_get(), &pident, TASK_FLAVOR_CONTROL);
a39ff7e2
A
942 if (error) {
943 error = KERN_FAILURE;
944 goto tfpout;
945 }
946#endif
0c530ab8 947
a39ff7e2
A
948 /* If we aren't root and target's task access port is set... */
949 if (!kauth_cred_issuser(kauth_cred_get()) &&
f427ee49 950 !is_current_proc &&
0a7de745
A
951 (task_get_task_access_port(task, &tfpport) == 0) &&
952 (tfpport != IPC_PORT_NULL)) {
a39ff7e2
A
953 if (tfpport == IPC_PORT_DEAD) {
954 error = KERN_PROTECTION_FAILURE;
1c79356b 955 goto tfpout;
2d21ac55 956 }
2d21ac55 957
a39ff7e2 958 /* Call up to the task access server */
c3c9b80d
A
959 error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport,
960 proc_selfpid(), kauth_getgid(), pid, TASK_FLAVOR_CONTROL);
5ba3f43e 961
a39ff7e2 962 if (error != MACH_MSG_SUCCESS) {
0a7de745 963 if (error == MACH_RCV_INTERRUPTED) {
a39ff7e2 964 error = KERN_ABORTED;
0a7de745 965 } else {
a39ff7e2 966 error = KERN_FAILURE;
0a7de745 967 }
5ba3f43e
A
968 goto tfpout;
969 }
a39ff7e2
A
970 }
971
972 /* Grant task port access */
973 extmod_statistics_incr_task_for_pid(task);
c3c9b80d
A
974
975 if (task == current_task()) {
976 /* return pinned self if current_task() so equality check with mach_task_self_ passes */
977 sright = (void *)convert_task_to_port_pinned(task);
978 } else {
979 sright = (void *)convert_task_to_port(task);
980 }
a39ff7e2
A
981
982 /* Check if the task has been corpsified */
983 if (is_corpsetask(task)) {
984 /* task ref consumed by convert_task_to_port */
985 task = TASK_NULL;
986 ipc_port_release_send(sright);
987 error = KERN_FAILURE;
988 goto tfpout;
989 }
990
991 /* task ref consumed by convert_task_to_port */
992 task = TASK_NULL;
993 tret = ipc_port_copyout_send(
0a7de745
A
994 sright,
995 get_task_ipcspace(current_task()));
5ba3f43e 996
2d21ac55 997 error = KERN_SUCCESS;
0c530ab8 998
1c79356b 999tfpout:
2d21ac55
A
1000 task_deallocate(t1);
1001 AUDIT_ARG(mach_port2, tret);
1002 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
a39ff7e2
A
1003
1004 if (tfpport != IPC_PORT_NULL) {
1005 ipc_port_release_send(tfpport);
1006 }
1007 if (task != TASK_NULL) {
1008 task_deallocate(task);
1009 }
0a7de745 1010 if (p != PROC_NULL) {
2d21ac55 1011 proc_rele(p);
0a7de745 1012 }
e5568f75 1013 AUDIT_MACH_SYSCALL_EXIT(error);
0a7de745 1014 return error;
1c79356b
A
1015}
1016
0c530ab8
A
1017/*
1018 * Routine: task_name_for_pid
1019 * Purpose:
1020 * Get the task name port for another "process", named by its
1021 * process ID on the same host as "target_task".
1022 *
1023 * Only permitted to privileged processes, or processes
1024 * with the same user ID.
1025 *
1026 * XXX This should be a BSD system call, not a Mach trap!!!
1027 */
1028
1029kern_return_t
1030task_name_for_pid(
1031 struct task_name_for_pid_args *args)
1032{
0a7de745
A
1033 mach_port_name_t target_tport = args->target_tport;
1034 int pid = args->pid;
1035 user_addr_t task_addr = args->t;
c3c9b80d
A
1036 proc_t p = PROC_NULL;
1037 task_t t1 = TASK_NULL;
1038 mach_port_name_t tret = MACH_PORT_NULL;
0c530ab8 1039 void * sright;
2d21ac55
A
1040 int error = 0, refheld = 0;
1041 kauth_cred_t target_cred;
0c530ab8
A
1042
1043 AUDIT_MACH_SYSCALL_ENTER(AUE_TASKNAMEFORPID);
1044 AUDIT_ARG(pid, pid);
1045 AUDIT_ARG(mach_port1, target_tport);
1046
1047 t1 = port_name_to_task(target_tport);
1048 if (t1 == TASK_NULL) {
c3c9b80d 1049 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
0c530ab8 1050 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
0a7de745
A
1051 return KERN_FAILURE;
1052 }
0c530ab8 1053
2d21ac55 1054 p = proc_find(pid);
2d21ac55 1055 if (p != PROC_NULL) {
b0d623f7 1056 AUDIT_ARG(process, p);
2d21ac55
A
1057 target_cred = kauth_cred_proc_ref(p);
1058 refheld = 1;
1059
1060 if ((p->p_stat != SZOMB)
1061 && ((current_proc() == p)
0a7de745
A
1062 || kauth_cred_issuser(kauth_cred_get())
1063 || ((kauth_cred_getuid(target_cred) == kauth_cred_getuid(kauth_cred_get())) &&
1064 ((kauth_cred_getruid(target_cred) == kauth_getruid()))))) {
2d21ac55 1065 if (p->task != TASK_NULL) {
f427ee49
A
1066 struct proc_ident pident = proc_ident(p);
1067
1068 task_t task = p->task;
1069
2d21ac55 1070 task_reference(p->task);
f427ee49
A
1071 proc_rele(p);
1072 p = PROC_NULL;
2d21ac55 1073#if CONFIG_MACF
c3c9b80d 1074 error = mac_proc_check_get_task(kauth_cred_get(), &pident, TASK_FLAVOR_NAME);
2d21ac55 1075 if (error) {
f427ee49 1076 task_deallocate(task);
2d21ac55
A
1077 goto noperm;
1078 }
1079#endif
f427ee49
A
1080 sright = (void *)convert_task_name_to_port(task);
1081 task = NULL;
0a7de745
A
1082 tret = ipc_port_copyout_send(sright,
1083 get_task_ipcspace(current_task()));
1084 } else {
2d21ac55 1085 tret = MACH_PORT_NULL;
0a7de745 1086 }
2d21ac55
A
1087
1088 AUDIT_ARG(mach_port2, tret);
1089 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
1090 task_deallocate(t1);
1091 error = KERN_SUCCESS;
1092 goto tnfpout;
1093 }
0c530ab8
A
1094 }
1095
2d21ac55
A
1096#if CONFIG_MACF
1097noperm:
1098#endif
0a7de745 1099 task_deallocate(t1);
0c530ab8
A
1100 tret = MACH_PORT_NULL;
1101 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
1102 error = KERN_FAILURE;
1103tnfpout:
0a7de745 1104 if (refheld != 0) {
2d21ac55 1105 kauth_cred_unref(&target_cred);
0a7de745
A
1106 }
1107 if (p != PROC_NULL) {
2d21ac55 1108 proc_rele(p);
0a7de745 1109 }
0c530ab8 1110 AUDIT_MACH_SYSCALL_EXIT(error);
0a7de745 1111 return error;
0c530ab8
A
1112}
1113
f427ee49
A
1114/*
1115 * Routine: task_inspect_for_pid
1116 * Purpose:
1117 * Get the task inspect port for another "process", named by its
1118 * process ID on the same host as "target_task".
1119 */
1120int
1121task_inspect_for_pid(struct proc *p __unused, struct task_inspect_for_pid_args *args, int *ret)
1122{
1123 mach_port_name_t target_tport = args->target_tport;
1124 int pid = args->pid;
1125 user_addr_t task_addr = args->t;
1126
1127 proc_t proc = PROC_NULL;
1128 task_t t1 = TASK_NULL;
1129 task_inspect_t task_insp = TASK_INSPECT_NULL;
1130 mach_port_name_t tret = MACH_PORT_NULL;
1131 ipc_port_t tfpport = MACH_PORT_NULL;
1132 int error = 0;
1133 void *sright = NULL;
1134 boolean_t is_current_proc = FALSE;
1135 struct proc_ident pident = {0};
1136
1137 /* Disallow inspect port for kernel_task */
1138 if (pid == 0) {
c3c9b80d 1139 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
f427ee49
A
1140 return EPERM;
1141 }
1142
1143 t1 = port_name_to_task(target_tport);
1144 if (t1 == TASK_NULL) {
c3c9b80d 1145 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
f427ee49
A
1146 return EINVAL;
1147 }
1148
1149 proc = proc_find(pid);
1150 if (proc == PROC_NULL) {
1151 error = ESRCH;
1152 goto tifpout;
1153 }
1154 pident = proc_ident(proc);
1155 is_current_proc = (proc == current_proc());
1156
1157 if (!(task_for_pid_posix_check(proc))) {
1158 error = EPERM;
1159 goto tifpout;
1160 }
1161
1162 task_insp = proc->task;
1163 if (task_insp == TASK_INSPECT_NULL) {
1164 goto tifpout;
1165 }
1166
1167 /*
1168 * Grab a task reference and drop the proc reference before making any upcalls.
1169 */
1170 task_reference(task_insp);
1171
1172 proc_rele(proc);
1173 proc = PROC_NULL;
1174
f427ee49 1175#if CONFIG_MACF
c3c9b80d 1176 error = mac_proc_check_get_task(kauth_cred_get(), &pident, TASK_FLAVOR_INSPECT);
f427ee49
A
1177 if (error) {
1178 error = EPERM;
1179 goto tifpout;
1180 }
1181#endif
1182
1183 /* If we aren't root and target's task access port is set... */
1184 if (!kauth_cred_issuser(kauth_cred_get()) &&
1185 !is_current_proc &&
1186 (task_get_task_access_port(task_insp, &tfpport) == 0) &&
1187 (tfpport != IPC_PORT_NULL)) {
1188 if (tfpport == IPC_PORT_DEAD) {
1189 error = EACCES;
1190 goto tifpout;
1191 }
1192
1193
1194 /* Call up to the task access server */
c3c9b80d
A
1195 error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport,
1196 proc_selfpid(), kauth_getgid(), pid, TASK_FLAVOR_INSPECT);
f427ee49
A
1197
1198 if (error != MACH_MSG_SUCCESS) {
1199 if (error == MACH_RCV_INTERRUPTED) {
1200 error = EINTR;
1201 } else {
1202 error = EPERM;
1203 }
1204 goto tifpout;
1205 }
1206 }
1207
1208 /* Check if the task has been corpsified */
1209 if (is_corpsetask(task_insp)) {
1210 error = EACCES;
1211 goto tifpout;
1212 }
1213
1214 /* could be IP_NULL, consumes a ref */
1215 sright = (void*) convert_task_inspect_to_port(task_insp);
1216 task_insp = TASK_INSPECT_NULL;
1217 tret = ipc_port_copyout_send(sright, get_task_ipcspace(current_task()));
1218
1219tifpout:
1220 task_deallocate(t1);
1221 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
1222 if (proc != PROC_NULL) {
1223 proc_rele(proc);
1224 }
1225 if (tfpport != IPC_PORT_NULL) {
1226 ipc_port_release_send(tfpport);
1227 }
1228 if (task_insp != TASK_INSPECT_NULL) {
1229 task_deallocate(task_insp);
1230 }
1231
1232 *ret = error;
1233 return error;
1234}
1235
1236/*
1237 * Routine: task_read_for_pid
1238 * Purpose:
1239 * Get the task read port for another "process", named by its
1240 * process ID on the same host as "target_task".
1241 */
1242int
1243task_read_for_pid(struct proc *p __unused, struct task_read_for_pid_args *args, int *ret)
1244{
1245 mach_port_name_t target_tport = args->target_tport;
1246 int pid = args->pid;
1247 user_addr_t task_addr = args->t;
1248
1249 proc_t proc = PROC_NULL;
1250 task_t t1 = TASK_NULL;
1251 task_read_t task_read = TASK_READ_NULL;
1252 mach_port_name_t tret = MACH_PORT_NULL;
1253 ipc_port_t tfpport = MACH_PORT_NULL;
1254 int error = 0;
1255 void *sright = NULL;
1256 boolean_t is_current_proc = FALSE;
1257 struct proc_ident pident = {0};
1258
1259 /* Disallow read port for kernel_task */
1260 if (pid == 0) {
c3c9b80d 1261 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
f427ee49
A
1262 return EPERM;
1263 }
1264
1265 t1 = port_name_to_task(target_tport);
1266 if (t1 == TASK_NULL) {
c3c9b80d 1267 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
f427ee49
A
1268 return EINVAL;
1269 }
1270
1271 proc = proc_find(pid);
1272 if (proc == PROC_NULL) {
1273 error = ESRCH;
1274 goto trfpout;
1275 }
1276 pident = proc_ident(proc);
1277 is_current_proc = (proc == current_proc());
1278
1279 if (!(task_for_pid_posix_check(proc))) {
1280 error = EPERM;
1281 goto trfpout;
1282 }
1283
1284 task_read = proc->task;
1285 if (task_read == TASK_INSPECT_NULL) {
1286 goto trfpout;
1287 }
1288
1289 /*
1290 * Grab a task reference and drop the proc reference before making any upcalls.
1291 */
1292 task_reference(task_read);
1293
1294 proc_rele(proc);
1295 proc = PROC_NULL;
1296
f427ee49 1297#if CONFIG_MACF
c3c9b80d 1298 error = mac_proc_check_get_task(kauth_cred_get(), &pident, TASK_FLAVOR_READ);
f427ee49
A
1299 if (error) {
1300 error = EPERM;
1301 goto trfpout;
1302 }
1303#endif
1304
1305 /* If we aren't root and target's task access port is set... */
1306 if (!kauth_cred_issuser(kauth_cred_get()) &&
1307 !is_current_proc &&
1308 (task_get_task_access_port(task_read, &tfpport) == 0) &&
1309 (tfpport != IPC_PORT_NULL)) {
1310 if (tfpport == IPC_PORT_DEAD) {
1311 error = EACCES;
1312 goto trfpout;
1313 }
1314
1315
1316 /* Call up to the task access server */
c3c9b80d
A
1317 error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport,
1318 proc_selfpid(), kauth_getgid(), pid, TASK_FLAVOR_READ);
f427ee49
A
1319
1320 if (error != MACH_MSG_SUCCESS) {
1321 if (error == MACH_RCV_INTERRUPTED) {
1322 error = EINTR;
1323 } else {
1324 error = EPERM;
1325 }
1326 goto trfpout;
1327 }
1328 }
1329
1330 /* Check if the task has been corpsified */
1331 if (is_corpsetask(task_read)) {
1332 error = EACCES;
1333 goto trfpout;
1334 }
1335
1336 /* could be IP_NULL, consumes a ref */
1337 sright = (void*) convert_task_read_to_port(task_read);
1338 task_read = TASK_READ_NULL;
1339 tret = ipc_port_copyout_send(sright, get_task_ipcspace(current_task()));
1340
1341trfpout:
1342 task_deallocate(t1);
1343 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
1344 if (proc != PROC_NULL) {
1345 proc_rele(proc);
1346 }
1347 if (tfpport != IPC_PORT_NULL) {
1348 ipc_port_release_send(tfpport);
1349 }
1350 if (task_read != TASK_READ_NULL) {
1351 task_deallocate(task_read);
1352 }
1353
1354 *ret = error;
1355 return error;
1356}
1357
d1ecb069
A
1358kern_return_t
1359pid_suspend(struct proc *p __unused, struct pid_suspend_args *args, int *ret)
1360{
0a7de745
A
1361 task_t target = NULL;
1362 proc_t targetproc = PROC_NULL;
1363 int pid = args->pid;
1364 int error = 0;
cb323159 1365 mach_port_t tfpport = MACH_PORT_NULL;
d1ecb069 1366
d1ecb069 1367 if (pid == 0) {
6d2010ae 1368 error = EPERM;
d1ecb069
A
1369 goto out;
1370 }
1371
1372 targetproc = proc_find(pid);
316670eb
A
1373 if (targetproc == PROC_NULL) {
1374 error = ESRCH;
1375 goto out;
1376 }
1377
cb323159
A
1378 if (!task_for_pid_posix_check(targetproc) &&
1379 !IOTaskHasEntitlement(current_task(), PROCESS_RESUME_SUSPEND_ENTITLEMENT)) {
6d2010ae 1380 error = EPERM;
d1ecb069
A
1381 goto out;
1382 }
1383
f427ee49
A
1384#if CONFIG_MACF
1385 error = mac_proc_check_suspend_resume(targetproc, MAC_PROC_CHECK_SUSPEND);
1386 if (error) {
1387 error = EPERM;
1388 goto out;
1389 }
1390#endif
1391
d1ecb069 1392 target = targetproc->task;
c3c9b80d 1393#if XNU_TARGET_OS_OSX
d1ecb069 1394 if (target != TASK_NULL) {
d1ecb069
A
1395 /* If we aren't root and target's task access port is set... */
1396 if (!kauth_cred_issuser(kauth_cred_get()) &&
0a7de745
A
1397 targetproc != current_proc() &&
1398 (task_get_task_access_port(target, &tfpport) == 0) &&
1399 (tfpport != IPC_PORT_NULL)) {
d1ecb069 1400 if (tfpport == IPC_PORT_DEAD) {
6d2010ae 1401 error = EACCES;
d1ecb069
A
1402 goto out;
1403 }
1404
1405 /* Call up to the task access server */
c3c9b80d
A
1406 error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport,
1407 proc_selfpid(), kauth_getgid(), pid, TASK_FLAVOR_CONTROL);
d1ecb069
A
1408
1409 if (error != MACH_MSG_SUCCESS) {
0a7de745 1410 if (error == MACH_RCV_INTERRUPTED) {
6d2010ae 1411 error = EINTR;
0a7de745 1412 } else {
6d2010ae 1413 error = EPERM;
0a7de745 1414 }
d1ecb069
A
1415 goto out;
1416 }
1417 }
1418 }
c3c9b80d 1419#endif /* XNU_TARGET_OS_OSX */
d1ecb069
A
1420
1421 task_reference(target);
316670eb 1422 error = task_pidsuspend(target);
6d2010ae
A
1423 if (error) {
1424 if (error == KERN_INVALID_ARGUMENT) {
1425 error = EINVAL;
1426 } else {
1427 error = EPERM;
1428 }
1429 }
316670eb
A
1430#if CONFIG_MEMORYSTATUS
1431 else {
39236c6e
A
1432 memorystatus_on_suspend(targetproc);
1433 }
6d2010ae
A
1434#endif
1435
316670eb
A
1436 task_deallocate(target);
1437
d1ecb069 1438out:
cb323159
A
1439 if (tfpport != IPC_PORT_NULL) {
1440 ipc_port_release_send(tfpport);
1441 }
1442
0a7de745 1443 if (targetproc != PROC_NULL) {
d1ecb069 1444 proc_rele(targetproc);
0a7de745 1445 }
d1ecb069
A
1446 *ret = error;
1447 return error;
1448}
1449
cb323159
A
1450kern_return_t
1451debug_control_port_for_pid(struct debug_control_port_for_pid_args *args)
1452{
1453 mach_port_name_t target_tport = args->target_tport;
1454 int pid = args->pid;
1455 user_addr_t task_addr = args->t;
1456 proc_t p = PROC_NULL;
1457 task_t t1 = TASK_NULL;
1458 task_t task = TASK_NULL;
1459 mach_port_name_t tret = MACH_PORT_NULL;
1460 ipc_port_t tfpport = MACH_PORT_NULL;
1461 ipc_port_t sright = NULL;
1462 int error = 0;
f427ee49
A
1463 boolean_t is_current_proc = FALSE;
1464 struct proc_ident pident = {0};
cb323159
A
1465
1466 AUDIT_MACH_SYSCALL_ENTER(AUE_DBGPORTFORPID);
1467 AUDIT_ARG(pid, pid);
1468 AUDIT_ARG(mach_port1, target_tport);
1469
1470 /* Always check if pid == 0 */
1471 if (pid == 0) {
c3c9b80d 1472 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
cb323159
A
1473 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
1474 return KERN_FAILURE;
1475 }
1476
1477 t1 = port_name_to_task(target_tport);
1478 if (t1 == TASK_NULL) {
c3c9b80d 1479 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
cb323159
A
1480 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
1481 return KERN_FAILURE;
1482 }
1483
cb323159
A
1484 p = proc_find(pid);
1485 if (p == PROC_NULL) {
1486 error = KERN_FAILURE;
1487 goto tfpout;
1488 }
f427ee49
A
1489 pident = proc_ident(p);
1490 is_current_proc = (p == current_proc());
cb323159
A
1491
1492#if CONFIG_AUDIT
1493 AUDIT_ARG(process, p);
1494#endif
1495
1496 if (!(task_for_pid_posix_check(p))) {
1497 error = KERN_FAILURE;
1498 goto tfpout;
1499 }
1500
1501 if (p->task == TASK_NULL) {
1502 error = KERN_SUCCESS;
1503 goto tfpout;
1504 }
1505
f427ee49
A
1506 /*
1507 * Grab a task reference and drop the proc reference before making any upcalls.
1508 */
cb323159
A
1509 task = p->task;
1510 task_reference(task);
1511
f427ee49
A
1512 proc_rele(p);
1513 p = PROC_NULL;
cb323159
A
1514
1515 if (!IOTaskHasEntitlement(current_task(), DEBUG_PORT_ENTITLEMENT)) {
1516#if CONFIG_MACF
c3c9b80d 1517 error = mac_proc_check_get_task(kauth_cred_get(), &pident, TASK_FLAVOR_CONTROL);
cb323159
A
1518 if (error) {
1519 error = KERN_FAILURE;
1520 goto tfpout;
1521 }
1522#endif
1523
1524 /* If we aren't root and target's task access port is set... */
1525 if (!kauth_cred_issuser(kauth_cred_get()) &&
f427ee49 1526 !is_current_proc &&
cb323159
A
1527 (task_get_task_access_port(task, &tfpport) == 0) &&
1528 (tfpport != IPC_PORT_NULL)) {
1529 if (tfpport == IPC_PORT_DEAD) {
1530 error = KERN_PROTECTION_FAILURE;
1531 goto tfpout;
1532 }
1533
cb323159
A
1534
1535 /* Call up to the task access server */
c3c9b80d
A
1536 error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport,
1537 proc_selfpid(), kauth_getgid(), pid, TASK_FLAVOR_CONTROL);
cb323159
A
1538
1539 if (error != MACH_MSG_SUCCESS) {
1540 if (error == MACH_RCV_INTERRUPTED) {
1541 error = KERN_ABORTED;
1542 } else {
1543 error = KERN_FAILURE;
1544 }
1545 goto tfpout;
1546 }
1547 }
1548 }
1549
1550 /* Check if the task has been corpsified */
1551 if (is_corpsetask(task)) {
1552 error = KERN_FAILURE;
1553 goto tfpout;
1554 }
1555
1556 error = task_get_debug_control_port(task, &sright);
1557 if (error != KERN_SUCCESS) {
1558 goto tfpout;
1559 }
1560
1561 tret = ipc_port_copyout_send(
1562 sright,
1563 get_task_ipcspace(current_task()));
1564
1565 error = KERN_SUCCESS;
1566
1567tfpout:
1568 task_deallocate(t1);
1569 AUDIT_ARG(mach_port2, tret);
1570 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
1571
1572 if (tfpport != IPC_PORT_NULL) {
1573 ipc_port_release_send(tfpport);
1574 }
1575 if (task != TASK_NULL) {
1576 task_deallocate(task);
1577 }
1578 if (p != PROC_NULL) {
1579 proc_rele(p);
1580 }
1581 AUDIT_MACH_SYSCALL_EXIT(error);
1582 return error;
1583}
1584
d1ecb069
A
1585kern_return_t
1586pid_resume(struct proc *p __unused, struct pid_resume_args *args, int *ret)
1587{
0a7de745
A
1588 task_t target = NULL;
1589 proc_t targetproc = PROC_NULL;
1590 int pid = args->pid;
1591 int error = 0;
cb323159 1592 mach_port_t tfpport = MACH_PORT_NULL;
d1ecb069 1593
d1ecb069 1594 if (pid == 0) {
6d2010ae 1595 error = EPERM;
d1ecb069
A
1596 goto out;
1597 }
1598
1599 targetproc = proc_find(pid);
316670eb
A
1600 if (targetproc == PROC_NULL) {
1601 error = ESRCH;
1602 goto out;
1603 }
1604
cb323159
A
1605 if (!task_for_pid_posix_check(targetproc) &&
1606 !IOTaskHasEntitlement(current_task(), PROCESS_RESUME_SUSPEND_ENTITLEMENT)) {
6d2010ae 1607 error = EPERM;
d1ecb069
A
1608 goto out;
1609 }
1610
f427ee49
A
1611#if CONFIG_MACF
1612 error = mac_proc_check_suspend_resume(targetproc, MAC_PROC_CHECK_RESUME);
1613 if (error) {
1614 error = EPERM;
1615 goto out;
1616 }
1617#endif
1618
d1ecb069 1619 target = targetproc->task;
c3c9b80d 1620#if XNU_TARGET_OS_OSX
d1ecb069 1621 if (target != TASK_NULL) {
d1ecb069
A
1622 /* If we aren't root and target's task access port is set... */
1623 if (!kauth_cred_issuser(kauth_cred_get()) &&
0a7de745
A
1624 targetproc != current_proc() &&
1625 (task_get_task_access_port(target, &tfpport) == 0) &&
1626 (tfpport != IPC_PORT_NULL)) {
d1ecb069 1627 if (tfpport == IPC_PORT_DEAD) {
6d2010ae 1628 error = EACCES;
d1ecb069
A
1629 goto out;
1630 }
1631
1632 /* Call up to the task access server */
c3c9b80d
A
1633 error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport,
1634 proc_selfpid(), kauth_getgid(), pid, TASK_FLAVOR_CONTROL);
d1ecb069
A
1635
1636 if (error != MACH_MSG_SUCCESS) {
0a7de745 1637 if (error == MACH_RCV_INTERRUPTED) {
6d2010ae 1638 error = EINTR;
0a7de745 1639 } else {
6d2010ae 1640 error = EPERM;
0a7de745 1641 }
d1ecb069
A
1642 goto out;
1643 }
1644 }
1645 }
c3c9b80d 1646#endif /* XNU_TARGET_OS_OSX */
d1ecb069 1647
f427ee49 1648#if !XNU_TARGET_OS_OSX
5ba3f43e
A
1649#if SOCKETS
1650 resume_proc_sockets(targetproc);
1651#endif /* SOCKETS */
f427ee49 1652#endif /* !XNU_TARGET_OS_OSX */
3e170ce0 1653
d1ecb069 1654 task_reference(target);
6d2010ae 1655
316670eb 1656#if CONFIG_MEMORYSTATUS
39236c6e 1657 memorystatus_on_resume(targetproc);
6d2010ae
A
1658#endif
1659
316670eb 1660 error = task_pidresume(target);
6d2010ae
A
1661 if (error) {
1662 if (error == KERN_INVALID_ARGUMENT) {
1663 error = EINVAL;
1664 } else {
39236c6e
A
1665 if (error == KERN_MEMORY_ERROR) {
1666 psignal(targetproc, SIGKILL);
1667 error = EIO;
0a7de745 1668 } else {
39236c6e 1669 error = EPERM;
0a7de745 1670 }
6d2010ae
A
1671 }
1672 }
0a7de745 1673
d1ecb069
A
1674 task_deallocate(target);
1675
1676out:
cb323159
A
1677 if (tfpport != IPC_PORT_NULL) {
1678 ipc_port_release_send(tfpport);
1679 }
1680
0a7de745 1681 if (targetproc != PROC_NULL) {
d1ecb069 1682 proc_rele(targetproc);
0a7de745
A
1683 }
1684
d1ecb069
A
1685 *ret = error;
1686 return error;
d1ecb069
A
1687}
1688
c3c9b80d 1689#if !XNU_TARGET_OS_OSX
5ba3f43e
A
1690/*
1691 * Freeze the specified process (provided in args->pid), or find and freeze a PID.
1692 * When a process is specified, this call is blocking, otherwise we wake up the
1693 * freezer thread and do not block on a process being frozen.
1694 */
1695kern_return_t
1696pid_hibernate(struct proc *p __unused, struct pid_hibernate_args *args, int *ret)
1697{
0a7de745
A
1698 int error = 0;
1699 proc_t targetproc = PROC_NULL;
1700 int pid = args->pid;
5ba3f43e
A
1701
1702#ifndef CONFIG_FREEZE
1703 #pragma unused(pid)
1704#else
1705
5ba3f43e
A
1706 /*
1707 * If a pid has been provided, we obtain the process handle and call task_for_pid_posix_check().
1708 */
1709
1710 if (pid >= 0) {
1711 targetproc = proc_find(pid);
1712
1713 if (targetproc == PROC_NULL) {
1714 error = ESRCH;
1715 goto out;
1716 }
1717
1718 if (!task_for_pid_posix_check(targetproc)) {
1719 error = EPERM;
1720 goto out;
1721 }
1722 }
1723
f427ee49
A
1724#if CONFIG_MACF
1725 //Note that targetproc may be null
1726 error = mac_proc_check_suspend_resume(targetproc, MAC_PROC_CHECK_HIBERNATE);
1727 if (error) {
1728 error = EPERM;
1729 goto out;
1730 }
1731#endif
1732
5ba3f43e
A
1733 if (pid == -2) {
1734 vm_pageout_anonymous_pages();
1735 } else if (pid == -1) {
1736 memorystatus_on_inactivity(targetproc);
1737 } else {
1738 error = memorystatus_freeze_process_sync(targetproc);
1739 }
1740
1741out:
1742
1743#endif /* CONFIG_FREEZE */
1744
0a7de745 1745 if (targetproc != PROC_NULL) {
5ba3f43e 1746 proc_rele(targetproc);
0a7de745 1747 }
5ba3f43e
A
1748 *ret = error;
1749 return error;
1750}
c3c9b80d 1751#endif /* !XNU_TARGET_OS_OSX */
5ba3f43e
A
1752
1753#if SOCKETS
a39ff7e2
A
1754int
1755networking_memstatus_callout(proc_t p, uint32_t status)
1756{
f427ee49 1757 struct fileproc *fp;
a39ff7e2
A
1758
1759 /*
1760 * proc list lock NOT held
1761 * proc lock NOT held
1762 * a reference on the proc has been held / shall be dropped by the caller.
1763 */
c3c9b80d 1764 LCK_MTX_ASSERT(&proc_list_mlock, LCK_MTX_ASSERT_NOTOWNED);
a39ff7e2
A
1765 LCK_MTX_ASSERT(&p->p_mlock, LCK_MTX_ASSERT_NOTOWNED);
1766
1767 proc_fdlock(p);
a39ff7e2 1768
f427ee49
A
1769 fdt_foreach(fp, p) {
1770 switch (FILEGLOB_DTYPE(fp->fp_glob)) {
a39ff7e2
A
1771#if NECP
1772 case DTYPE_NETPOLICY:
1773 necp_fd_memstatus(p, status,
f427ee49 1774 (struct necp_fd_data *)fp->fp_glob->fg_data);
a39ff7e2
A
1775 break;
1776#endif /* NECP */
1777 default:
1778 break;
1779 }
1780 }
1781 proc_fdunlock(p);
1782
0a7de745 1783 return 1;
a39ff7e2
A
1784}
1785
1786
5ba3f43e 1787static int
a39ff7e2 1788networking_defunct_callout(proc_t p, void *arg)
5ba3f43e
A
1789{
1790 struct pid_shutdown_sockets_args *args = arg;
1791 int pid = args->pid;
1792 int level = args->level;
f427ee49 1793 struct fileproc *fp;
5ba3f43e
A
1794
1795 proc_fdlock(p);
a39ff7e2 1796
f427ee49
A
1797 fdt_foreach(fp, p) {
1798 struct fileglob *fg = fp->fp_glob;
a39ff7e2 1799
a39ff7e2
A
1800 switch (FILEGLOB_DTYPE(fg)) {
1801 case DTYPE_SOCKET: {
1802 struct socket *so = (struct socket *)fg->fg_data;
0a7de745 1803 if (p->p_pid == pid || so->last_pid == pid ||
5ba3f43e
A
1804 ((so->so_flags & SOF_DELEGATED) && so->e_pid == pid)) {
1805 /* Call networking stack with socket and level */
f427ee49 1806 (void)socket_defunct(p, so, level);
5ba3f43e 1807 }
a39ff7e2 1808 break;
5ba3f43e
A
1809 }
1810#if NECP
a39ff7e2
A
1811 case DTYPE_NETPOLICY:
1812 /* first pass: defunct necp and get stats for ntstat */
1813 if (p->p_pid == pid) {
1814 necp_fd_defunct(p,
1815 (struct necp_fd_data *)fg->fg_data);
1816 }
1817 break;
5ba3f43e 1818#endif /* NECP */
a39ff7e2
A
1819 default:
1820 break;
1821 }
5ba3f43e 1822 }
a39ff7e2 1823
5ba3f43e
A
1824 proc_fdunlock(p);
1825
0a7de745 1826 return PROC_RETURNED;
5ba3f43e
A
1827}
1828
1829int
1830pid_shutdown_sockets(struct proc *p __unused, struct pid_shutdown_sockets_args *args, int *ret)
1831{
0a7de745
A
1832 int error = 0;
1833 proc_t targetproc = PROC_NULL;
1834 int pid = args->pid;
1835 int level = args->level;
5ba3f43e
A
1836
1837 if (level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC &&
1838 level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL) {
1839 error = EINVAL;
1840 goto out;
1841 }
1842
5ba3f43e
A
1843 targetproc = proc_find(pid);
1844 if (targetproc == PROC_NULL) {
1845 error = ESRCH;
1846 goto out;
1847 }
1848
cb323159
A
1849 if (!task_for_pid_posix_check(targetproc) &&
1850 !IOTaskHasEntitlement(current_task(), PROCESS_RESUME_SUSPEND_ENTITLEMENT)) {
5ba3f43e
A
1851 error = EPERM;
1852 goto out;
1853 }
1854
f427ee49
A
1855#if CONFIG_MACF
1856 error = mac_proc_check_suspend_resume(targetproc, MAC_PROC_CHECK_SHUTDOWN_SOCKETS);
1857 if (error) {
1858 error = EPERM;
1859 goto out;
1860 }
1861#endif
1862
a39ff7e2
A
1863 proc_iterate(PROC_ALLPROCLIST | PROC_NOWAITTRANS,
1864 networking_defunct_callout, args, NULL, NULL);
5ba3f43e
A
1865
1866out:
0a7de745 1867 if (targetproc != PROC_NULL) {
5ba3f43e 1868 proc_rele(targetproc);
0a7de745 1869 }
5ba3f43e
A
1870 *ret = error;
1871 return error;
1872}
1873
1874#endif /* SOCKETS */
6d2010ae 1875
0c530ab8
A
1876static int
1877sysctl_settfp_policy(__unused struct sysctl_oid *oidp, void *arg1,
1878 __unused int arg2, struct sysctl_req *req)
1879{
0a7de745 1880 int error = 0;
0c530ab8
A
1881 int new_value;
1882
0a7de745
A
1883 error = SYSCTL_OUT(req, arg1, sizeof(int));
1884 if (error || req->newptr == USER_ADDR_NULL) {
1885 return error;
1886 }
0c530ab8 1887
0a7de745
A
1888 if (!kauth_cred_issuser(kauth_cred_get())) {
1889 return EPERM;
1890 }
0c530ab8
A
1891
1892 if ((error = SYSCTL_IN(req, &new_value, sizeof(int)))) {
1893 goto out;
1894 }
0a7de745
A
1895 if ((new_value == KERN_TFP_POLICY_DENY)
1896 || (new_value == KERN_TFP_POLICY_DEFAULT)) {
1897 tfp_policy = new_value;
1898 } else {
1899 error = EINVAL;
1900 }
0c530ab8 1901out:
0a7de745 1902 return error;
0c530ab8
A
1903}
1904
2d21ac55
A
1905#if defined(SECURE_KERNEL)
1906static int kern_secure_kernel = 1;
1907#else
1908static int kern_secure_kernel = 0;
1909#endif
0c530ab8 1910
6d2010ae 1911SYSCTL_INT(_kern, OID_AUTO, secure_kernel, CTLFLAG_RD | CTLFLAG_LOCKED, &kern_secure_kernel, 0, "");
0c530ab8 1912
6d2010ae
A
1913SYSCTL_NODE(_kern, KERN_TFP, tfp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "tfp");
1914SYSCTL_PROC(_kern_tfp, KERN_TFP_POLICY, policy, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 1915 &tfp_policy, sizeof(uint32_t), &sysctl_settfp_policy, "I", "policy");
0c530ab8 1916
6d2010ae 1917SYSCTL_INT(_vm, OID_AUTO, shared_region_trace_level, CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 1918 &shared_region_trace_level, 0, "");
6d2010ae 1919SYSCTL_INT(_vm, OID_AUTO, shared_region_version, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 1920 &shared_region_version, 0, "");
6d2010ae 1921SYSCTL_INT(_vm, OID_AUTO, shared_region_persistence, CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 1922 &shared_region_persistence, 0, "");
1c79356b 1923
91447636 1924/*
2d21ac55 1925 * shared_region_check_np:
91447636 1926 *
2d21ac55
A
1927 * This system call is intended for dyld.
1928 *
1929 * dyld calls this when any process starts to see if the process's shared
1930 * region is already set up and ready to use.
1931 * This call returns the base address of the first mapping in the
1932 * process's shared region's first mapping.
1933 * dyld will then check what's mapped at that address.
1934 *
1935 * If the shared region is empty, dyld will then attempt to map the shared
1936 * cache file in the shared region via the shared_region_map_np() system call.
1937 *
1938 * If something's already mapped in the shared region, dyld will check if it
1939 * matches the shared cache it would like to use for that process.
1940 * If it matches, evrything's ready and the process can proceed and use the
1941 * shared region.
1942 * If it doesn't match, dyld will unmap the shared region and map the shared
1943 * cache into the process's address space via mmap().
1944 *
1945 * ERROR VALUES
1946 * EINVAL no shared region
1947 * ENOMEM shared region is empty
1948 * EFAULT bad address for "start_address"
91447636
A
1949 */
1950int
2d21ac55 1951shared_region_check_np(
0a7de745
A
1952 __unused struct proc *p,
1953 struct shared_region_check_np_args *uap,
1954 __unused int *retvalp)
91447636 1955{
0a7de745
A
1956 vm_shared_region_t shared_region;
1957 mach_vm_offset_t start_address = 0;
f427ee49 1958 int error = 0;
0a7de745 1959 kern_return_t kr;
c3c9b80d 1960 task_t task = current_task();
2d21ac55
A
1961
1962 SHARED_REGION_TRACE_DEBUG(
1963 ("shared_region: %p [%d(%s)] -> check_np(0x%llx)\n",
0a7de745
A
1964 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1965 p->p_pid, p->p_comm,
1966 (uint64_t)uap->start_address));
2d21ac55
A
1967
1968 /* retrieve the current tasks's shared region */
c3c9b80d 1969 shared_region = vm_shared_region_get(task);
2d21ac55
A
1970 if (shared_region != NULL) {
1971 /* retrieve address of its first mapping... */
c3c9b80d 1972 kr = vm_shared_region_start_address(shared_region, &start_address, task);
91447636
A
1973 if (kr != KERN_SUCCESS) {
1974 error = ENOMEM;
2d21ac55 1975 } else {
f427ee49
A
1976#if __has_feature(ptrauth_calls)
1977 /*
1978 * Remap any section of the shared library that
1979 * has authenticated pointers into private memory.
1980 */
1981 if (vm_shared_region_auth_remap(shared_region) != KERN_SUCCESS) {
1982 error = ENOMEM;
1983 }
1984#endif /* __has_feature(ptrauth_calls) */
1985
2d21ac55 1986 /* ... and give it to the caller */
f427ee49
A
1987 if (error == 0) {
1988 error = copyout(&start_address,
1989 (user_addr_t) uap->start_address,
1990 sizeof(start_address));
1991 }
1992 if (error != 0) {
2d21ac55
A
1993 SHARED_REGION_TRACE_ERROR(
1994 ("shared_region: %p [%d(%s)] "
0a7de745
A
1995 "check_np(0x%llx) "
1996 "copyout(0x%llx) error %d\n",
1997 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1998 p->p_pid, p->p_comm,
1999 (uint64_t)uap->start_address, (uint64_t)start_address,
2000 error));
2d21ac55 2001 }
91447636 2002 }
2d21ac55 2003 vm_shared_region_deallocate(shared_region);
91447636 2004 } else {
2d21ac55 2005 /* no shared region ! */
91447636 2006 error = EINVAL;
91447636 2007 }
0c530ab8 2008
2d21ac55
A
2009 SHARED_REGION_TRACE_DEBUG(
2010 ("shared_region: %p [%d(%s)] check_np(0x%llx) <- 0x%llx %d\n",
0a7de745
A
2011 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2012 p->p_pid, p->p_comm,
2013 (uint64_t)uap->start_address, (uint64_t)start_address, error));
0c530ab8 2014
91447636
A
2015 return error;
2016}
2017
6d2010ae 2018
f427ee49
A
2019static int
2020shared_region_copyin(
2021 struct proc *p,
2022 user_addr_t user_addr,
2023 unsigned int count,
2024 unsigned int element_size,
2025 void *kernel_data)
6d2010ae 2026{
0a7de745 2027 int error = 0;
f427ee49 2028 vm_size_t size = count * element_size;
6d2010ae 2029
f427ee49 2030 error = copyin(user_addr, kernel_data, size);
6d2010ae
A
2031 if (error) {
2032 SHARED_REGION_TRACE_ERROR(
2033 ("shared_region: %p [%d(%s)] map(): "
f427ee49 2034 "copyin(0x%llx, %ld) failed (error=%d)\n",
0a7de745
A
2035 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2036 p->p_pid, p->p_comm,
f427ee49 2037 (uint64_t)user_addr, (long)size, error));
6d2010ae
A
2038 }
2039 return error;
2040}
f427ee49
A
2041
2042#define _SR_FILE_MAPPINGS_MAX_FILES 2
2043
2044/* forward declaration */
2045__attribute__((noinline))
2046static void shared_region_map_and_slide_cleanup(
2047 struct proc *p,
2048 uint32_t files_count,
2049 struct _sr_file_mappings *sr_file_mappings,
2050 struct vm_shared_region *shared_region,
2051 struct vnode *scdir_vp);
2052
91447636 2053/*
f427ee49
A
2054 * Setup part of _shared_region_map_and_slide().
2055 * It had to be broken out of _shared_region_map_and_slide() to
2056 * prevent compiler inlining from blowing out the stack.
91447636 2057 */
f427ee49
A
2058__attribute__((noinline))
2059static int
2060shared_region_map_and_slide_setup(
2061 struct proc *p,
2062 uint32_t files_count,
2063 struct shared_file_np *files,
2064 uint32_t mappings_count,
2065 struct shared_file_mapping_slide_np *mappings,
2066 struct _sr_file_mappings **sr_file_mappings,
2a1bd2d3
A
2067 struct vm_shared_region **shared_region_ptr,
2068 struct vnode **scdir_vp,
2069 struct vnode *rdir_vp)
91447636 2070{
f427ee49
A
2071 int error = 0;
2072 struct _sr_file_mappings *srfmp;
2073 uint32_t mappings_next;
0a7de745
A
2074 struct vnode_attr va;
2075 off_t fs;
39236c6e 2076#if CONFIG_MACF
0a7de745 2077 vm_prot_t maxprot = VM_PROT_ALL;
39236c6e 2078#endif
0a7de745 2079 uint32_t i;
2a1bd2d3 2080 struct vm_shared_region *shared_region;
2d21ac55
A
2081
2082 SHARED_REGION_TRACE_DEBUG(
2083 ("shared_region: %p [%d(%s)] -> map\n",
0a7de745
A
2084 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2085 p->p_pid, p->p_comm));
2d21ac55 2086
f427ee49
A
2087 if (files_count > _SR_FILE_MAPPINGS_MAX_FILES) {
2088 error = E2BIG;
91447636
A
2089 goto done;
2090 }
f427ee49 2091 if (files_count == 0) {
91447636
A
2092 error = EINVAL;
2093 goto done;
2094 }
f427ee49
A
2095 *sr_file_mappings = kheap_alloc(KHEAP_TEMP, files_count * sizeof(struct _sr_file_mappings), Z_WAITOK);
2096 if (*sr_file_mappings == NULL) {
2097 error = ENOMEM;
91447636
A
2098 goto done;
2099 }
f427ee49
A
2100 bzero(*sr_file_mappings, files_count * sizeof(struct _sr_file_mappings));
2101 mappings_next = 0;
2102 for (i = 0; i < files_count; i++) {
2103 srfmp = &(*sr_file_mappings)[i];
2104 srfmp->fd = files[i].sf_fd;
2105 srfmp->mappings_count = files[i].sf_mappings_count;
2106 srfmp->mappings = &mappings[mappings_next];
2107 mappings_next += srfmp->mappings_count;
2108 if (mappings_next > mappings_count) {
2109 error = EINVAL;
2110 goto done;
2111 }
2112 srfmp->slide = files[i].sf_slide;
2113 }
91447636 2114
f427ee49
A
2115 if (scdir_enforce) {
2116 /* get vnode for scdir_path */
2117 error = vnode_lookup(scdir_path, 0, scdir_vp, vfs_context_current());
2118 if (error) {
2119 SHARED_REGION_TRACE_ERROR(
2120 ("shared_region: %p [%d(%s)]: "
2121 "vnode_lookup(%s) failed (error=%d)\n",
2122 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2123 p->p_pid, p->p_comm,
2124 scdir_path, error));
2125 goto done;
2126 }
91447636 2127 }
91447636 2128
f427ee49 2129 /* get the process's shared region (setup in vm_map_exec()) */
2a1bd2d3
A
2130 shared_region = vm_shared_region_trim_and_get(current_task());
2131 *shared_region_ptr = shared_region;
2132 if (shared_region == NULL) {
2d21ac55 2133 SHARED_REGION_TRACE_ERROR(
f427ee49
A
2134 ("shared_region: %p [%d(%s)] map(): "
2135 "no shared region\n",
0a7de745 2136 (void *)VM_KERNEL_ADDRPERM(current_thread()),
f427ee49 2137 p->p_pid, p->p_comm));
91447636
A
2138 error = EINVAL;
2139 goto done;
2140 }
2141
2a1bd2d3
A
2142 /*
2143 * Check the shared region matches the current root
2144 * directory of this process. Deny the mapping to
2145 * avoid tainting the shared region with something that
2146 * doesn't quite belong into it.
2147 */
2148 struct vnode *sr_vnode = vm_shared_region_root_dir(shared_region);
2149 if (sr_vnode != NULL ? rdir_vp != sr_vnode : rdir_vp != rootvnode) {
2150 SHARED_REGION_TRACE_ERROR(
2151 ("shared_region: map(%p) root_dir mismatch\n",
2152 (void *)VM_KERNEL_ADDRPERM(current_thread())));
2153 error = EPERM;
2154 goto done;
2155 }
2156
2157
f427ee49
A
2158 for (srfmp = &(*sr_file_mappings)[0];
2159 srfmp < &(*sr_file_mappings)[files_count];
2160 srfmp++) {
2161 if (srfmp->mappings_count == 0) {
2162 /* no mappings here... */
2163 continue;
2164 }
6d2010ae 2165
f427ee49
A
2166 /* get file structure from file descriptor */
2167 error = fp_get_ftype(p, srfmp->fd, DTYPE_VNODE, EINVAL, &srfmp->fp);
2168 if (error) {
2169 SHARED_REGION_TRACE_ERROR(
2170 ("shared_region: %p [%d(%s)] map: "
2171 "fd=%d lookup failed (error=%d)\n",
2172 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2173 p->p_pid, p->p_comm, srfmp->fd, error));
2174 goto done;
2175 }
91447636 2176
f427ee49
A
2177 /* we need at least read permission on the file */
2178 if (!(srfmp->fp->fp_glob->fg_flag & FREAD)) {
2179 SHARED_REGION_TRACE_ERROR(
2180 ("shared_region: %p [%d(%s)] map: "
2181 "fd=%d not readable\n",
2182 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2183 p->p_pid, p->p_comm, srfmp->fd));
2184 error = EPERM;
2185 goto done;
2186 }
2d21ac55 2187
f427ee49
A
2188 /* get vnode from file structure */
2189 error = vnode_getwithref((vnode_t) srfmp->fp->fp_glob->fg_data);
2190 if (error) {
2191 SHARED_REGION_TRACE_ERROR(
2192 ("shared_region: %p [%d(%s)] map: "
2193 "fd=%d getwithref failed (error=%d)\n",
2194 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2195 p->p_pid, p->p_comm, srfmp->fd, error));
2196 goto done;
2197 }
2198 srfmp->vp = (struct vnode *) srfmp->fp->fp_glob->fg_data;
2199
2200 /* make sure the vnode is a regular file */
2201 if (srfmp->vp->v_type != VREG) {
2202 SHARED_REGION_TRACE_ERROR(
2203 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
2204 "not a file (type=%d)\n",
2205 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2206 p->p_pid, p->p_comm,
2207 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2208 srfmp->vp->v_name, srfmp->vp->v_type));
2209 error = EINVAL;
2210 goto done;
2211 }
2212
2213#if CONFIG_MACF
2214 /* pass in 0 for the offset argument because AMFI does not need the offset
2215 * of the shared cache */
2216 error = mac_file_check_mmap(vfs_context_ucred(vfs_context_current()),
2217 srfmp->fp->fp_glob, VM_PROT_ALL, MAP_FILE, 0, &maxprot);
2218 if (error) {
2219 goto done;
2220 }
2221#endif /* MAC */
2222
2223#if XNU_TARGET_OS_OSX && defined(__arm64__)
cb323159 2224 /*
f427ee49
A
2225 * Check if the shared cache is in the trust cache;
2226 * if so, we can skip the root ownership check.
cb323159 2227 */
f427ee49
A
2228#if DEVELOPMENT || DEBUG
2229 /*
2230 * Skip both root ownership and trust cache check if
2231 * enforcement is disabled.
2232 */
2233 if (!cs_system_enforcement()) {
2234 goto after_root_check;
2235 }
2236#endif /* DEVELOPMENT || DEBUG */
2237 struct cs_blob *blob = csvnode_get_blob(srfmp->vp, 0);
2238 if (blob == NULL) {
2239 SHARED_REGION_TRACE_ERROR(
2240 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
2241 "missing CS blob\n",
2242 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2243 p->p_pid, p->p_comm,
2244 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2245 srfmp->vp->v_name));
2246 goto root_check;
2247 }
2248 const uint8_t *cdhash = csblob_get_cdhash(blob);
2249 if (cdhash == NULL) {
2250 SHARED_REGION_TRACE_ERROR(
2251 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
2252 "missing cdhash\n",
2253 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2254 p->p_pid, p->p_comm,
2255 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2256 srfmp->vp->v_name));
2257 goto root_check;
2258 }
2259 uint32_t result = pmap_lookup_in_static_trust_cache(cdhash);
2260 boolean_t in_trust_cache = result & (TC_LOOKUP_FOUND << TC_LOOKUP_RESULT_SHIFT);
2261 if (!in_trust_cache) {
2262 SHARED_REGION_TRACE_ERROR(
2263 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
2264 "not in trust cache\n",
2265 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2266 p->p_pid, p->p_comm,
2267 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2268 srfmp->vp->v_name));
2269 goto root_check;
2270 }
2271 goto after_root_check;
2272root_check:
2273#endif /* XNU_TARGET_OS_OSX && defined(__arm64__) */
cb323159 2274
f427ee49
A
2275 /* The shared cache file must be owned by root */
2276 VATTR_INIT(&va);
2277 VATTR_WANTED(&va, va_uid);
2278 error = vnode_getattr(srfmp->vp, &va, vfs_context_current());
fe8ab488
A
2279 if (error) {
2280 SHARED_REGION_TRACE_ERROR(
2281 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
f427ee49 2282 "vnode_getattr(%p) failed (error=%d)\n",
0a7de745
A
2283 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2284 p->p_pid, p->p_comm,
f427ee49
A
2285 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2286 srfmp->vp->v_name,
2287 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2288 error));
fe8ab488
A
2289 goto done;
2290 }
f427ee49 2291 if (va.va_uid != 0) {
fe8ab488
A
2292 SHARED_REGION_TRACE_ERROR(
2293 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
f427ee49 2294 "owned by uid=%d instead of 0\n",
0a7de745
A
2295 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2296 p->p_pid, p->p_comm,
f427ee49
A
2297 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2298 srfmp->vp->v_name, va.va_uid));
fe8ab488
A
2299 error = EPERM;
2300 goto done;
2301 }
fe8ab488 2302
f427ee49
A
2303#if XNU_TARGET_OS_OSX && defined(__arm64__)
2304after_root_check:
2305#endif /* XNU_TARGET_OS_OSX && defined(__arm64__) */
91447636 2306
f427ee49
A
2307#if CONFIG_CSR
2308 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
2309 VATTR_INIT(&va);
2310 VATTR_WANTED(&va, va_flags);
2311 error = vnode_getattr(srfmp->vp, &va, vfs_context_current());
2312 if (error) {
2313 SHARED_REGION_TRACE_ERROR(
2314 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
2315 "vnode_getattr(%p) failed (error=%d)\n",
2316 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2317 p->p_pid, p->p_comm,
2318 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2319 srfmp->vp->v_name,
2320 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2321 error));
2322 goto done;
2323 }
91447636 2324
f427ee49
A
2325 if (!(va.va_flags & SF_RESTRICTED)) {
2326 /*
2327 * CSR is not configured in CSR_ALLOW_UNRESTRICTED_FS mode, and
2328 * the shared cache file is NOT SIP-protected, so reject the
2329 * mapping request
2330 */
2331 SHARED_REGION_TRACE_ERROR(
2332 ("shared_region: %p [%d(%s)] map(%p:'%s'), "
2333 "vnode is not SIP-protected. \n",
2334 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2335 p->p_pid, p->p_comm,
2336 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2337 srfmp->vp->v_name));
2338 error = EPERM;
2339 goto done;
0a7de745 2340 }
f427ee49
A
2341 }
2342#else /* CONFIG_CSR */
2343 /* Devices without SIP/ROSP need to make sure that the shared cache is on the root volume. */
2344
2a1bd2d3
A
2345 assert(rdir_vp != NULL);
2346 if (srfmp->vp->v_mount != rdir_vp->v_mount) {
f427ee49
A
2347 SHARED_REGION_TRACE_ERROR(
2348 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
2349 "not on process's root volume\n",
2350 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2351 p->p_pid, p->p_comm,
2352 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2353 srfmp->vp->v_name));
2354 error = EPERM;
2355 goto done;
2356 }
2357#endif /* CONFIG_CSR */
2358
2359 if (scdir_enforce) {
2360 /* ensure parent is scdir_vp */
2361 assert(*scdir_vp != NULL);
2362 if (vnode_parent(srfmp->vp) != *scdir_vp) {
2363 SHARED_REGION_TRACE_ERROR(
2364 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
2365 "shared cache file not in %s\n",
2366 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2367 p->p_pid, p->p_comm,
2368 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2369 srfmp->vp->v_name, scdir_path));
2370 error = EPERM;
2371 goto done;
0a7de745 2372 }
f427ee49
A
2373 }
2374
2375 /* get vnode size */
2376 error = vnode_size(srfmp->vp, &fs, vfs_context_current());
2377 if (error) {
0a7de745
A
2378 SHARED_REGION_TRACE_ERROR(
2379 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
f427ee49 2380 "vnode_size(%p) failed (error=%d)\n",
0a7de745
A
2381 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2382 p->p_pid, p->p_comm,
f427ee49
A
2383 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2384 srfmp->vp->v_name,
2385 (void *)VM_KERNEL_ADDRPERM(srfmp->vp), error));
2386 goto done;
2387 }
2388 srfmp->file_size = fs;
2389
2390 /* get the file's memory object handle */
2391 srfmp->file_control = ubc_getobject(srfmp->vp, UBC_HOLDOBJECT);
2392 if (srfmp->file_control == MEMORY_OBJECT_CONTROL_NULL) {
2393 SHARED_REGION_TRACE_ERROR(
2394 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
2395 "no memory object\n",
2396 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2397 p->p_pid, p->p_comm,
2398 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2399 srfmp->vp->v_name));
0a7de745
A
2400 error = EINVAL;
2401 goto done;
39037602 2402 }
f427ee49
A
2403
2404 /* check that the mappings are properly covered by code signatures */
2405 if (!cs_system_enforcement()) {
2406 /* code signing is not enforced: no need to check */
2407 } else {
2408 for (i = 0; i < srfmp->mappings_count; i++) {
2409 if (srfmp->mappings[i].sms_init_prot & VM_PROT_ZF) {
2410 /* zero-filled mapping: not backed by the file */
2411 continue;
2412 }
2413 if (ubc_cs_is_range_codesigned(srfmp->vp,
2414 srfmp->mappings[i].sms_file_offset,
2415 srfmp->mappings[i].sms_size)) {
2416 /* this mapping is fully covered by code signatures */
2417 continue;
2418 }
2419 SHARED_REGION_TRACE_ERROR(
2420 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
2421 "mapping #%d/%d [0x%llx:0x%llx:0x%llx:0x%x:0x%x] "
2422 "is not code-signed\n",
2423 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2424 p->p_pid, p->p_comm,
2425 (void *)VM_KERNEL_ADDRPERM(srfmp->vp),
2426 srfmp->vp->v_name,
2427 i, srfmp->mappings_count,
2428 srfmp->mappings[i].sms_address,
2429 srfmp->mappings[i].sms_size,
2430 srfmp->mappings[i].sms_file_offset,
2431 srfmp->mappings[i].sms_max_prot,
2432 srfmp->mappings[i].sms_init_prot));
2433 error = EINVAL;
2434 goto done;
2435 }
2436 }
39037602 2437 }
f427ee49
A
2438done:
2439 if (error != 0) {
2a1bd2d3 2440 shared_region_map_and_slide_cleanup(p, files_count, *sr_file_mappings, shared_region, *scdir_vp);
f427ee49 2441 *sr_file_mappings = NULL;
2a1bd2d3 2442 *shared_region_ptr = NULL;
f427ee49
A
2443 *scdir_vp = NULL;
2444 }
2445 return error;
2446}
91447636 2447
f427ee49
A
2448/*
2449 * shared_region_map_np()
2450 *
2451 * This system call is intended for dyld.
2452 *
2453 * dyld uses this to map a shared cache file into a shared region.
2454 * This is usually done only the first time a shared cache is needed.
2455 * Subsequent processes will just use the populated shared region without
2456 * requiring any further setup.
2457 */
2458static int
2459_shared_region_map_and_slide(
2460 struct proc *p,
2461 uint32_t files_count,
2462 struct shared_file_np *files,
2463 uint32_t mappings_count,
2464 struct shared_file_mapping_slide_np *mappings)
2465{
2466 int error = 0;
2467 kern_return_t kr = KERN_SUCCESS;
2468 struct _sr_file_mappings *sr_file_mappings = NULL;
2469 struct vnode *scdir_vp = NULL;
2a1bd2d3 2470 struct vnode *rdir_vp = NULL;
f427ee49
A
2471 struct vm_shared_region *shared_region = NULL;
2472
2a1bd2d3
A
2473 /*
2474 * Get a reference to the current proc's root dir.
2475 * Need this to prevent racing with chroot.
2476 */
2477 proc_fdlock(p);
2478 rdir_vp = p->p_fd->fd_rdir;
2479 if (rdir_vp == NULL) {
2480 rdir_vp = rootvnode;
2481 }
2482 assert(rdir_vp != NULL);
2483 vnode_get(rdir_vp);
2484 proc_fdunlock(p);
2485
f427ee49
A
2486 /*
2487 * Turn files, mappings into sr_file_mappings and other setup.
2488 */
2489 error = shared_region_map_and_slide_setup(p, files_count,
2490 files, mappings_count, mappings,
2a1bd2d3 2491 &sr_file_mappings, &shared_region, &scdir_vp, rdir_vp);
f427ee49 2492 if (error != 0) {
2a1bd2d3 2493 vnode_put(rdir_vp);
f427ee49 2494 return error;
2d21ac55 2495 }
91447636 2496
f427ee49 2497 /* map the file(s) into that shared region's submap */
2a1bd2d3 2498 kr = vm_shared_region_map_file(shared_region, files_count, sr_file_mappings);
2d21ac55 2499 if (kr != KERN_SUCCESS) {
f427ee49
A
2500 SHARED_REGION_TRACE_ERROR(("shared_region: %p [%d(%s)] map(): "
2501 "vm_shared_region_map_file() failed kr=0x%x\n",
2502 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2503 p->p_pid, p->p_comm, kr));
2504 }
2505
2506 /* convert kern_return_t to errno */
2507 switch (kr) {
2508 case KERN_SUCCESS:
2509 error = 0;
2510 break;
2511 case KERN_INVALID_ADDRESS:
2512 error = EFAULT;
2513 break;
2514 case KERN_PROTECTION_FAILURE:
2515 error = EPERM;
2516 break;
2517 case KERN_NO_SPACE:
2518 error = ENOMEM;
2519 break;
2520 case KERN_FAILURE:
2521 case KERN_INVALID_ARGUMENT:
2522 default:
2523 error = EINVAL;
2524 break;
91447636
A
2525 }
2526
f427ee49
A
2527 /*
2528 * Mark that this process is now using split libraries.
2529 */
2530 if (error == 0 && (p->p_flag & P_NOSHLIB)) {
2531 OSBitAndAtomic(~((uint32_t)P_NOSHLIB), &p->p_flag);
2532 }
2d21ac55 2533
2a1bd2d3 2534 vnode_put(rdir_vp);
f427ee49 2535 shared_region_map_and_slide_cleanup(p, files_count, sr_file_mappings, shared_region, scdir_vp);
6d2010ae 2536
f427ee49
A
2537 SHARED_REGION_TRACE_DEBUG(
2538 ("shared_region: %p [%d(%s)] <- map\n",
2539 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2540 p->p_pid, p->p_comm));
6d2010ae 2541
f427ee49
A
2542 return error;
2543}
6d2010ae 2544
f427ee49
A
2545/*
2546 * Clean up part of _shared_region_map_and_slide()
2547 * It had to be broken out of _shared_region_map_and_slide() to
2548 * prevent compiler inlining from blowing out the stack.
2549 */
2550__attribute__((noinline))
2551static void
2552shared_region_map_and_slide_cleanup(
2553 struct proc *p,
2554 uint32_t files_count,
2555 struct _sr_file_mappings *sr_file_mappings,
2556 struct vm_shared_region *shared_region,
2557 struct vnode *scdir_vp)
2558{
2559 struct _sr_file_mappings *srfmp;
2560 struct vnode_attr va;
2561
2562 if (sr_file_mappings != NULL) {
2563 for (srfmp = &sr_file_mappings[0]; srfmp < &sr_file_mappings[files_count]; srfmp++) {
2564 if (srfmp->vp != NULL) {
2565 vnode_lock_spin(srfmp->vp);
2566 srfmp->vp->v_flag |= VSHARED_DYLD;
2567 vnode_unlock(srfmp->vp);
2568
2569 /* update the vnode's access time */
2570 if (!(vnode_vfsvisflags(srfmp->vp) & MNT_NOATIME)) {
2571 VATTR_INIT(&va);
2572 nanotime(&va.va_access_time);
2573 VATTR_SET_ACTIVE(&va, va_access_time);
2574 vnode_setattr(srfmp->vp, &va, vfs_context_current());
2575 }
91447636 2576
f427ee49
A
2577#if NAMEDSTREAMS
2578 /*
2579 * If the shared cache is compressed, it may
2580 * have a namedstream vnode instantiated for
2581 * for it. That namedstream vnode will also
2582 * have to be marked with VSHARED_DYLD.
2583 */
2584 if (vnode_hasnamedstreams(srfmp->vp)) {
2585 vnode_t svp;
2586 if (vnode_getnamedstream(srfmp->vp, &svp, XATTR_RESOURCEFORK_NAME,
2587 NS_OPEN, 0, vfs_context_kernel()) == 0) {
2588 vnode_lock_spin(svp);
2589 svp->v_flag |= VSHARED_DYLD;
2590 vnode_unlock(svp);
2591 vnode_put(svp);
2592 }
2593 }
2594#endif /* NAMEDSTREAMS */
2595 /*
2596 * release the vnode...
2597 * ubc_map() still holds it for us in the non-error case
2598 */
2599 (void) vnode_put(srfmp->vp);
2600 srfmp->vp = NULL;
2601 }
2602 if (srfmp->fp != NULL) {
2603 /* release the file descriptor */
2604 fp_drop(p, srfmp->fd, srfmp->fp, 0);
2605 srfmp->fp = NULL;
2606 }
2607 }
2608 kheap_free(KHEAP_TEMP, sr_file_mappings, files_count * sizeof(*sr_file_mappings));
91447636
A
2609 }
2610
fe8ab488
A
2611 if (scdir_vp != NULL) {
2612 (void)vnode_put(scdir_vp);
2613 scdir_vp = NULL;
2614 }
9bccf70c 2615
2d21ac55
A
2616 if (shared_region != NULL) {
2617 vm_shared_region_deallocate(shared_region);
9bccf70c 2618 }
f427ee49 2619}
9bccf70c 2620
9bccf70c 2621
f427ee49 2622#define SFM_MAX 1024 /* max mapping structs allowed to pass in */
9bccf70c 2623
f427ee49
A
2624/*
2625 * This interface is used by dyld to map shared caches which are
2626 * for any architecture which doesn't have run time support of pointer
2627 * authentication. Note dyld could also use the new ...map_and_slide_2_np()
2628 * call for this case, however, it just doesn't do that yet.
2629 */
6d2010ae
A
2630int
2631shared_region_map_and_slide_np(
f427ee49
A
2632 struct proc *p,
2633 struct shared_region_map_and_slide_np_args *uap,
2634 __unused int *retvalp)
6d2010ae 2635{
f427ee49
A
2636 unsigned int mappings_count = uap->count;
2637 unsigned int m;
2638 uint32_t slide = uap->slide;
2639 struct shared_file_np shared_files[1];
2640 struct shared_file_mapping_np legacy_mapping;
2641 struct shared_file_mapping_slide_np *mappings = NULL;
2642 kern_return_t kr = KERN_SUCCESS;
0a7de745 2643
6d2010ae
A
2644 if ((kr = vm_shared_region_sliding_valid(slide)) != KERN_SUCCESS) {
2645 if (kr == KERN_INVALID_ARGUMENT) {
2646 /*
0a7de745 2647 * This will happen if we request sliding again
6d2010ae 2648 * with the same slide value that was used earlier
316670eb 2649 * for the very first sliding.
6d2010ae
A
2650 */
2651 kr = KERN_SUCCESS;
6d2010ae 2652 }
316670eb 2653 goto done;
6d2010ae
A
2654 }
2655
2656 if (mappings_count == 0) {
2657 SHARED_REGION_TRACE_INFO(
2658 ("shared_region: %p [%d(%s)] map(): "
0a7de745
A
2659 "no mappings\n",
2660 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2661 p->p_pid, p->p_comm));
2662 kr = 0; /* no mappings: we're done ! */
6d2010ae 2663 goto done;
f427ee49
A
2664 } else if (mappings_count <= SFM_MAX) {
2665 mappings = kheap_alloc(KHEAP_TEMP,
2666 mappings_count * sizeof(mappings[0]), Z_WAITOK);
2667 if (mappings == NULL) {
2668 kr = KERN_RESOURCE_SHORTAGE;
2669 goto done;
2670 }
6d2010ae
A
2671 } else {
2672 SHARED_REGION_TRACE_ERROR(
2673 ("shared_region: %p [%d(%s)] map(): "
f427ee49 2674 "too many mappings (%d) max %d\n",
0a7de745
A
2675 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2676 p->p_pid, p->p_comm,
f427ee49 2677 mappings_count, SFM_MAX));
6d2010ae
A
2678 kr = KERN_FAILURE;
2679 goto done;
2680 }
2681
f427ee49
A
2682 /*
2683 * Read in the mappings and translate to new format.
2684 */
2685 for (m = 0; m < mappings_count; ++m) {
2686 user_addr_t from_uaddr = uap->mappings + (m * sizeof(struct shared_file_mapping_np));
2687 kr = shared_region_copyin(p, from_uaddr, 1, sizeof(legacy_mapping), &legacy_mapping);
2688 if (kr != 0) {
2689 goto done;
2690 }
2691 mappings[m].sms_address = legacy_mapping.sfm_address;
2692 mappings[m].sms_size = legacy_mapping.sfm_size;
2693 mappings[m].sms_file_offset = legacy_mapping.sfm_file_offset;
2694 mappings[m].sms_max_prot = legacy_mapping.sfm_max_prot;
2695 mappings[m].sms_init_prot = legacy_mapping.sfm_init_prot;
2696 mappings[m].sms_slide_size = uap->slide_size;
2697 mappings[m].sms_slide_start = uap->slide_start;
2698 }
2699
2700 bzero(shared_files, sizeof(shared_files));
2701 shared_files[0].sf_fd = uap->fd;
2702 shared_files[0].sf_mappings_count = mappings_count;
2703 shared_files[0].sf_slide = slide;
2704
2705 kr = _shared_region_map_and_slide(p,
2706 1, /* # of files to map */
2707 &shared_files[0], /* files to map */
2708 mappings_count,
2709 mappings);
2710
2711done:
2712 if (mappings != NULL) {
2713 kheap_free(KHEAP_TEMP, mappings, mappings_count * sizeof(mappings[0]));
2714 mappings = NULL;
2715 }
2716 return kr;
2717}
2718
2719/*
2720 * This interface for setting up shared region mappings is what dyld
2721 * uses for shared caches that have __AUTH sections. All other shared
2722 * caches use the non _2 version.
2723 *
2724 * The slide used for shared regions setup using this interface is done differently
2725 * from the old interface. The slide value passed in the shared_files_np represents
2726 * a max value. The kernel will choose a random value based on that, then use it
2727 * for all shared regions.
2728 */
c3c9b80d
A
2729#if defined (__x86_64__)
2730#define SLIDE_AMOUNT_MASK ~FOURK_PAGE_MASK
2731#else
2732#define SLIDE_AMOUNT_MASK ~SIXTEENK_PAGE_MASK
2733#endif
f427ee49
A
2734
2735int
2736shared_region_map_and_slide_2_np(
2737 struct proc *p,
2738 struct shared_region_map_and_slide_2_np_args *uap,
2739 __unused int *retvalp)
2740{
2741 unsigned int files_count;
2742 struct shared_file_np *shared_files = NULL;
2743 unsigned int mappings_count;
2744 struct shared_file_mapping_slide_np *mappings = NULL;
2745 kern_return_t kr = KERN_SUCCESS;
2746 boolean_t should_slide_mappings = TRUE;
2747
2748 files_count = uap->files_count;
2749 mappings_count = uap->mappings_count;
2750
2751
2752 if (files_count == 0) {
2753 SHARED_REGION_TRACE_INFO(
2754 ("shared_region: %p [%d(%s)] map(): "
2755 "no files\n",
2756 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2757 p->p_pid, p->p_comm));
2758 kr = 0; /* no files to map: we're done ! */
2759 goto done;
2760 } else if (files_count <= _SR_FILE_MAPPINGS_MAX_FILES) {
2761 shared_files = kheap_alloc(KHEAP_TEMP,
2762 files_count * sizeof(shared_files[0]), Z_WAITOK);
2763 if (shared_files == NULL) {
2764 kr = KERN_RESOURCE_SHORTAGE;
2765 goto done;
2766 }
2767 } else {
2768 SHARED_REGION_TRACE_ERROR(
2769 ("shared_region: %p [%d(%s)] map(): "
2770 "too many files (%d) max %d\n",
2771 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2772 p->p_pid, p->p_comm,
2773 files_count, _SR_FILE_MAPPINGS_MAX_FILES));
2774 kr = KERN_FAILURE;
2775 goto done;
2776 }
2777
2778 if (mappings_count == 0) {
2779 SHARED_REGION_TRACE_INFO(
2780 ("shared_region: %p [%d(%s)] map(): "
2781 "no mappings\n",
2782 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2783 p->p_pid, p->p_comm));
2784 kr = 0; /* no mappings: we're done ! */
2785 goto done;
2786 } else if (mappings_count <= SFM_MAX) {
2787 mappings = kheap_alloc(KHEAP_TEMP,
2788 mappings_count * sizeof(mappings[0]), Z_WAITOK);
2789 if (mappings == NULL) {
2790 kr = KERN_RESOURCE_SHORTAGE;
2791 goto done;
2792 }
2793 } else {
2794 SHARED_REGION_TRACE_ERROR(
2795 ("shared_region: %p [%d(%s)] map(): "
2796 "too many mappings (%d) max %d\n",
2797 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2798 p->p_pid, p->p_comm,
2799 mappings_count, SFM_MAX));
2800 kr = KERN_FAILURE;
6d2010ae
A
2801 goto done;
2802 }
2803
f427ee49
A
2804 kr = shared_region_copyin(p, uap->files, files_count, sizeof(shared_files[0]), shared_files);
2805 if (kr != KERN_SUCCESS) {
2806 goto done;
2807 }
6d2010ae 2808
f427ee49 2809 kr = shared_region_copyin(p, uap->mappings, mappings_count, sizeof(mappings[0]), mappings);
6d2010ae 2810 if (kr != KERN_SUCCESS) {
f427ee49 2811 goto done;
6d2010ae
A
2812 }
2813
f427ee49
A
2814 if (should_slide_mappings) {
2815 uint32_t max_slide = shared_files[0].sf_slide;
2816 uint32_t random_val;
2817 uint32_t slide_amount;
2818
2819 if (max_slide != 0) {
2820 read_random(&random_val, sizeof random_val);
2821 slide_amount = ((random_val % max_slide) & SLIDE_AMOUNT_MASK);
2822 } else {
2823 slide_amount = 0;
2824 }
2825
2826 /*
2827 * Fix up the mappings to reflect the desired slide.
2828 */
2829 unsigned int f;
2830 unsigned int m = 0;
2831 unsigned int i;
2832 for (f = 0; f < files_count; ++f) {
2833 shared_files[f].sf_slide = slide_amount;
2834 for (i = 0; i < shared_files[f].sf_mappings_count; ++i, ++m) {
2835 if (m >= mappings_count) {
2836 SHARED_REGION_TRACE_ERROR(
2837 ("shared_region: %p [%d(%s)] map(): "
2838 "mapping count argument was too small\n",
2839 (void *)VM_KERNEL_ADDRPERM(current_thread()),
2840 p->p_pid, p->p_comm));
2841 kr = KERN_FAILURE;
2842 goto done;
2843 }
2844 mappings[m].sms_address += slide_amount;
2845 if (mappings[m].sms_slide_size != 0) {
c3c9b80d 2846 mappings[m].sms_slide_start += slide_amount;
f427ee49
A
2847 }
2848 }
2849 }
2850 }
2851 kr = _shared_region_map_and_slide(p, files_count, shared_files, mappings_count, mappings);
6d2010ae 2852done:
f427ee49
A
2853 if (shared_files != NULL) {
2854 kheap_free(KHEAP_TEMP, shared_files, files_count * sizeof(shared_files[0]));
2855 shared_files = NULL;
2856 }
2857 if (mappings != NULL) {
2858 kheap_free(KHEAP_TEMP, mappings, mappings_count * sizeof(mappings[0]));
2859 mappings = NULL;
2860 }
6d2010ae
A
2861 return kr;
2862}
9bccf70c 2863
2d21ac55 2864/* sysctl overflow room */
9bccf70c 2865
0a7de745
A
2866SYSCTL_INT(_vm, OID_AUTO, pagesize, CTLFLAG_RD | CTLFLAG_LOCKED,
2867 (int *) &page_size, 0, "vm page size");
fe8ab488 2868
2d21ac55 2869/* vm_page_free_target is provided as a makeshift solution for applications that want to
0a7de745
A
2870 * allocate buffer space, possibly purgeable memory, but not cause inactive pages to be
2871 * reclaimed. It allows the app to calculate how much memory is free outside the free target. */
2872extern unsigned int vm_page_free_target;
2873SYSCTL_INT(_vm, OID_AUTO, vm_page_free_target, CTLFLAG_RD | CTLFLAG_LOCKED,
2874 &vm_page_free_target, 0, "Pageout daemon free target");
9bccf70c 2875
6d2010ae 2876SYSCTL_INT(_vm, OID_AUTO, memory_pressure, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2877 &vm_pageout_state.vm_memory_pressure, 0, "Memory pressure indicator");
b0d623f7
A
2878
2879static int
2880vm_ctl_page_free_wanted SYSCTL_HANDLER_ARGS
2881{
2882#pragma unused(oidp, arg1, arg2)
2883 unsigned int page_free_wanted;
2884
2885 page_free_wanted = mach_vm_ctl_page_free_wanted();
0a7de745 2886 return SYSCTL_OUT(req, &page_free_wanted, sizeof(page_free_wanted));
b0d623f7
A
2887}
2888SYSCTL_PROC(_vm, OID_AUTO, page_free_wanted,
0a7de745
A
2889 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
2890 0, 0, vm_ctl_page_free_wanted, "I", "");
b0d623f7 2891
0a7de745 2892extern unsigned int vm_page_purgeable_count;
6d2010ae 2893SYSCTL_INT(_vm, OID_AUTO, page_purgeable_count, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2894 &vm_page_purgeable_count, 0, "Purgeable page count");
b0d623f7 2895
0a7de745 2896extern unsigned int vm_page_purgeable_wired_count;
6d2010ae 2897SYSCTL_INT(_vm, OID_AUTO, page_purgeable_wired_count, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2898 &vm_page_purgeable_wired_count, 0, "Wired purgeable page count");
b0d623f7 2899
cb323159
A
2900extern unsigned int vm_page_kern_lpage_count;
2901SYSCTL_INT(_vm, OID_AUTO, kern_lpage_count, CTLFLAG_RD | CTLFLAG_LOCKED,
2902 &vm_page_kern_lpage_count, 0, "kernel used large pages");
2903
d9a64523 2904#if DEVELOPMENT || DEBUG
f427ee49
A
2905#if __ARM_MIXED_PAGE_SIZE__
2906static int vm_mixed_pagesize_supported = 1;
2907#else
2908static int vm_mixed_pagesize_supported = 0;
2909#endif /*__ARM_MIXED_PAGE_SIZE__ */
2910SYSCTL_INT(_debug, OID_AUTO, vm_mixed_pagesize_supported, CTLFLAG_ANYBODY | CTLFLAG_RD | CTLFLAG_LOCKED,
2911 &vm_mixed_pagesize_supported, 0, "kernel support for mixed pagesize");
2912
c3c9b80d
A
2913SCALABLE_COUNTER_DECLARE(vm_page_grab_count);
2914SYSCTL_SCALABLE_COUNTER(_vm, pages_grabbed, vm_page_grab_count, "Total pages grabbed");
d9a64523 2915SYSCTL_ULONG(_vm, OID_AUTO, pages_freed, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2916 &vm_pageout_vminfo.vm_page_pages_freed, "Total pages freed");
d9a64523 2917
3e170ce0 2918SYSCTL_INT(_vm, OID_AUTO, pageout_purged_objects, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2919 &vm_pageout_debug.vm_pageout_purged_objects, 0, "System purged object count");
d9a64523 2920SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_busy, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2921 &vm_pageout_debug.vm_pageout_cleaned_busy, 0, "Cleaned pages busy (deactivated)");
d9a64523 2922SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_nolock, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2923 &vm_pageout_debug.vm_pageout_cleaned_nolock, 0, "Cleaned pages no-lock (deactivated)");
d9a64523
A
2924
2925SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_volatile_reactivated, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2926 &vm_pageout_debug.vm_pageout_cleaned_volatile_reactivated, 0, "Cleaned pages volatile reactivated");
d9a64523 2927SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_fault_reactivated, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2928 &vm_pageout_debug.vm_pageout_cleaned_fault_reactivated, 0, "Cleaned pages fault reactivated");
d9a64523 2929SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_reactivated, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2930 &vm_pageout_debug.vm_pageout_cleaned_reactivated, 0, "Cleaned pages reactivated"); /* sum of all reactivated AND busy and nolock (even though those actually get reDEactivated */
d9a64523 2931SYSCTL_ULONG(_vm, OID_AUTO, pageout_cleaned, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2932 &vm_pageout_vminfo.vm_pageout_freed_cleaned, "Cleaned pages freed");
d9a64523 2933SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_reference_reactivated, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2934 &vm_pageout_debug.vm_pageout_cleaned_reference_reactivated, 0, "Cleaned pages reference reactivated");
d9a64523 2935SYSCTL_UINT(_vm, OID_AUTO, pageout_enqueued_cleaned, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2936 &vm_pageout_debug.vm_pageout_enqueued_cleaned, 0, ""); /* sum of next two */
f427ee49 2937#endif /* DEVELOPMENT || DEBUG */
3e170ce0 2938
39236c6e
A
2939extern int madvise_free_debug;
2940SYSCTL_INT(_vm, OID_AUTO, madvise_free_debug, CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 2941 &madvise_free_debug, 0, "zero-fill on madvise(MADV_FREE*)");
39236c6e 2942
6d2010ae 2943SYSCTL_INT(_vm, OID_AUTO, page_reusable_count, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2944 &vm_page_stats_reusable.reusable_count, 0, "Reusable page count");
6d2010ae 2945SYSCTL_QUAD(_vm, OID_AUTO, reusable_success, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2946 &vm_page_stats_reusable.reusable_pages_success, "");
6d2010ae 2947SYSCTL_QUAD(_vm, OID_AUTO, reusable_failure, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2948 &vm_page_stats_reusable.reusable_pages_failure, "");
39037602 2949SYSCTL_QUAD(_vm, OID_AUTO, reusable_pages_shared, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2950 &vm_page_stats_reusable.reusable_pages_shared, "");
6d2010ae 2951SYSCTL_QUAD(_vm, OID_AUTO, all_reusable_calls, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2952 &vm_page_stats_reusable.all_reusable_calls, "");
6d2010ae 2953SYSCTL_QUAD(_vm, OID_AUTO, partial_reusable_calls, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2954 &vm_page_stats_reusable.partial_reusable_calls, "");
6d2010ae 2955SYSCTL_QUAD(_vm, OID_AUTO, reuse_success, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2956 &vm_page_stats_reusable.reuse_pages_success, "");
6d2010ae 2957SYSCTL_QUAD(_vm, OID_AUTO, reuse_failure, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2958 &vm_page_stats_reusable.reuse_pages_failure, "");
6d2010ae 2959SYSCTL_QUAD(_vm, OID_AUTO, all_reuse_calls, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2960 &vm_page_stats_reusable.all_reuse_calls, "");
6d2010ae 2961SYSCTL_QUAD(_vm, OID_AUTO, partial_reuse_calls, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2962 &vm_page_stats_reusable.partial_reuse_calls, "");
6d2010ae 2963SYSCTL_QUAD(_vm, OID_AUTO, can_reuse_success, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2964 &vm_page_stats_reusable.can_reuse_success, "");
6d2010ae 2965SYSCTL_QUAD(_vm, OID_AUTO, can_reuse_failure, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2966 &vm_page_stats_reusable.can_reuse_failure, "");
39236c6e 2967SYSCTL_QUAD(_vm, OID_AUTO, reusable_reclaimed, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2968 &vm_page_stats_reusable.reusable_reclaimed, "");
39037602 2969SYSCTL_QUAD(_vm, OID_AUTO, reusable_nonwritable, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2970 &vm_page_stats_reusable.reusable_nonwritable, "");
39037602 2971SYSCTL_QUAD(_vm, OID_AUTO, reusable_shared, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2972 &vm_page_stats_reusable.reusable_shared, "");
39037602 2973SYSCTL_QUAD(_vm, OID_AUTO, free_shared, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 2974 &vm_page_stats_reusable.free_shared, "");
b0d623f7
A
2975
2976
316670eb
A
2977extern unsigned int vm_page_free_count, vm_page_speculative_count;
2978SYSCTL_UINT(_vm, OID_AUTO, page_free_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_free_count, 0, "");
2979SYSCTL_UINT(_vm, OID_AUTO, page_speculative_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_speculative_count, 0, "");
2980
2981extern unsigned int vm_page_cleaned_count;
2982SYSCTL_UINT(_vm, OID_AUTO, page_cleaned_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_cleaned_count, 0, "Cleaned queue size");
2983
39037602
A
2984extern unsigned int vm_page_pageable_internal_count, vm_page_pageable_external_count;
2985SYSCTL_UINT(_vm, OID_AUTO, page_pageable_internal_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_pageable_internal_count, 0, "");
2986SYSCTL_UINT(_vm, OID_AUTO, page_pageable_external_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_pageable_external_count, 0, "");
2987
316670eb 2988/* pageout counts */
d9a64523
A
2989SYSCTL_UINT(_vm, OID_AUTO, pageout_inactive_clean, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_state.vm_pageout_inactive_clean, 0, "");
2990SYSCTL_UINT(_vm, OID_AUTO, pageout_inactive_used, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_state.vm_pageout_inactive_used, 0, "");
2991
2992SYSCTL_ULONG(_vm, OID_AUTO, pageout_inactive_dirty_internal, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_inactive_dirty_internal, "");
2993SYSCTL_ULONG(_vm, OID_AUTO, pageout_inactive_dirty_external, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_inactive_dirty_external, "");
2994SYSCTL_ULONG(_vm, OID_AUTO, pageout_speculative_clean, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_freed_speculative, "");
2995SYSCTL_ULONG(_vm, OID_AUTO, pageout_freed_external, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_freed_external, "");
2996SYSCTL_ULONG(_vm, OID_AUTO, pageout_freed_speculative, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_freed_speculative, "");
2997SYSCTL_ULONG(_vm, OID_AUTO, pageout_freed_cleaned, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_freed_cleaned, "");
2998
316670eb 2999
fe8ab488
A
3000/* counts of pages prefaulted when entering a memory object */
3001extern int64_t vm_prefault_nb_pages, vm_prefault_nb_bailout;
3002SYSCTL_QUAD(_vm, OID_AUTO, prefault_nb_pages, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_prefault_nb_pages, "");
3003SYSCTL_QUAD(_vm, OID_AUTO, prefault_nb_bailout, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_prefault_nb_bailout, "");
3004
5ba3f43e
A
3005#if defined (__x86_64__)
3006extern unsigned int vm_clump_promote_threshold;
3007SYSCTL_UINT(_vm, OID_AUTO, vm_clump_promote_threshold, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_clump_promote_threshold, 0, "clump size threshold for promotes");
3008#if DEVELOPMENT || DEBUG
3009extern unsigned long vm_clump_stats[];
3010SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats1, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[1], "free page allocations from clump of 1 page");
3011SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats2, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[2], "free page allocations from clump of 2 pages");
3012SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats3, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[3], "free page allocations from clump of 3 pages");
3013SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats4, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[4], "free page allocations from clump of 4 pages");
3014SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats5, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[5], "free page allocations from clump of 5 pages");
3015SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats6, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[6], "free page allocations from clump of 6 pages");
3016SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats7, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[7], "free page allocations from clump of 7 pages");
3017SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats8, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[8], "free page allocations from clump of 8 pages");
3018SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats9, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[9], "free page allocations from clump of 9 pages");
3019SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats10, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[10], "free page allocations from clump of 10 pages");
3020SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats11, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[11], "free page allocations from clump of 11 pages");
3021SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats12, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[12], "free page allocations from clump of 12 pages");
3022SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats13, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[13], "free page allocations from clump of 13 pages");
3023SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats14, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[14], "free page allocations from clump of 14 pages");
3024SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats15, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[15], "free page allocations from clump of 15 pages");
3025SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats16, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[16], "free page allocations from clump of 16 pages");
3026extern unsigned long vm_clump_allocs, vm_clump_inserts, vm_clump_inrange, vm_clump_promotes;
3027SYSCTL_LONG(_vm, OID_AUTO, vm_clump_alloc, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_allocs, "free page allocations");
3028SYSCTL_LONG(_vm, OID_AUTO, vm_clump_inserts, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_inserts, "free page insertions");
3029SYSCTL_LONG(_vm, OID_AUTO, vm_clump_inrange, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_inrange, "free page insertions that are part of vm_pages");
3030SYSCTL_LONG(_vm, OID_AUTO, vm_clump_promotes, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_promotes, "pages promoted to head");
3031#endif /* if DEVELOPMENT || DEBUG */
3032#endif /* #if defined (__x86_64__) */
3033
39037602
A
3034#if CONFIG_SECLUDED_MEMORY
3035
3036SYSCTL_UINT(_vm, OID_AUTO, num_tasks_can_use_secluded_mem, CTLFLAG_RD | CTLFLAG_LOCKED, &num_tasks_can_use_secluded_mem, 0, "");
3037extern unsigned int vm_page_secluded_target;
3038extern unsigned int vm_page_secluded_count;
3039extern unsigned int vm_page_secluded_count_free;
3040extern unsigned int vm_page_secluded_count_inuse;
cb323159 3041extern unsigned int vm_page_secluded_count_over_target;
39037602
A
3042SYSCTL_UINT(_vm, OID_AUTO, page_secluded_target, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded_target, 0, "");
3043SYSCTL_UINT(_vm, OID_AUTO, page_secluded_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded_count, 0, "");
3044SYSCTL_UINT(_vm, OID_AUTO, page_secluded_count_free, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded_count_free, 0, "");
3045SYSCTL_UINT(_vm, OID_AUTO, page_secluded_count_inuse, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded_count_inuse, 0, "");
cb323159 3046SYSCTL_UINT(_vm, OID_AUTO, page_secluded_count_over_target, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded_count_over_target, 0, "");
39037602
A
3047
3048extern struct vm_page_secluded_data vm_page_secluded;
3049SYSCTL_UINT(_vm, OID_AUTO, page_secluded_eligible, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.eligible_for_secluded, 0, "");
3050SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_success_free, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_success_free, 0, "");
3051SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_success_other, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_success_other, 0, "");
3052SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_failure_locked, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_failure_locked, 0, "");
3053SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_failure_state, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_failure_state, 0, "");
3054SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_failure_dirty, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_failure_dirty, 0, "");
3055SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_for_iokit, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_for_iokit, 0, "");
3056SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_for_iokit_success, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_for_iokit_success, 0, "");
3057
39037602
A
3058#endif /* CONFIG_SECLUDED_MEMORY */
3059
316670eb
A
3060#include <kern/thread.h>
3061#include <sys/user.h>
3062
3063void vm_pageout_io_throttle(void);
3064
0a7de745
A
3065void
3066vm_pageout_io_throttle(void)
3067{
316670eb 3068 struct uthread *uthread = get_bsdthread_info(current_thread());
0a7de745
A
3069
3070 /*
3071 * thread is marked as a low priority I/O type
3072 * and the I/O we issued while in this cleaning operation
3073 * collided with normal I/O operations... we'll
3074 * delay in order to mitigate the impact of this
3075 * task on the normal operation of the system
3076 */
316670eb
A
3077
3078 if (uthread->uu_lowpri_window) {
39236c6e 3079 throttle_lowpri_io(1);
316670eb 3080 }
316670eb
A
3081}
3082
b0d623f7
A
3083int
3084vm_pressure_monitor(
3085 __unused struct proc *p,
3086 struct vm_pressure_monitor_args *uap,
3087 int *retval)
3088{
0a7de745
A
3089 kern_return_t kr;
3090 uint32_t pages_reclaimed;
3091 uint32_t pages_wanted;
b0d623f7
A
3092
3093 kr = mach_vm_pressure_monitor(
3094 (boolean_t) uap->wait_for_pressure,
3095 uap->nsecs_monitored,
3096 (uap->pages_reclaimed) ? &pages_reclaimed : NULL,
3097 &pages_wanted);
3098
3099 switch (kr) {
3100 case KERN_SUCCESS:
3101 break;
3102 case KERN_ABORTED:
3103 return EINTR;
3104 default:
3105 return EINVAL;
3106 }
3107
3108 if (uap->pages_reclaimed) {
3109 if (copyout((void *)&pages_reclaimed,
0a7de745
A
3110 uap->pages_reclaimed,
3111 sizeof(pages_reclaimed)) != 0) {
b0d623f7
A
3112 return EFAULT;
3113 }
3114 }
3115
3116 *retval = (int) pages_wanted;
3117 return 0;
3118}
316670eb
A
3119
3120int
3121kas_info(struct proc *p,
0a7de745
A
3122 struct kas_info_args *uap,
3123 int *retval __unused)
316670eb 3124{
f427ee49 3125#ifndef CONFIG_KAS_INFO
316670eb
A
3126 (void)p;
3127 (void)uap;
3128 return ENOTSUP;
f427ee49 3129#else /* CONFIG_KAS_INFO */
0a7de745
A
3130 int selector = uap->selector;
3131 user_addr_t valuep = uap->value;
3132 user_addr_t sizep = uap->size;
f427ee49 3133 user_size_t size, rsize;
0a7de745 3134 int error;
316670eb
A
3135
3136 if (!kauth_cred_issuser(kauth_cred_get())) {
3137 return EPERM;
3138 }
3139
3140#if CONFIG_MACF
3141 error = mac_system_check_kas_info(kauth_cred_get(), selector);
3142 if (error) {
3143 return error;
3144 }
3145#endif
3146
3147 if (IS_64BIT_PROCESS(p)) {
3148 user64_size_t size64;
3149 error = copyin(sizep, &size64, sizeof(size64));
3150 size = (user_size_t)size64;
3151 } else {
3152 user32_size_t size32;
3153 error = copyin(sizep, &size32, sizeof(size32));
3154 size = (user_size_t)size32;
3155 }
3156 if (error) {
3157 return error;
3158 }
3159
3160 switch (selector) {
0a7de745
A
3161 case KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR:
3162 {
3163 uint64_t slide = vm_kernel_slide;
316670eb 3164
0a7de745 3165 if (sizeof(slide) != size) {
316670eb 3166 return EINVAL;
0a7de745
A
3167 }
3168
f427ee49 3169 error = copyout(&slide, valuep, sizeof(slide));
0a7de745
A
3170 if (error) {
3171 return error;
3172 }
f427ee49
A
3173 rsize = size;
3174 }
3175 break;
3176 case KAS_INFO_KERNEL_SEGMENT_VMADDR_SELECTOR:
3177 {
3178 uint32_t i;
3179 kernel_mach_header_t *mh = &_mh_execute_header;
3180 struct load_command *cmd;
3181 cmd = (struct load_command*) &mh[1];
3182 uint64_t *bases;
3183 rsize = mh->ncmds * sizeof(uint64_t);
3184
3185 /*
3186 * Return the size if no data was passed
3187 */
3188 if (valuep == 0) {
3189 break;
3190 }
3191
3192 if (rsize > size) {
3193 return EINVAL;
3194 }
3195
3196 bases = kheap_alloc(KHEAP_TEMP, rsize, Z_WAITOK | Z_ZERO);
3197
3198 for (i = 0; i < mh->ncmds; i++) {
3199 if (cmd->cmd == LC_SEGMENT_KERNEL) {
3200 __IGNORE_WCASTALIGN(kernel_segment_command_t * sg = (kernel_segment_command_t *) cmd);
3201 bases[i] = (uint64_t)sg->vmaddr;
3202 }
3203 cmd = (struct load_command *) ((uintptr_t) cmd + cmd->cmdsize);
3204 }
3205
3206 error = copyout(bases, valuep, rsize);
3207
3208 kheap_free(KHEAP_TEMP, bases, rsize);
0a7de745 3209
0a7de745
A
3210 if (error) {
3211 return error;
3212 }
3213 }
3214 break;
3215 default:
3216 return EINVAL;
316670eb
A
3217 }
3218
f427ee49
A
3219 if (IS_64BIT_PROCESS(p)) {
3220 user64_size_t size64 = (user64_size_t)rsize;
3221 error = copyout(&size64, sizep, sizeof(size64));
3222 } else {
3223 user32_size_t size32 = (user32_size_t)rsize;
3224 error = copyout(&size32, sizep, sizeof(size32));
3225 }
3226
3227 return error;
3228#endif /* CONFIG_KAS_INFO */
3229}
3230
3231#if __has_feature(ptrauth_calls)
3232/*
3233 * Generate a random pointer signing key that isn't 0.
3234 */
3235uint64_t
3236generate_jop_key(void)
3237{
3238 uint64_t key;
3239
3240 do {
3241 read_random(&key, sizeof key);
3242 } while (key == 0);
3243 return key;
316670eb 3244}
f427ee49 3245#endif /* __has_feature(ptrauth_calls) */
5ba3f43e
A
3246
3247
3248#pragma clang diagnostic push
3249#pragma clang diagnostic ignored "-Wcast-qual"
3250#pragma clang diagnostic ignored "-Wunused-function"
3251
0a7de745
A
3252static void
3253asserts()
3254{
5ba3f43e
A
3255 static_assert(sizeof(vm_min_kernel_address) == sizeof(unsigned long));
3256 static_assert(sizeof(vm_max_kernel_address) == sizeof(unsigned long));
3257}
3258
3259SYSCTL_ULONG(_vm, OID_AUTO, vm_min_kernel_address, CTLFLAG_RD, (unsigned long *) &vm_min_kernel_address, "");
3260SYSCTL_ULONG(_vm, OID_AUTO, vm_max_kernel_address, CTLFLAG_RD, (unsigned long *) &vm_max_kernel_address, "");
3261#pragma clang diagnostic pop
3262
3263extern uint32_t vm_page_pages;
3264SYSCTL_UINT(_vm, OID_AUTO, pages, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_pages, 0, "");
3265
d9a64523
A
3266extern uint32_t vm_page_busy_absent_skipped;
3267SYSCTL_UINT(_vm, OID_AUTO, page_busy_absent_skipped, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_busy_absent_skipped, 0, "");
3268
cb323159
A
3269extern uint32_t vm_page_upl_tainted;
3270SYSCTL_UINT(_vm, OID_AUTO, upl_pages_tainted, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_upl_tainted, 0, "");
3271
3272extern uint32_t vm_page_iopl_tainted;
3273SYSCTL_UINT(_vm, OID_AUTO, iopl_pages_tainted, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_iopl_tainted, 0, "");
3274
5ba3f43e 3275#if (__arm__ || __arm64__) && (DEVELOPMENT || DEBUG)
d9a64523
A
3276extern int vm_footprint_suspend_allowed;
3277SYSCTL_INT(_vm, OID_AUTO, footprint_suspend_allowed, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_footprint_suspend_allowed, 0, "");
9d749ea3 3278
5ba3f43e
A
3279extern void pmap_footprint_suspend(vm_map_t map, boolean_t suspend);
3280static int
3281sysctl_vm_footprint_suspend SYSCTL_HANDLER_ARGS
3282{
3283#pragma unused(oidp, arg1, arg2)
3284 int error = 0;
3285 int new_value;
3286
3287 if (req->newptr == USER_ADDR_NULL) {
3288 return 0;
3289 }
3290 error = SYSCTL_IN(req, &new_value, sizeof(int));
3291 if (error) {
3292 return error;
3293 }
d9a64523 3294 if (!vm_footprint_suspend_allowed) {
9d749ea3
A
3295 if (new_value != 0) {
3296 /* suspends are not allowed... */
3297 return 0;
3298 }
3299 /* ... but let resumes proceed */
3300 }
3301 DTRACE_VM2(footprint_suspend,
0a7de745
A
3302 vm_map_t, current_map(),
3303 int, new_value);
9d749ea3 3304
5ba3f43e 3305 pmap_footprint_suspend(current_map(), new_value);
9d749ea3 3306
5ba3f43e
A
3307 return 0;
3308}
3309SYSCTL_PROC(_vm, OID_AUTO, footprint_suspend,
0a7de745
A
3310 CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_ANYBODY | CTLFLAG_LOCKED | CTLFLAG_MASKED,
3311 0, 0, &sysctl_vm_footprint_suspend, "I", "");
5ba3f43e 3312#endif /* (__arm__ || __arm64__) && (DEVELOPMENT || DEBUG) */
d9a64523
A
3313
3314extern uint64_t vm_map_corpse_footprint_count;
3315extern uint64_t vm_map_corpse_footprint_size_avg;
3316extern uint64_t vm_map_corpse_footprint_size_max;
3317extern uint64_t vm_map_corpse_footprint_full;
3318extern uint64_t vm_map_corpse_footprint_no_buf;
3319SYSCTL_QUAD(_vm, OID_AUTO, corpse_footprint_count,
0a7de745 3320 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_corpse_footprint_count, "");
d9a64523 3321SYSCTL_QUAD(_vm, OID_AUTO, corpse_footprint_size_avg,
0a7de745 3322 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_corpse_footprint_size_avg, "");
d9a64523 3323SYSCTL_QUAD(_vm, OID_AUTO, corpse_footprint_size_max,
0a7de745 3324 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_corpse_footprint_size_max, "");
d9a64523 3325SYSCTL_QUAD(_vm, OID_AUTO, corpse_footprint_full,
0a7de745 3326 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_corpse_footprint_full, "");
d9a64523 3327SYSCTL_QUAD(_vm, OID_AUTO, corpse_footprint_no_buf,
0a7de745 3328 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_corpse_footprint_no_buf, "");
d9a64523 3329
d9a64523
A
3330
3331extern uint64_t shared_region_pager_copied;
3332extern uint64_t shared_region_pager_slid;
3333extern uint64_t shared_region_pager_slid_error;
3334extern uint64_t shared_region_pager_reclaimed;
3335SYSCTL_QUAD(_vm, OID_AUTO, shared_region_pager_copied,
0a7de745 3336 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pager_copied, "");
d9a64523 3337SYSCTL_QUAD(_vm, OID_AUTO, shared_region_pager_slid,
0a7de745 3338 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pager_slid, "");
d9a64523 3339SYSCTL_QUAD(_vm, OID_AUTO, shared_region_pager_slid_error,
0a7de745 3340 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pager_slid_error, "");
d9a64523 3341SYSCTL_QUAD(_vm, OID_AUTO, shared_region_pager_reclaimed,
0a7de745 3342 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pager_reclaimed, "");
f427ee49
A
3343extern int shared_region_destroy_delay;
3344SYSCTL_INT(_vm, OID_AUTO, shared_region_destroy_delay,
3345 CTLFLAG_RW | CTLFLAG_LOCKED, &shared_region_destroy_delay, 0, "");
d9a64523
A
3346
3347#if MACH_ASSERT
3348extern int pmap_ledgers_panic_leeway;
3349SYSCTL_INT(_vm, OID_AUTO, pmap_ledgers_panic_leeway, CTLFLAG_RW | CTLFLAG_LOCKED, &pmap_ledgers_panic_leeway, 0, "");
3350#endif /* MACH_ASSERT */
cb323159 3351
c3c9b80d
A
3352
3353extern uint64_t vm_map_lookup_locked_copy_slowly_count;
3354extern uint64_t vm_map_lookup_locked_copy_slowly_size;
3355extern uint64_t vm_map_lookup_locked_copy_slowly_max;
3356extern uint64_t vm_map_lookup_locked_copy_slowly_restart;
3357extern uint64_t vm_map_lookup_locked_copy_slowly_error;
3358extern uint64_t vm_map_lookup_locked_copy_strategically_count;
3359extern uint64_t vm_map_lookup_locked_copy_strategically_size;
3360extern uint64_t vm_map_lookup_locked_copy_strategically_max;
3361extern uint64_t vm_map_lookup_locked_copy_strategically_restart;
3362extern uint64_t vm_map_lookup_locked_copy_strategically_error;
3363extern uint64_t vm_map_lookup_locked_copy_shadow_count;
3364extern uint64_t vm_map_lookup_locked_copy_shadow_size;
3365extern uint64_t vm_map_lookup_locked_copy_shadow_max;
3366SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_slowly_count,
3367 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_slowly_count, "");
3368SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_slowly_size,
3369 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_slowly_size, "");
3370SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_slowly_max,
3371 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_slowly_max, "");
3372SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_slowly_restart,
3373 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_slowly_restart, "");
3374SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_slowly_error,
3375 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_slowly_error, "");
3376SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_strategically_count,
3377 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_strategically_count, "");
3378SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_strategically_size,
3379 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_strategically_size, "");
3380SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_strategically_max,
3381 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_strategically_max, "");
3382SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_strategically_restart,
3383 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_strategically_restart, "");
3384SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_strategically_error,
3385 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_strategically_error, "");
3386SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_shadow_count,
3387 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_shadow_count, "");
3388SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_shadow_size,
3389 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_shadow_size, "");
3390SYSCTL_QUAD(_vm, OID_AUTO, map_lookup_locked_copy_shadow_max,
3391 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_lookup_locked_copy_shadow_max, "");
3392
cb323159
A
3393extern int vm_protect_privileged_from_untrusted;
3394SYSCTL_INT(_vm, OID_AUTO, protect_privileged_from_untrusted,
3395 CTLFLAG_RW | CTLFLAG_LOCKED, &vm_protect_privileged_from_untrusted, 0, "");
3396extern uint64_t vm_copied_on_read;
3397SYSCTL_QUAD(_vm, OID_AUTO, copied_on_read,
3398 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_copied_on_read, "");
f427ee49
A
3399
3400extern int vm_shared_region_count;
3401extern int vm_shared_region_peak;
3402SYSCTL_INT(_vm, OID_AUTO, shared_region_count,
3403 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_shared_region_count, 0, "");
3404SYSCTL_INT(_vm, OID_AUTO, shared_region_peak,
3405 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_shared_region_peak, 0, "");
3406#if DEVELOPMENT || DEBUG
3407extern unsigned int shared_region_pagers_resident_count;
3408SYSCTL_INT(_vm, OID_AUTO, shared_region_pagers_resident_count,
3409 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pagers_resident_count, 0, "");
3410extern unsigned int shared_region_pagers_resident_peak;
3411SYSCTL_INT(_vm, OID_AUTO, shared_region_pagers_resident_peak,
3412 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pagers_resident_peak, 0, "");
3413extern int shared_region_pager_count;
3414SYSCTL_INT(_vm, OID_AUTO, shared_region_pager_count,
3415 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pager_count, 0, "");
3416#if __has_feature(ptrauth_calls)
3417extern int shared_region_key_count;
3418SYSCTL_INT(_vm, OID_AUTO, shared_region_key_count,
3419 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_key_count, 0, "");
3420extern int vm_shared_region_reslide_count;
3421SYSCTL_INT(_vm, OID_AUTO, shared_region_reslide_count,
3422 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_shared_region_reslide_count, 0, "");
3423#endif /* __has_feature(ptrauth_calls) */
3424#endif /* DEVELOPMENT || DEBUG */
3425
3426#if MACH_ASSERT
3427extern int debug4k_filter;
3428SYSCTL_INT(_vm, OID_AUTO, debug4k_filter, CTLFLAG_RW | CTLFLAG_LOCKED, &debug4k_filter, 0, "");
3429extern int debug4k_panic_on_terminate;
3430SYSCTL_INT(_vm, OID_AUTO, debug4k_panic_on_terminate, CTLFLAG_RW | CTLFLAG_LOCKED, &debug4k_panic_on_terminate, 0, "");
3431extern int debug4k_panic_on_exception;
3432SYSCTL_INT(_vm, OID_AUTO, debug4k_panic_on_exception, CTLFLAG_RW | CTLFLAG_LOCKED, &debug4k_panic_on_exception, 0, "");
3433extern int debug4k_panic_on_misaligned_sharing;
3434SYSCTL_INT(_vm, OID_AUTO, debug4k_panic_on_misaligned_sharing, CTLFLAG_RW | CTLFLAG_LOCKED, &debug4k_panic_on_misaligned_sharing, 0, "");
3435#endif /* MACH_ASSERT */
3436
3437/*
3438 * A sysctl which causes all existing shared regions to become stale. They
3439 * will no longer be used by anything new and will be torn down as soon as
3440 * the last existing user exits. A write of non-zero value causes that to happen.
3441 * This should only be used by launchd, so we check that this is initproc.
3442 */
3443static int
3444shared_region_pivot(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3445{
3446 unsigned int value = 0;
3447 int changed = 0;
3448 int error = sysctl_io_number(req, 0, sizeof(value), &value, &changed);
3449 if (error || !changed) {
3450 return error;
3451 }
3452 if (current_proc() != initproc) {
3453 return EPERM;
3454 }
3455
3456 vm_shared_region_pivot();
3457
3458 return 0;
3459}
3460
3461SYSCTL_PROC(_vm, OID_AUTO, shared_region_pivot,
3462 CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_LOCKED,
3463 0, 0, shared_region_pivot, "I", "");
3464
c3c9b80d
A
3465/*
3466 * sysctl to return the number of pages on retired_pages_object
3467 */
3468static int
3469retired_pages_count SYSCTL_HANDLER_ARGS
3470{
3471#pragma unused(arg1, arg2, oidp)
3472 extern uint32_t vm_retired_pages_count(void);
3473 uint32_t value = vm_retired_pages_count();
3474
3475 return SYSCTL_OUT(req, &value, sizeof(value));
3476}
3477SYSCTL_PROC(_vm, OID_AUTO, retired_pages_count, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
3478 0, 0, &retired_pages_count, "I", "");
3479
3480SYSCTL_INT(_vm, OID_AUTO, vmtc_total, CTLFLAG_RD | CTLFLAG_LOCKED,
3481 &vmtc_total, 0, "total text page corruptions detected");
3482SYSCTL_INT(_vm, OID_AUTO, vmtc_undiagnosed, CTLFLAG_RD | CTLFLAG_LOCKED,
3483 &vmtc_undiagnosed, 0, "undiagnosed text page corruptions");
3484SYSCTL_INT(_vm, OID_AUTO, vmtc_not_eligible, CTLFLAG_RD | CTLFLAG_LOCKED,
3485 &vmtc_not_eligible, 0, "text page corruptions not eligible for correction");
3486SYSCTL_INT(_vm, OID_AUTO, vmtc_copyin_fail, CTLFLAG_RD | CTLFLAG_LOCKED,
3487 &vmtc_copyin_fail, 0, "undiagnosed text page corruptions due to copyin failure");
3488SYSCTL_INT(_vm, OID_AUTO, vmtc_not_found, CTLFLAG_RD | CTLFLAG_LOCKED,
3489 &vmtc_not_found, 0, "text page corruptions but no diff found");
3490SYSCTL_INT(_vm, OID_AUTO, vmtc_one_bit_flip, CTLFLAG_RD | CTLFLAG_LOCKED,
3491 &vmtc_one_bit_flip, 0, "text page corruptions that had a single bit flip");
3492
3493SYSCTL_INT(_vm, OID_AUTO, vmtc_1_byte, CTLFLAG_RD | CTLFLAG_LOCKED,
3494 &vmtc_byte_counts[0], 0, "text page corruptions with 1 changed byte");
3495
3496SYSCTL_INT(_vm, OID_AUTO, vmtc_2_byte, CTLFLAG_RD | CTLFLAG_LOCKED,
3497 &vmtc_byte_counts[1], 0, "text page corruptions with 2 changed bytes");
3498
3499SYSCTL_INT(_vm, OID_AUTO, vmtc_4_byte, CTLFLAG_RD | CTLFLAG_LOCKED,
3500 &vmtc_byte_counts[2], 0, "text page corruptions with 3 to 4 changed bytes");
3501
3502SYSCTL_INT(_vm, OID_AUTO, vmtc_8_byte, CTLFLAG_RD | CTLFLAG_LOCKED,
3503 &vmtc_byte_counts[3], 0, "text page corruptions with 5 to 8 changed bytes");
3504
3505SYSCTL_INT(_vm, OID_AUTO, vmtc_16_byte, CTLFLAG_RD | CTLFLAG_LOCKED,
3506 &vmtc_byte_counts[4], 0, "text page corruptions with 9 to 16 changed bytes");
3507
3508SYSCTL_INT(_vm, OID_AUTO, vmtc_32_byte, CTLFLAG_RD | CTLFLAG_LOCKED,
3509 &vmtc_byte_counts[5], 0, "text page corruptions with 17 to 32 changed bytes");
3510
3511SYSCTL_INT(_vm, OID_AUTO, vmtc_64_byte, CTLFLAG_RD | CTLFLAG_LOCKED,
3512 &vmtc_byte_counts[6], 0, "text page corruptions with 33 to 64 changed bytes");
3513
3514SYSCTL_INT(_vm, OID_AUTO, vmtc_128byte, CTLFLAG_RD | CTLFLAG_LOCKED,
3515 &vmtc_byte_counts[7], 0, "text page corruptions with 65 to 128 changed bytes");
3516
3517SYSCTL_INT(_vm, OID_AUTO, vmtc_256_byte, CTLFLAG_RD | CTLFLAG_LOCKED,
3518 &vmtc_byte_counts[8], 0, "text page corruptions with >128 changed bytes");
3519
3520#if DEBUG || DEVELOPMENT
3521/*
3522 * A sysctl that can be used to corrupt a text page with an illegal instruction.
3523 * Used for testing text page self healing.
3524 */
3525extern kern_return_t vm_corrupt_text_addr(uintptr_t);
3526static int
3527corrupt_text_addr(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3528{
3529 uint64_t value = 0;
3530 int error = sysctl_handle_quad(oidp, &value, 0, req);
3531 if (error || !req->newptr) {
3532 return error;
3533 }
3534
3535 if (vm_corrupt_text_addr((uintptr_t)value) == KERN_SUCCESS) {
3536 return 0;
3537 } else {
3538 return EINVAL;
3539 }
3540}
3541
3542SYSCTL_PROC(_vm, OID_AUTO, corrupt_text_addr,
3543 CTLTYPE_QUAD | CTLFLAG_WR | CTLFLAG_LOCKED | CTLFLAG_MASKED,
3544 0, 0, corrupt_text_addr, "-", "");
3545#endif /* DEBUG || DEVELOPMENT */