1/*
2 * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
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 */
34/*
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.
39 */
40#include <vm/vm_options.h>
41
42#include <kern/task.h>
43#include <kern/thread.h>
44#include <kern/debug.h>
45#include <kern/extmod_statistics.h>
46#include <mach/mach_traps.h>
47#include <mach/port.h>
48#include <mach/sdt.h>
49#include <mach/task.h>
50#include <mach/task_access.h>
51#include <mach/task_special_ports.h>
52#include <mach/time_value.h>
53#include <mach/vm_map.h>
54#include <mach/vm_param.h>
55#include <mach/vm_prot.h>
56
57#include <sys/file_internal.h>
58#include <sys/param.h>
59#include <sys/systm.h>
60#include <sys/dir.h>
61#include <sys/namei.h>
62#include <sys/proc_internal.h>
63#include <sys/kauth.h>
64#include <sys/vm.h>
65#include <sys/file.h>
66#include <sys/vnode_internal.h>
67#include <sys/mount.h>
68#include <sys/trace.h>
69#include <sys/kernel.h>
70#include <sys/ubc_internal.h>
71#include <sys/user.h>
72#include <sys/syslog.h>
73#include <sys/stat.h>
74#include <sys/sysproto.h>
75#include <sys/mman.h>
76#include <sys/sysctl.h>
77#include <sys/cprotect.h>
78#include <sys/kpi_socket.h>
79#include <sys/kas_info.h>
80#include <sys/socket.h>
81#include <sys/socketvar.h>
82#if NECP
83#include <net/necp.h>
84#endif /* NECP */
85
86#include <security/audit/audit.h>
87#include <security/mac.h>
88#include <bsm/audit_kevents.h>
89
90#include <kern/kalloc.h>
91#include <vm/vm_map.h>
92#include <vm/vm_kern.h>
93#include <vm/vm_pageout.h>
94
95#include <mach/shared_region.h>
96#include <vm/vm_shared_region.h>
97
98#include <vm/vm_protos.h>
99
100#include <sys/kern_memorystatus.h>
101
102#if CONFIG_MACF
103#include <security/mac_framework.h>
104#endif
105
106#if CONFIG_CSR
107#include <sys/csr.h>
108#endif /* CONFIG_CSR */
109
110int _shared_region_map_and_slide(struct proc*, int, unsigned int, struct shared_file_mapping_np*, uint32_t, user_addr_t, user_addr_t);
111int shared_region_copyin_mappings(struct proc*, user_addr_t, unsigned int, struct shared_file_mapping_np *);
112
113#if VM_MAP_DEBUG_APPLE_PROTECT
114SYSCTL_INT(_vm, OID_AUTO, map_debug_apple_protect, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_map_debug_apple_protect, 0, "");
115#endif /* VM_MAP_DEBUG_APPLE_PROTECT */
116
117#if VM_MAP_DEBUG_FOURK
118SYSCTL_INT(_vm, OID_AUTO, map_debug_fourk, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_map_debug_fourk, 0, "");
119#endif /* VM_MAP_DEBUG_FOURK */
120
121#if DEVELOPMENT || DEBUG
122
123static int
124sysctl_kmem_alloc_contig SYSCTL_HANDLER_ARGS
125{
126#pragma unused(arg1, arg2)
127 vm_offset_t kaddr;
128 kern_return_t kr;
129 int error = 0;
130 int size = 0;
131
132 error = sysctl_handle_int(oidp, &size, 0, req);
133 if (error || !req->newptr)
134 return (error);
135
136 kr = kmem_alloc_contig(kernel_map, &kaddr, (vm_size_t)size, 0, 0, 0, 0, VM_KERN_MEMORY_IOKIT);
137
138 if (kr == KERN_SUCCESS)
139 kmem_free(kernel_map, kaddr, size);
140
141 return error;
142}
143
144SYSCTL_PROC(_vm, OID_AUTO, kmem_alloc_contig, CTLTYPE_INT|CTLFLAG_WR|CTLFLAG_LOCKED|CTLFLAG_MASKED,
145 0, 0, &sysctl_kmem_alloc_contig, "I", "");
146
147extern int vm_region_footprint;
148SYSCTL_INT(_vm, OID_AUTO, region_footprint, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, &vm_region_footprint, 0, "");
149static int
150sysctl_vm_self_region_footprint SYSCTL_HANDLER_ARGS
151{
152#pragma unused(arg1, arg2, oidp)
153 int error = 0;
154 int value;
155
156 value = task_self_region_footprint();
157 error = SYSCTL_OUT(req, &value, sizeof (int));
158 if (error) {
159 return error;
160 }
161
162 if (!req->newptr) {
163 return 0;
164 }
165
166 error = SYSCTL_IN(req, &value, sizeof (int));
167 if (error) {
168 return (error);
169 }
170 task_self_region_footprint_set(value);
171 return 0;
172}
173SYSCTL_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", "");
174
175#endif /* DEVELOPMENT || DEBUG */
176
177
178#if CONFIG_EMBEDDED
179
180#if DEVELOPMENT || DEBUG
181extern int panic_on_unsigned_execute;
182SYSCTL_INT(_vm, OID_AUTO, panic_on_unsigned_execute, CTLFLAG_RW | CTLFLAG_LOCKED, &panic_on_unsigned_execute, 0, "");
183#endif /* DEVELOPMENT || DEBUG */
184
185extern int log_executable_mem_entry;
186extern int cs_executable_create_upl;
187extern int cs_executable_mem_entry;
188extern int cs_executable_wire;
189SYSCTL_INT(_vm, OID_AUTO, log_executable_mem_entry, CTLFLAG_RD | CTLFLAG_LOCKED, &log_executable_mem_entry, 0, "");
190SYSCTL_INT(_vm, OID_AUTO, cs_executable_create_upl, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_executable_create_upl, 0, "");
191SYSCTL_INT(_vm, OID_AUTO, cs_executable_mem_entry, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_executable_mem_entry, 0, "");
192SYSCTL_INT(_vm, OID_AUTO, cs_executable_wire, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_executable_wire, 0, "");
193#endif /* CONFIG_EMBEDDED */
194
195#if DEVELOPMENT || DEBUG
196extern int radar_20146450;
197SYSCTL_INT(_vm, OID_AUTO, radar_20146450, CTLFLAG_RW | CTLFLAG_LOCKED, &radar_20146450, 0, "");
198
199extern int macho_printf;
200SYSCTL_INT(_vm, OID_AUTO, macho_printf, CTLFLAG_RW | CTLFLAG_LOCKED, &macho_printf, 0, "");
201
202extern int apple_protect_pager_data_request_debug;
203SYSCTL_INT(_vm, OID_AUTO, apple_protect_pager_data_request_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &apple_protect_pager_data_request_debug, 0, "");
204
205#if __arm__ || __arm64__
206/* These are meant to support the page table accounting unit test. */
207extern unsigned int arm_hardware_page_size;
208extern unsigned int arm_pt_desc_size;
209extern unsigned int arm_pt_root_size;
210extern unsigned int free_page_size_tt_count;
211extern unsigned int free_two_page_size_tt_count;
212extern unsigned int free_tt_count;
213extern unsigned int inuse_user_tteroot_count;
214extern unsigned int inuse_kernel_tteroot_count;
215extern unsigned int inuse_user_ttepages_count;
216extern unsigned int inuse_kernel_ttepages_count;
217extern unsigned int inuse_user_ptepages_count;
218extern unsigned int inuse_kernel_ptepages_count;
219SYSCTL_UINT(_vm, OID_AUTO, native_hw_pagesize, CTLFLAG_RD | CTLFLAG_LOCKED, &arm_hardware_page_size, 0, "");
220SYSCTL_UINT(_vm, OID_AUTO, arm_pt_desc_size, CTLFLAG_RD | CTLFLAG_LOCKED, &arm_pt_desc_size, 0, "");
221SYSCTL_UINT(_vm, OID_AUTO, arm_pt_root_size, CTLFLAG_RD | CTLFLAG_LOCKED, &arm_pt_root_size, 0, "");
222SYSCTL_UINT(_vm, OID_AUTO, free_1page_tte_root, CTLFLAG_RD | CTLFLAG_LOCKED, &free_page_size_tt_count, 0, "");
223SYSCTL_UINT(_vm, OID_AUTO, free_2page_tte_root, CTLFLAG_RD | CTLFLAG_LOCKED, &free_two_page_size_tt_count, 0, "");
224SYSCTL_UINT(_vm, OID_AUTO, free_tte_root, CTLFLAG_RD | CTLFLAG_LOCKED, &free_tt_count, 0, "");
225SYSCTL_UINT(_vm, OID_AUTO, user_tte_root, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_user_tteroot_count, 0, "");
226SYSCTL_UINT(_vm, OID_AUTO, kernel_tte_root, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_kernel_tteroot_count, 0, "");
227SYSCTL_UINT(_vm, OID_AUTO, user_tte_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_user_ttepages_count, 0, "");
228SYSCTL_UINT(_vm, OID_AUTO, kernel_tte_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_kernel_ttepages_count, 0, "");
229SYSCTL_UINT(_vm, OID_AUTO, user_pte_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_user_ptepages_count, 0, "");
230SYSCTL_UINT(_vm, OID_AUTO, kernel_pte_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &inuse_kernel_ptepages_count, 0, "");
231#endif /* __arm__ || __arm64__ */
232
233#if __arm64__
234extern int fourk_pager_data_request_debug;
235SYSCTL_INT(_vm, OID_AUTO, fourk_pager_data_request_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &fourk_pager_data_request_debug, 0, "");
236#endif /* __arm64__ */
237#endif /* DEVELOPMENT || DEBUG */
238
239SYSCTL_INT(_vm, OID_AUTO, vm_do_collapse_compressor, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.do_collapse_compressor, 0, "");
240SYSCTL_INT(_vm, OID_AUTO, vm_do_collapse_compressor_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.do_collapse_compressor_pages, 0, "");
241SYSCTL_INT(_vm, OID_AUTO, vm_do_collapse_terminate, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.do_collapse_terminate, 0, "");
242SYSCTL_INT(_vm, OID_AUTO, vm_do_collapse_terminate_failure, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.do_collapse_terminate_failure, 0, "");
243SYSCTL_INT(_vm, OID_AUTO, vm_should_cow_but_wired, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.should_cow_but_wired, 0, "");
244SYSCTL_INT(_vm, OID_AUTO, vm_create_upl_extra_cow, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.create_upl_extra_cow, 0, "");
245SYSCTL_INT(_vm, OID_AUTO, vm_create_upl_extra_cow_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.create_upl_extra_cow_pages, 0, "");
246SYSCTL_INT(_vm, OID_AUTO, vm_create_upl_lookup_failure_write, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.create_upl_lookup_failure_write, 0, "");
247SYSCTL_INT(_vm, OID_AUTO, vm_create_upl_lookup_failure_copy, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_counters.create_upl_lookup_failure_copy, 0, "");
248#if VM_SCAN_FOR_SHADOW_CHAIN
249static int vm_shadow_max_enabled = 0; /* Disabled by default */
250extern int proc_shadow_max(void);
251static int
252vm_shadow_max SYSCTL_HANDLER_ARGS
253{
254#pragma unused(arg1, arg2, oidp)
255 int value = 0;
256
257 if (vm_shadow_max_enabled)
258 value = proc_shadow_max();
259
260 return SYSCTL_OUT(req, &value, sizeof(value));
261}
262SYSCTL_PROC(_vm, OID_AUTO, vm_shadow_max, CTLTYPE_INT|CTLFLAG_RD|CTLFLAG_LOCKED,
263 0, 0, &vm_shadow_max, "I", "");
264
265SYSCTL_INT(_vm, OID_AUTO, vm_shadow_max_enabled, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_shadow_max_enabled, 0, "");
266
267#endif /* VM_SCAN_FOR_SHADOW_CHAIN */
268
269SYSCTL_INT(_vm, OID_AUTO, vm_debug_events, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_debug_events, 0, "");
270
271__attribute__((noinline)) int __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(
272 mach_port_t task_access_port, int32_t calling_pid, uint32_t calling_gid, int32_t target_pid);
273/*
274 * Sysctl's related to data/stack execution. See osfmk/vm/vm_map.c
275 */
276
277#if DEVELOPMENT || DEBUG
278extern int allow_stack_exec, allow_data_exec;
279
280SYSCTL_INT(_vm, OID_AUTO, allow_stack_exec, CTLFLAG_RW | CTLFLAG_LOCKED, &allow_stack_exec, 0, "");
281SYSCTL_INT(_vm, OID_AUTO, allow_data_exec, CTLFLAG_RW | CTLFLAG_LOCKED, &allow_data_exec, 0, "");
282
283#endif /* DEVELOPMENT || DEBUG */
284
285static const char *prot_values[] = {
286 "none",
287 "read-only",
288 "write-only",
289 "read-write",
290 "execute-only",
291 "read-execute",
292 "write-execute",
293 "read-write-execute"
294};
295
296void
297log_stack_execution_failure(addr64_t vaddr, vm_prot_t prot)
298{
299 printf("Data/Stack execution not permitted: %s[pid %d] at virtual address 0x%qx, protections were %s\n",
300 current_proc()->p_comm, current_proc()->p_pid, vaddr, prot_values[prot & VM_PROT_ALL]);
301}
302
303/*
304 * shared_region_unnest_logging: level of logging of unnesting events
305 * 0 - no logging
306 * 1 - throttled logging of unexpected unnesting events (default)
307 * 2 - unthrottled logging of unexpected unnesting events
308 * 3+ - unthrottled logging of all unnesting events
309 */
310int shared_region_unnest_logging = 1;
311
312SYSCTL_INT(_vm, OID_AUTO, shared_region_unnest_logging, CTLFLAG_RW | CTLFLAG_LOCKED,
313 &shared_region_unnest_logging, 0, "");
314
315int vm_shared_region_unnest_log_interval = 10;
316int shared_region_unnest_log_count_threshold = 5;
317
318/*
319 * Shared cache path enforcement.
320 */
321
322#ifndef CONFIG_EMBEDDED
323static int scdir_enforce = 1;
324static char scdir_path[] = "/var/db/dyld/";
325#else
326static int scdir_enforce = 0;
327static char scdir_path[] = "/System/Library/Caches/com.apple.dyld/";
328#endif
329
330#ifndef SECURE_KERNEL
331static int sysctl_scdir_enforce SYSCTL_HANDLER_ARGS
332{
333#if CONFIG_CSR
334 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
335 printf("Failed attempt to set vm.enforce_shared_cache_dir sysctl\n");
336 return EPERM;
337 }
338#endif /* CONFIG_CSR */
339 return sysctl_handle_int(oidp, arg1, arg2, req);
340}
341
342SYSCTL_PROC(_vm, OID_AUTO, enforce_shared_cache_dir, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &scdir_enforce, 0, sysctl_scdir_enforce, "I", "");
343#endif
344
345/* These log rate throttling state variables aren't thread safe, but
346 * are sufficient unto the task.
347 */
348static int64_t last_unnest_log_time = 0;
349static int shared_region_unnest_log_count = 0;
350
351void
352log_unnest_badness(
353 vm_map_t m,
354 vm_map_offset_t s,
355 vm_map_offset_t e,
356 boolean_t is_nested_map,
357 vm_map_offset_t lowest_unnestable_addr)
358{
359 struct timeval tv;
360
361 if (shared_region_unnest_logging == 0)
362 return;
363
364 if (shared_region_unnest_logging <= 2 &&
365 is_nested_map &&
366 s >= lowest_unnestable_addr) {
367 /*
368 * Unnesting of writable map entries is fine.
369 */
370 return;
371 }
372
373 if (shared_region_unnest_logging <= 1) {
374 microtime(&tv);
375 if ((tv.tv_sec - last_unnest_log_time) <
376 vm_shared_region_unnest_log_interval) {
377 if (shared_region_unnest_log_count++ >
378 shared_region_unnest_log_count_threshold)
379 return;
380 } else {
381 last_unnest_log_time = tv.tv_sec;
382 shared_region_unnest_log_count = 0;
383 }
384 }
385
386 DTRACE_VM4(log_unnest_badness,
387 vm_map_t, m,
388 vm_map_offset_t, s,
389 vm_map_offset_t, e,
390 vm_map_offset_t, lowest_unnestable_addr);
391 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));
392}
393
394int
395useracc(
396 user_addr_t addr,
397 user_size_t len,
398 int prot)
399{
400 vm_map_t map;
401
402 map = current_map();
403 return (vm_map_check_protection(
404 map,
405 vm_map_trunc_page(addr,
406 vm_map_page_mask(map)),
407 vm_map_round_page(addr+len,
408 vm_map_page_mask(map)),
409 prot == B_READ ? VM_PROT_READ : VM_PROT_WRITE));
410}
411
412int
413vslock(
414 user_addr_t addr,
415 user_size_t len)
416{
417 kern_return_t kret;
418 vm_map_t map;
419
420 map = current_map();
421 kret = vm_map_wire_kernel(map,
422 vm_map_trunc_page(addr,
423 vm_map_page_mask(map)),
424 vm_map_round_page(addr+len,
425 vm_map_page_mask(map)),
426 VM_PROT_READ | VM_PROT_WRITE, VM_KERN_MEMORY_BSD,
427 FALSE);
428
429 switch (kret) {
430 case KERN_SUCCESS:
431 return (0);
432 case KERN_INVALID_ADDRESS:
433 case KERN_NO_SPACE:
434 return (ENOMEM);
435 case KERN_PROTECTION_FAILURE:
436 return (EACCES);
437 default:
438 return (EINVAL);
439 }
440}
441
442int
443vsunlock(
444 user_addr_t addr,
445 user_size_t len,
446 __unused int dirtied)
447{
448#if FIXME /* [ */
449 pmap_t pmap;
450 vm_page_t pg;
451 vm_map_offset_t vaddr;
452 ppnum_t paddr;
453#endif /* FIXME ] */
454 kern_return_t kret;
455 vm_map_t map;
456
457 map = current_map();
458
459#if FIXME /* [ */
460 if (dirtied) {
461 pmap = get_task_pmap(current_task());
462 for (vaddr = vm_map_trunc_page(addr, PAGE_MASK);
463 vaddr < vm_map_round_page(addr+len, PAGE_MASK);
464 vaddr += PAGE_SIZE) {
465 paddr = pmap_extract(pmap, vaddr);
466 pg = PHYS_TO_VM_PAGE(paddr);
467 vm_page_set_modified(pg);
468 }
469 }
470#endif /* FIXME ] */
471#ifdef lint
472 dirtied++;
473#endif /* lint */
474 kret = vm_map_unwire(map,
475 vm_map_trunc_page(addr,
476 vm_map_page_mask(map)),
477 vm_map_round_page(addr+len,
478 vm_map_page_mask(map)),
479 FALSE);
480 switch (kret) {
481 case KERN_SUCCESS:
482 return (0);
483 case KERN_INVALID_ADDRESS:
484 case KERN_NO_SPACE:
485 return (ENOMEM);
486 case KERN_PROTECTION_FAILURE:
487 return (EACCES);
488 default:
489 return (EINVAL);
490 }
491}
492
493int
494subyte(
495 user_addr_t addr,
496 int byte)
497{
498 char character;
499
500 character = (char)byte;
501 return (copyout((void *)&(character), addr, sizeof(char)) == 0 ? 0 : -1);
502}
503
504int
505suibyte(
506 user_addr_t addr,
507 int byte)
508{
509 char character;
510
511 character = (char)byte;
512 return (copyout((void *)&(character), addr, sizeof(char)) == 0 ? 0 : -1);
513}
514
515int fubyte(user_addr_t addr)
516{
517 unsigned char byte;
518
519 if (copyin(addr, (void *) &byte, sizeof(char)))
520 return(-1);
521 return(byte);
522}
523
524int fuibyte(user_addr_t addr)
525{
526 unsigned char byte;
527
528 if (copyin(addr, (void *) &(byte), sizeof(char)))
529 return(-1);
530 return(byte);
531}
532
533int
534suword(
535 user_addr_t addr,
536 long word)
537{
538 return (copyout((void *) &word, addr, sizeof(int)) == 0 ? 0 : -1);
539}
540
541long fuword(user_addr_t addr)
542{
543 long word = 0;
544
545 if (copyin(addr, (void *) &word, sizeof(int)))
546 return(-1);
547 return(word);
548}
549
550/* suiword and fuiword are the same as suword and fuword, respectively */
551
552int
553suiword(
554 user_addr_t addr,
555 long word)
556{
557 return (copyout((void *) &word, addr, sizeof(int)) == 0 ? 0 : -1);
558}
559
560long fuiword(user_addr_t addr)
561{
562 long word = 0;
563
564 if (copyin(addr, (void *) &word, sizeof(int)))
565 return(-1);
566 return(word);
567}
568
569/*
570 * With a 32-bit kernel and mixed 32/64-bit user tasks, this interface allows the
571 * fetching and setting of process-sized size_t and pointer values.
572 */
573int
574sulong(user_addr_t addr, int64_t word)
575{
576
577 if (IS_64BIT_PROCESS(current_proc())) {
578 return(copyout((void *)&word, addr, sizeof(word)) == 0 ? 0 : -1);
579 } else {
580 return(suiword(addr, (long)word));
581 }
582}
583
584int64_t
585fulong(user_addr_t addr)
586{
587 int64_t longword;
588
589 if (IS_64BIT_PROCESS(current_proc())) {
590 if (copyin(addr, (void *)&longword, sizeof(longword)) != 0)
591 return(-1);
592 return(longword);
593 } else {
594 return((int64_t)fuiword(addr));
595 }
596}
597
598int
599suulong(user_addr_t addr, uint64_t uword)
600{
601
602 if (IS_64BIT_PROCESS(current_proc())) {
603 return(copyout((void *)&uword, addr, sizeof(uword)) == 0 ? 0 : -1);
604 } else {
605 return(suiword(addr, (uint32_t)uword));
606 }
607}
608
609uint64_t
610fuulong(user_addr_t addr)
611{
612 uint64_t ulongword;
613
614 if (IS_64BIT_PROCESS(current_proc())) {
615 if (copyin(addr, (void *)&ulongword, sizeof(ulongword)) != 0)
616 return(-1ULL);
617 return(ulongword);
618 } else {
619 return((uint64_t)fuiword(addr));
620 }
621}
622
623int
624swapon(__unused proc_t procp, __unused struct swapon_args *uap, __unused int *retval)
625{
626 return(ENOTSUP);
627}
628
629/*
630 * pid_for_task
631 *
632 * Find the BSD process ID for the Mach task associated with the given Mach port
633 * name
634 *
635 * Parameters: args User argument descriptor (see below)
636 *
637 * Indirect parameters: args->t Mach port name
638 * args->pid Process ID (returned value; see below)
639 *
640 * Returns: KERL_SUCCESS Success
641 * KERN_FAILURE Not success
642 *
643 * Implicit returns: args->pid Process ID
644 *
645 */
646kern_return_t
647pid_for_task(
648 struct pid_for_task_args *args)
649{
650 mach_port_name_t t = args->t;
651 user_addr_t pid_addr = args->pid;
652 proc_t p;
653 task_t t1;
654 int pid = -1;
655 kern_return_t err = KERN_SUCCESS;
656
657 AUDIT_MACH_SYSCALL_ENTER(AUE_PIDFORTASK);
658 AUDIT_ARG(mach_port1, t);
659
660 t1 = port_name_to_task_inspect(t);
661
662 if (t1 == TASK_NULL) {
663 err = KERN_FAILURE;
664 goto pftout;
665 } else {
666 p = get_bsdtask_info(t1);
667 if (p) {
668 pid = proc_pid(p);
669 err = KERN_SUCCESS;
670 } else if (is_corpsetask(t1)) {
671 pid = task_pid(t1);
672 err = KERN_SUCCESS;
673 }else {
674 err = KERN_FAILURE;
675 }
676 }
677 task_deallocate(t1);
678pftout:
679 AUDIT_ARG(pid, pid);
680 (void) copyout((char *) &pid, pid_addr, sizeof(int));
681 AUDIT_MACH_SYSCALL_EXIT(err);
682 return(err);
683}
684
685/*
686 *
687 * tfp_policy = KERN_TFP_POLICY_DENY; Deny Mode: None allowed except for self
688 * tfp_policy = KERN_TFP_POLICY_DEFAULT; default mode: all posix checks and upcall via task port for authentication
689 *
690 */
691static int tfp_policy = KERN_TFP_POLICY_DEFAULT;
692
693/*
694 * Routine: task_for_pid_posix_check
695 * Purpose:
696 * Verify that the current process should be allowed to
697 * get the target process's task port. This is only
698 * permitted if:
699 * - The current process is root
700 * OR all of the following are true:
701 * - The target process's real, effective, and saved uids
702 * are the same as the current proc's euid,
703 * - The target process's group set is a subset of the
704 * calling process's group set, and
705 * - The target process hasn't switched credentials.
706 *
707 * Returns: TRUE: permitted
708 * FALSE: denied
709 */
710static int
711task_for_pid_posix_check(proc_t target)
712{
713 kauth_cred_t targetcred, mycred;
714 uid_t myuid;
715 int allowed;
716
717 /* No task_for_pid on bad targets */
718 if (target->p_stat == SZOMB) {
719 return FALSE;
720 }
721
722 mycred = kauth_cred_get();
723 myuid = kauth_cred_getuid(mycred);
724
725 /* If we're running as root, the check passes */
726 if (kauth_cred_issuser(mycred))
727 return TRUE;
728
729 /* We're allowed to get our own task port */
730 if (target == current_proc())
731 return TRUE;
732
733 /*
734 * Under DENY, only root can get another proc's task port,
735 * so no more checks are needed.
736 */
737 if (tfp_policy == KERN_TFP_POLICY_DENY) {
738 return FALSE;
739 }
740
741 targetcred = kauth_cred_proc_ref(target);
742 allowed = TRUE;
743
744 /* Do target's ruid, euid, and saved uid match my euid? */
745 if ((kauth_cred_getuid(targetcred) != myuid) ||
746 (kauth_cred_getruid(targetcred) != myuid) ||
747 (kauth_cred_getsvuid(targetcred) != myuid)) {
748 allowed = FALSE;
749 goto out;
750 }
751
752 /* Are target's groups a subset of my groups? */
753 if (kauth_cred_gid_subset(targetcred, mycred, &allowed) ||
754 allowed == 0) {
755 allowed = FALSE;
756 goto out;
757 }
758
759 /* Has target switched credentials? */
760 if (target->p_flag & P_SUGID) {
761 allowed = FALSE;
762 goto out;
763 }
764
765out:
766 kauth_cred_unref(&targetcred);
767 return allowed;
768}
769
770/*
771 * __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__
772 *
773 * Description: Waits for the user space daemon to respond to the request
774 * we made. Function declared non inline to be visible in
775 * stackshots and spindumps as well as debugging.
776 */
777__attribute__((noinline)) int __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(
778 mach_port_t task_access_port, int32_t calling_pid, uint32_t calling_gid, int32_t target_pid)
779{
780 return check_task_access(task_access_port, calling_pid, calling_gid, target_pid);
781}
782
783/*
784 * Routine: task_for_pid
785 * Purpose:
786 * Get the task port for another "process", named by its
787 * process ID on the same host as "target_task".
788 *
789 * Only permitted to privileged processes, or processes
790 * with the same user ID.
791 *
792 * Note: if pid == 0, an error is return no matter who is calling.
793 *
794 * XXX This should be a BSD system call, not a Mach trap!!!
795 */
796kern_return_t
797task_for_pid(
798 struct task_for_pid_args *args)
799{
800 mach_port_name_t target_tport = args->target_tport;
801 int pid = args->pid;
802 user_addr_t task_addr = args->t;
803 proc_t p = PROC_NULL;
804 task_t t1 = TASK_NULL;
805 task_t task = TASK_NULL;
806 mach_port_name_t tret = MACH_PORT_NULL;
807 ipc_port_t tfpport = MACH_PORT_NULL;
808 void * sright;
809 int error = 0;
810
811 AUDIT_MACH_SYSCALL_ENTER(AUE_TASKFORPID);
812 AUDIT_ARG(pid, pid);
813 AUDIT_ARG(mach_port1, target_tport);
814
815 /* Always check if pid == 0 */
816 if (pid == 0) {
817 (void ) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
818 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
819 return(KERN_FAILURE);
820 }
821
822 t1 = port_name_to_task(target_tport);
823 if (t1 == TASK_NULL) {
824 (void) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
825 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
826 return(KERN_FAILURE);
827 }
828
829
830 p = proc_find(pid);
831 if (p == PROC_NULL) {
832 error = KERN_FAILURE;
833 goto tfpout;
834 }
835
836#if CONFIG_AUDIT
837 AUDIT_ARG(process, p);
838#endif
839
840 if (!(task_for_pid_posix_check(p))) {
841 error = KERN_FAILURE;
842 goto tfpout;
843 }
844
845 if (p->task == TASK_NULL) {
846 error = KERN_SUCCESS;
847 goto tfpout;
848 }
849
850#if CONFIG_MACF
851 error = mac_proc_check_get_task(kauth_cred_get(), p);
852 if (error) {
853 error = KERN_FAILURE;
854 goto tfpout;
855 }
856#endif
857
858 /* Grab a task reference since the proc ref might be dropped if an upcall to task access server is made */
859 task = p->task;
860 task_reference(task);
861
862 /* If we aren't root and target's task access port is set... */
863 if (!kauth_cred_issuser(kauth_cred_get()) &&
864 p != current_proc() &&
865 (task_get_task_access_port(task, &tfpport) == 0) &&
866 (tfpport != IPC_PORT_NULL)) {
867
868 if (tfpport == IPC_PORT_DEAD) {
869 error = KERN_PROTECTION_FAILURE;
870 goto tfpout;
871 }
872
873 /*
874 * Drop the proc_find proc ref before making an upcall
875 * to taskgated, since holding a proc_find
876 * ref while making an upcall can cause deadlock.
877 */
878 proc_rele(p);
879 p = PROC_NULL;
880
881 /* Call up to the task access server */
882 error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport, proc_selfpid(), kauth_getgid(), pid);
883
884 if (error != MACH_MSG_SUCCESS) {
885 if (error == MACH_RCV_INTERRUPTED)
886 error = KERN_ABORTED;
887 else
888 error = KERN_FAILURE;
889 goto tfpout;
890 }
891 }
892
893 /* Grant task port access */
894 extmod_statistics_incr_task_for_pid(task);
895 sright = (void *) convert_task_to_port(task);
896
897 /* Check if the task has been corpsified */
898 if (is_corpsetask(task)) {
899 /* task ref consumed by convert_task_to_port */
900 task = TASK_NULL;
901 ipc_port_release_send(sright);
902 error = KERN_FAILURE;
903 goto tfpout;
904 }
905
906 /* task ref consumed by convert_task_to_port */
907 task = TASK_NULL;
908 tret = ipc_port_copyout_send(
909 sright,
910 get_task_ipcspace(current_task()));
911
912 error = KERN_SUCCESS;
913
914tfpout:
915 task_deallocate(t1);
916 AUDIT_ARG(mach_port2, tret);
917 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
918
919 if (tfpport != IPC_PORT_NULL) {
920 ipc_port_release_send(tfpport);
921 }
922 if (task != TASK_NULL) {
923 task_deallocate(task);
924 }
925 if (p != PROC_NULL)
926 proc_rele(p);
927 AUDIT_MACH_SYSCALL_EXIT(error);
928 return(error);
929}
930
931/*
932 * Routine: task_name_for_pid
933 * Purpose:
934 * Get the task name port for another "process", named by its
935 * process ID on the same host as "target_task".
936 *
937 * Only permitted to privileged processes, or processes
938 * with the same user ID.
939 *
940 * XXX This should be a BSD system call, not a Mach trap!!!
941 */
942
943kern_return_t
944task_name_for_pid(
945 struct task_name_for_pid_args *args)
946{
947 mach_port_name_t target_tport = args->target_tport;
948 int pid = args->pid;
949 user_addr_t task_addr = args->t;
950 proc_t p = PROC_NULL;
951 task_t t1;
952 mach_port_name_t tret;
953 void * sright;
954 int error = 0, refheld = 0;
955 kauth_cred_t target_cred;
956
957 AUDIT_MACH_SYSCALL_ENTER(AUE_TASKNAMEFORPID);
958 AUDIT_ARG(pid, pid);
959 AUDIT_ARG(mach_port1, target_tport);
960
961 t1 = port_name_to_task(target_tport);
962 if (t1 == TASK_NULL) {
963 (void) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
964 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
965 return(KERN_FAILURE);
966 }
967
968 p = proc_find(pid);
969 if (p != PROC_NULL) {
970 AUDIT_ARG(process, p);
971 target_cred = kauth_cred_proc_ref(p);
972 refheld = 1;
973
974 if ((p->p_stat != SZOMB)
975 && ((current_proc() == p)
976 || kauth_cred_issuser(kauth_cred_get())
977 || ((kauth_cred_getuid(target_cred) == kauth_cred_getuid(kauth_cred_get())) &&
978 ((kauth_cred_getruid(target_cred) == kauth_getruid()))))) {
979
980 if (p->task != TASK_NULL) {
981 task_reference(p->task);
982#if CONFIG_MACF
983 error = mac_proc_check_get_task_name(kauth_cred_get(), p);
984 if (error) {
985 task_deallocate(p->task);
986 goto noperm;
987 }
988#endif
989 sright = (void *)convert_task_name_to_port(p->task);
990 tret = ipc_port_copyout_send(sright,
991 get_task_ipcspace(current_task()));
992 } else
993 tret = MACH_PORT_NULL;
994
995 AUDIT_ARG(mach_port2, tret);
996 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
997 task_deallocate(t1);
998 error = KERN_SUCCESS;
999 goto tnfpout;
1000 }
1001 }
1002
1003#if CONFIG_MACF
1004noperm:
1005#endif
1006 task_deallocate(t1);
1007 tret = MACH_PORT_NULL;
1008 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
1009 error = KERN_FAILURE;
1010tnfpout:
1011 if (refheld != 0)
1012 kauth_cred_unref(&target_cred);
1013 if (p != PROC_NULL)
1014 proc_rele(p);
1015 AUDIT_MACH_SYSCALL_EXIT(error);
1016 return(error);
1017}
1018
1019kern_return_t
1020pid_suspend(struct proc *p __unused, struct pid_suspend_args *args, int *ret)
1021{
1022 task_t target = NULL;
1023 proc_t targetproc = PROC_NULL;
1024 int pid = args->pid;
1025 int error = 0;
1026
1027#if CONFIG_MACF
1028 error = mac_proc_check_suspend_resume(p, MAC_PROC_CHECK_SUSPEND);
1029 if (error) {
1030 error = EPERM;
1031 goto out;
1032 }
1033#endif
1034
1035 if (pid == 0) {
1036 error = EPERM;
1037 goto out;
1038 }
1039
1040 targetproc = proc_find(pid);
1041 if (targetproc == PROC_NULL) {
1042 error = ESRCH;
1043 goto out;
1044 }
1045
1046 if (!task_for_pid_posix_check(targetproc)) {
1047 error = EPERM;
1048 goto out;
1049 }
1050
1051 target = targetproc->task;
1052#ifndef CONFIG_EMBEDDED
1053 if (target != TASK_NULL) {
1054 mach_port_t tfpport;
1055
1056 /* If we aren't root and target's task access port is set... */
1057 if (!kauth_cred_issuser(kauth_cred_get()) &&
1058 targetproc != current_proc() &&
1059 (task_get_task_access_port(target, &tfpport) == 0) &&
1060 (tfpport != IPC_PORT_NULL)) {
1061
1062 if (tfpport == IPC_PORT_DEAD) {
1063 error = EACCES;
1064 goto out;
1065 }
1066
1067 /* Call up to the task access server */
1068 error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport, proc_selfpid(), kauth_getgid(), pid);
1069
1070 if (error != MACH_MSG_SUCCESS) {
1071 if (error == MACH_RCV_INTERRUPTED)
1072 error = EINTR;
1073 else
1074 error = EPERM;
1075 goto out;
1076 }
1077 }
1078 }
1079#endif
1080
1081 task_reference(target);
1082 error = task_pidsuspend(target);
1083 if (error) {
1084 if (error == KERN_INVALID_ARGUMENT) {
1085 error = EINVAL;
1086 } else {
1087 error = EPERM;
1088 }
1089 }
1090#if CONFIG_MEMORYSTATUS
1091 else {
1092 memorystatus_on_suspend(targetproc);
1093 }
1094#endif
1095
1096 task_deallocate(target);
1097
1098out:
1099 if (targetproc != PROC_NULL)
1100 proc_rele(targetproc);
1101 *ret = error;
1102 return error;
1103}
1104
1105kern_return_t
1106pid_resume(struct proc *p __unused, struct pid_resume_args *args, int *ret)
1107{
1108 task_t target = NULL;
1109 proc_t targetproc = PROC_NULL;
1110 int pid = args->pid;
1111 int error = 0;
1112
1113#if CONFIG_MACF
1114 error = mac_proc_check_suspend_resume(p, MAC_PROC_CHECK_RESUME);
1115 if (error) {
1116 error = EPERM;
1117 goto out;
1118 }
1119#endif
1120
1121 if (pid == 0) {
1122 error = EPERM;
1123 goto out;
1124 }
1125
1126 targetproc = proc_find(pid);
1127 if (targetproc == PROC_NULL) {
1128 error = ESRCH;
1129 goto out;
1130 }
1131
1132 if (!task_for_pid_posix_check(targetproc)) {
1133 error = EPERM;
1134 goto out;
1135 }
1136
1137 target = targetproc->task;
1138#ifndef CONFIG_EMBEDDED
1139 if (target != TASK_NULL) {
1140 mach_port_t tfpport;
1141
1142 /* If we aren't root and target's task access port is set... */
1143 if (!kauth_cred_issuser(kauth_cred_get()) &&
1144 targetproc != current_proc() &&
1145 (task_get_task_access_port(target, &tfpport) == 0) &&
1146 (tfpport != IPC_PORT_NULL)) {
1147
1148 if (tfpport == IPC_PORT_DEAD) {
1149 error = EACCES;
1150 goto out;
1151 }
1152
1153 /* Call up to the task access server */
1154 error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport, proc_selfpid(), kauth_getgid(), pid);
1155
1156 if (error != MACH_MSG_SUCCESS) {
1157 if (error == MACH_RCV_INTERRUPTED)
1158 error = EINTR;
1159 else
1160 error = EPERM;
1161 goto out;
1162 }
1163 }
1164 }
1165#endif
1166
1167#if CONFIG_EMBEDDED
1168#if SOCKETS
1169 resume_proc_sockets(targetproc);
1170#endif /* SOCKETS */
1171#endif /* CONFIG_EMBEDDED */
1172
1173 task_reference(target);
1174
1175#if CONFIG_MEMORYSTATUS
1176 memorystatus_on_resume(targetproc);
1177#endif
1178
1179 error = task_pidresume(target);
1180 if (error) {
1181 if (error == KERN_INVALID_ARGUMENT) {
1182 error = EINVAL;
1183 } else {
1184 if (error == KERN_MEMORY_ERROR) {
1185 psignal(targetproc, SIGKILL);
1186 error = EIO;
1187 } else
1188 error = EPERM;
1189 }
1190 }
1191
1192 task_deallocate(target);
1193
1194out:
1195 if (targetproc != PROC_NULL)
1196 proc_rele(targetproc);
1197
1198 *ret = error;
1199 return error;
1200}
1201
1202#if CONFIG_EMBEDDED
1203/*
1204 * Freeze the specified process (provided in args->pid), or find and freeze a PID.
1205 * When a process is specified, this call is blocking, otherwise we wake up the
1206 * freezer thread and do not block on a process being frozen.
1207 */
1208kern_return_t
1209pid_hibernate(struct proc *p __unused, struct pid_hibernate_args *args, int *ret)
1210{
1211 int error = 0;
1212 proc_t targetproc = PROC_NULL;
1213 int pid = args->pid;
1214
1215#ifndef CONFIG_FREEZE
1216 #pragma unused(pid)
1217#else
1218
1219#if CONFIG_MACF
1220 error = mac_proc_check_suspend_resume(p, MAC_PROC_CHECK_HIBERNATE);
1221 if (error) {
1222 error = EPERM;
1223 goto out;
1224 }
1225#endif
1226
1227 /*
1228 * If a pid has been provided, we obtain the process handle and call task_for_pid_posix_check().
1229 */
1230
1231 if (pid >= 0) {
1232 targetproc = proc_find(pid);
1233
1234 if (targetproc == PROC_NULL) {
1235 error = ESRCH;
1236 goto out;
1237 }
1238
1239 if (!task_for_pid_posix_check(targetproc)) {
1240 error = EPERM;
1241 goto out;
1242 }
1243 }
1244
1245 if (pid == -2) {
1246 vm_pageout_anonymous_pages();
1247 } else if (pid == -1) {
1248 memorystatus_on_inactivity(targetproc);
1249 } else {
1250 error = memorystatus_freeze_process_sync(targetproc);
1251 }
1252
1253out:
1254
1255#endif /* CONFIG_FREEZE */
1256
1257 if (targetproc != PROC_NULL)
1258 proc_rele(targetproc);
1259 *ret = error;
1260 return error;
1261}
1262#endif /* CONFIG_EMBEDDED */
1263
1264#if SOCKETS
1265int
1266networking_memstatus_callout(proc_t p, uint32_t status)
1267{
1268 struct filedesc *fdp;
1269 int i;
1270
1271 /*
1272 * proc list lock NOT held
1273 * proc lock NOT held
1274 * a reference on the proc has been held / shall be dropped by the caller.
1275 */
1276 LCK_MTX_ASSERT(proc_list_mlock, LCK_MTX_ASSERT_NOTOWNED);
1277 LCK_MTX_ASSERT(&p->p_mlock, LCK_MTX_ASSERT_NOTOWNED);
1278
1279 proc_fdlock(p);
1280 fdp = p->p_fd;
1281 for (i = 0; i < fdp->fd_nfiles; i++) {
1282 struct fileproc *fp;
1283
1284 fp = fdp->fd_ofiles[i];
1285 if (fp == NULL || (fdp->fd_ofileflags[i] & UF_RESERVED) != 0) {
1286 continue;
1287 }
1288 switch (FILEGLOB_DTYPE(fp->f_fglob)) {
1289#if NECP
1290 case DTYPE_NETPOLICY:
1291 necp_fd_memstatus(p, status,
1292 (struct necp_fd_data *)fp->f_fglob->fg_data);
1293 break;
1294#endif /* NECP */
1295 default:
1296 break;
1297 }
1298 }
1299 proc_fdunlock(p);
1300
1301 return (1);
1302}
1303
1304
1305static int
1306networking_defunct_callout(proc_t p, void *arg)
1307{
1308 struct pid_shutdown_sockets_args *args = arg;
1309 int pid = args->pid;
1310 int level = args->level;
1311 struct filedesc *fdp;
1312 int i;
1313
1314 proc_fdlock(p);
1315 fdp = p->p_fd;
1316 for (i = 0; i < fdp->fd_nfiles; i++) {
1317 struct fileproc *fp = fdp->fd_ofiles[i];
1318 struct fileglob *fg;
1319
1320 if (fp == NULL || (fdp->fd_ofileflags[i] & UF_RESERVED) != 0) {
1321 continue;
1322 }
1323
1324 fg = fp->f_fglob;
1325 switch (FILEGLOB_DTYPE(fg)) {
1326 case DTYPE_SOCKET: {
1327 struct socket *so = (struct socket *)fg->fg_data;
1328 if (p->p_pid == pid || so->last_pid == pid ||
1329 ((so->so_flags & SOF_DELEGATED) && so->e_pid == pid)) {
1330 /* Call networking stack with socket and level */
1331 (void) socket_defunct(p, so, level);
1332 }
1333 break;
1334 }
1335#if NECP
1336 case DTYPE_NETPOLICY:
1337 /* first pass: defunct necp and get stats for ntstat */
1338 if (p->p_pid == pid) {
1339 necp_fd_defunct(p,
1340 (struct necp_fd_data *)fg->fg_data);
1341 }
1342 break;
1343#endif /* NECP */
1344 default:
1345 break;
1346 }
1347 }
1348
1349 proc_fdunlock(p);
1350
1351 return (PROC_RETURNED);
1352}
1353
1354int
1355pid_shutdown_sockets(struct proc *p __unused, struct pid_shutdown_sockets_args *args, int *ret)
1356{
1357 int error = 0;
1358 proc_t targetproc = PROC_NULL;
1359 int pid = args->pid;
1360 int level = args->level;
1361
1362 if (level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC &&
1363 level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL) {
1364 error = EINVAL;
1365 goto out;
1366 }
1367
1368#if CONFIG_MACF
1369 error = mac_proc_check_suspend_resume(p, MAC_PROC_CHECK_SHUTDOWN_SOCKETS);
1370 if (error) {
1371 error = EPERM;
1372 goto out;
1373 }
1374#endif
1375
1376 targetproc = proc_find(pid);
1377 if (targetproc == PROC_NULL) {
1378 error = ESRCH;
1379 goto out;
1380 }
1381
1382 if (!task_for_pid_posix_check(targetproc)) {
1383 error = EPERM;
1384 goto out;
1385 }
1386
1387 proc_iterate(PROC_ALLPROCLIST | PROC_NOWAITTRANS,
1388 networking_defunct_callout, args, NULL, NULL);
1389
1390out:
1391 if (targetproc != PROC_NULL)
1392 proc_rele(targetproc);
1393 *ret = error;
1394 return error;
1395}
1396
1397#endif /* SOCKETS */
1398
1399static int
1400sysctl_settfp_policy(__unused struct sysctl_oid *oidp, void *arg1,
1401 __unused int arg2, struct sysctl_req *req)
1402{
1403 int error = 0;
1404 int new_value;
1405
1406 error = SYSCTL_OUT(req, arg1, sizeof(int));
1407 if (error || req->newptr == USER_ADDR_NULL)
1408 return(error);
1409
1410 if (!kauth_cred_issuser(kauth_cred_get()))
1411 return(EPERM);
1412
1413 if ((error = SYSCTL_IN(req, &new_value, sizeof(int)))) {
1414 goto out;
1415 }
1416 if ((new_value == KERN_TFP_POLICY_DENY)
1417 || (new_value == KERN_TFP_POLICY_DEFAULT))
1418 tfp_policy = new_value;
1419 else
1420 error = EINVAL;
1421out:
1422 return(error);
1423
1424}
1425
1426#if defined(SECURE_KERNEL)
1427static int kern_secure_kernel = 1;
1428#else
1429static int kern_secure_kernel = 0;
1430#endif
1431
1432SYSCTL_INT(_kern, OID_AUTO, secure_kernel, CTLFLAG_RD | CTLFLAG_LOCKED, &kern_secure_kernel, 0, "");
1433
1434SYSCTL_NODE(_kern, KERN_TFP, tfp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "tfp");
1435SYSCTL_PROC(_kern_tfp, KERN_TFP_POLICY, policy, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
1436 &tfp_policy, sizeof(uint32_t), &sysctl_settfp_policy ,"I","policy");
1437
1438SYSCTL_INT(_vm, OID_AUTO, shared_region_trace_level, CTLFLAG_RW | CTLFLAG_LOCKED,
1439 &shared_region_trace_level, 0, "");
1440SYSCTL_INT(_vm, OID_AUTO, shared_region_version, CTLFLAG_RD | CTLFLAG_LOCKED,
1441 &shared_region_version, 0, "");
1442SYSCTL_INT(_vm, OID_AUTO, shared_region_persistence, CTLFLAG_RW | CTLFLAG_LOCKED,
1443 &shared_region_persistence, 0, "");
1444
1445/*
1446 * shared_region_check_np:
1447 *
1448 * This system call is intended for dyld.
1449 *
1450 * dyld calls this when any process starts to see if the process's shared
1451 * region is already set up and ready to use.
1452 * This call returns the base address of the first mapping in the
1453 * process's shared region's first mapping.
1454 * dyld will then check what's mapped at that address.
1455 *
1456 * If the shared region is empty, dyld will then attempt to map the shared
1457 * cache file in the shared region via the shared_region_map_np() system call.
1458 *
1459 * If something's already mapped in the shared region, dyld will check if it
1460 * matches the shared cache it would like to use for that process.
1461 * If it matches, evrything's ready and the process can proceed and use the
1462 * shared region.
1463 * If it doesn't match, dyld will unmap the shared region and map the shared
1464 * cache into the process's address space via mmap().
1465 *
1466 * ERROR VALUES
1467 * EINVAL no shared region
1468 * ENOMEM shared region is empty
1469 * EFAULT bad address for "start_address"
1470 */
1471int
1472shared_region_check_np(
1473 __unused struct proc *p,
1474 struct shared_region_check_np_args *uap,
1475 __unused int *retvalp)
1476{
1477 vm_shared_region_t shared_region;
1478 mach_vm_offset_t start_address = 0;
1479 int error;
1480 kern_return_t kr;
1481
1482 SHARED_REGION_TRACE_DEBUG(
1483 ("shared_region: %p [%d(%s)] -> check_np(0x%llx)\n",
1484 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1485 p->p_pid, p->p_comm,
1486 (uint64_t)uap->start_address));
1487
1488 /* retrieve the current tasks's shared region */
1489 shared_region = vm_shared_region_get(current_task());
1490 if (shared_region != NULL) {
1491 /* retrieve address of its first mapping... */
1492 kr = vm_shared_region_start_address(shared_region,
1493 &start_address);
1494 if (kr != KERN_SUCCESS) {
1495 error = ENOMEM;
1496 } else {
1497 /* ... and give it to the caller */
1498 error = copyout(&start_address,
1499 (user_addr_t) uap->start_address,
1500 sizeof (start_address));
1501 if (error) {
1502 SHARED_REGION_TRACE_ERROR(
1503 ("shared_region: %p [%d(%s)] "
1504 "check_np(0x%llx) "
1505 "copyout(0x%llx) error %d\n",
1506 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1507 p->p_pid, p->p_comm,
1508 (uint64_t)uap->start_address, (uint64_t)start_address,
1509 error));
1510 }
1511 }
1512 vm_shared_region_deallocate(shared_region);
1513 } else {
1514 /* no shared region ! */
1515 error = EINVAL;
1516 }
1517
1518 SHARED_REGION_TRACE_DEBUG(
1519 ("shared_region: %p [%d(%s)] check_np(0x%llx) <- 0x%llx %d\n",
1520 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1521 p->p_pid, p->p_comm,
1522 (uint64_t)uap->start_address, (uint64_t)start_address, error));
1523
1524 return error;
1525}
1526
1527
1528int
1529shared_region_copyin_mappings(
1530 struct proc *p,
1531 user_addr_t user_mappings,
1532 unsigned int mappings_count,
1533 struct shared_file_mapping_np *mappings)
1534{
1535 int error = 0;
1536 vm_size_t mappings_size = 0;
1537
1538 /* get the list of mappings the caller wants us to establish */
1539 mappings_size = (vm_size_t) (mappings_count * sizeof (mappings[0]));
1540 error = copyin(user_mappings,
1541 mappings,
1542 mappings_size);
1543 if (error) {
1544 SHARED_REGION_TRACE_ERROR(
1545 ("shared_region: %p [%d(%s)] map(): "
1546 "copyin(0x%llx, %d) failed (error=%d)\n",
1547 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1548 p->p_pid, p->p_comm,
1549 (uint64_t)user_mappings, mappings_count, error));
1550 }
1551 return error;
1552}
1553/*
1554 * shared_region_map_np()
1555 *
1556 * This system call is intended for dyld.
1557 *
1558 * dyld uses this to map a shared cache file into a shared region.
1559 * This is usually done only the first time a shared cache is needed.
1560 * Subsequent processes will just use the populated shared region without
1561 * requiring any further setup.
1562 */
1563int
1564_shared_region_map_and_slide(
1565 struct proc *p,
1566 int fd,
1567 uint32_t mappings_count,
1568 struct shared_file_mapping_np *mappings,
1569 uint32_t slide,
1570 user_addr_t slide_start,
1571 user_addr_t slide_size)
1572{
1573 int error;
1574 kern_return_t kr;
1575 struct fileproc *fp;
1576 struct vnode *vp, *root_vp, *scdir_vp;
1577 struct vnode_attr va;
1578 off_t fs;
1579 memory_object_size_t file_size;
1580#if CONFIG_MACF
1581 vm_prot_t maxprot = VM_PROT_ALL;
1582#endif
1583 memory_object_control_t file_control;
1584 struct vm_shared_region *shared_region;
1585 uint32_t i;
1586
1587 SHARED_REGION_TRACE_DEBUG(
1588 ("shared_region: %p [%d(%s)] -> map\n",
1589 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1590 p->p_pid, p->p_comm));
1591
1592 shared_region = NULL;
1593 fp = NULL;
1594 vp = NULL;
1595 scdir_vp = NULL;
1596
1597 /* get file structure from file descriptor */
1598 error = fp_lookup(p, fd, &fp, 0);
1599 if (error) {
1600 SHARED_REGION_TRACE_ERROR(
1601 ("shared_region: %p [%d(%s)] map: "
1602 "fd=%d lookup failed (error=%d)\n",
1603 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1604 p->p_pid, p->p_comm, fd, error));
1605 goto done;
1606 }
1607
1608 /* make sure we're attempting to map a vnode */
1609 if (FILEGLOB_DTYPE(fp->f_fglob) != DTYPE_VNODE) {
1610 SHARED_REGION_TRACE_ERROR(
1611 ("shared_region: %p [%d(%s)] map: "
1612 "fd=%d not a vnode (type=%d)\n",
1613 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1614 p->p_pid, p->p_comm,
1615 fd, FILEGLOB_DTYPE(fp->f_fglob)));
1616 error = EINVAL;
1617 goto done;
1618 }
1619
1620 /* we need at least read permission on the file */
1621 if (! (fp->f_fglob->fg_flag & FREAD)) {
1622 SHARED_REGION_TRACE_ERROR(
1623 ("shared_region: %p [%d(%s)] map: "
1624 "fd=%d not readable\n",
1625 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1626 p->p_pid, p->p_comm, fd));
1627 error = EPERM;
1628 goto done;
1629 }
1630
1631 /* get vnode from file structure */
1632 error = vnode_getwithref((vnode_t) fp->f_fglob->fg_data);
1633 if (error) {
1634 SHARED_REGION_TRACE_ERROR(
1635 ("shared_region: %p [%d(%s)] map: "
1636 "fd=%d getwithref failed (error=%d)\n",
1637 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1638 p->p_pid, p->p_comm, fd, error));
1639 goto done;
1640 }
1641 vp = (struct vnode *) fp->f_fglob->fg_data;
1642
1643 /* make sure the vnode is a regular file */
1644 if (vp->v_type != VREG) {
1645 SHARED_REGION_TRACE_ERROR(
1646 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1647 "not a file (type=%d)\n",
1648 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1649 p->p_pid, p->p_comm,
1650 (void *)VM_KERNEL_ADDRPERM(vp),
1651 vp->v_name, vp->v_type));
1652 error = EINVAL;
1653 goto done;
1654 }
1655
1656#if CONFIG_MACF
1657 /* pass in 0 for the offset argument because AMFI does not need the offset
1658 of the shared cache */
1659 error = mac_file_check_mmap(vfs_context_ucred(vfs_context_current()),
1660 fp->f_fglob, VM_PROT_ALL, MAP_FILE, 0, &maxprot);
1661 if (error) {
1662 goto done;
1663 }
1664#endif /* MAC */
1665
1666 /* make sure vnode is on the process's root volume */
1667 root_vp = p->p_fd->fd_rdir;
1668 if (root_vp == NULL) {
1669 root_vp = rootvnode;
1670 } else {
1671 /*
1672 * Chroot-ed processes can't use the shared_region.
1673 */
1674 error = EINVAL;
1675 goto done;
1676 }
1677
1678 if (vp->v_mount != root_vp->v_mount) {
1679 SHARED_REGION_TRACE_ERROR(
1680 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1681 "not on process's root volume\n",
1682 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1683 p->p_pid, p->p_comm,
1684 (void *)VM_KERNEL_ADDRPERM(vp), vp->v_name));
1685 error = EPERM;
1686 goto done;
1687 }
1688
1689 /* make sure vnode is owned by "root" */
1690 VATTR_INIT(&va);
1691 VATTR_WANTED(&va, va_uid);
1692 error = vnode_getattr(vp, &va, vfs_context_current());
1693 if (error) {
1694 SHARED_REGION_TRACE_ERROR(
1695 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1696 "vnode_getattr(%p) failed (error=%d)\n",
1697 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1698 p->p_pid, p->p_comm,
1699 (void *)VM_KERNEL_ADDRPERM(vp), vp->v_name,
1700 (void *)VM_KERNEL_ADDRPERM(vp), error));
1701 goto done;
1702 }
1703 if (va.va_uid != 0) {
1704 SHARED_REGION_TRACE_ERROR(
1705 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1706 "owned by uid=%d instead of 0\n",
1707 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1708 p->p_pid, p->p_comm,
1709 (void *)VM_KERNEL_ADDRPERM(vp),
1710 vp->v_name, va.va_uid));
1711 error = EPERM;
1712 goto done;
1713 }
1714
1715 if (scdir_enforce) {
1716 /* get vnode for scdir_path */
1717 error = vnode_lookup(scdir_path, 0, &scdir_vp, vfs_context_current());
1718 if (error) {
1719 SHARED_REGION_TRACE_ERROR(
1720 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1721 "vnode_lookup(%s) failed (error=%d)\n",
1722 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1723 p->p_pid, p->p_comm,
1724 (void *)VM_KERNEL_ADDRPERM(vp), vp->v_name,
1725 scdir_path, error));
1726 goto done;
1727 }
1728
1729 /* ensure parent is scdir_vp */
1730 if (vnode_parent(vp) != scdir_vp) {
1731 SHARED_REGION_TRACE_ERROR(
1732 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1733 "shared cache file not in %s\n",
1734 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1735 p->p_pid, p->p_comm,
1736 (void *)VM_KERNEL_ADDRPERM(vp),
1737 vp->v_name, scdir_path));
1738 error = EPERM;
1739 goto done;
1740 }
1741 }
1742
1743 /* get vnode size */
1744 error = vnode_size(vp, &fs, vfs_context_current());
1745 if (error) {
1746 SHARED_REGION_TRACE_ERROR(
1747 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1748 "vnode_size(%p) failed (error=%d)\n",
1749 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1750 p->p_pid, p->p_comm,
1751 (void *)VM_KERNEL_ADDRPERM(vp), vp->v_name,
1752 (void *)VM_KERNEL_ADDRPERM(vp), error));
1753 goto done;
1754 }
1755 file_size = fs;
1756
1757 /* get the file's memory object handle */
1758 file_control = ubc_getobject(vp, UBC_HOLDOBJECT);
1759 if (file_control == MEMORY_OBJECT_CONTROL_NULL) {
1760 SHARED_REGION_TRACE_ERROR(
1761 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1762 "no memory object\n",
1763 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1764 p->p_pid, p->p_comm,
1765 (void *)VM_KERNEL_ADDRPERM(vp), vp->v_name));
1766 error = EINVAL;
1767 goto done;
1768 }
1769
1770 /* check that the mappings are properly covered by code signatures */
1771 if (!cs_system_enforcement()) {
1772 /* code signing is not enforced: no need to check */
1773 } else for (i = 0; i < mappings_count; i++) {
1774 if (mappings[i].sfm_init_prot & VM_PROT_ZF) {
1775 /* zero-filled mapping: not backed by the file */
1776 continue;
1777 }
1778 if (ubc_cs_is_range_codesigned(vp,
1779 mappings[i].sfm_file_offset,
1780 mappings[i].sfm_size)) {
1781 /* this mapping is fully covered by code signatures */
1782 continue;
1783 }
1784 SHARED_REGION_TRACE_ERROR(
1785 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1786 "mapping #%d/%d [0x%llx:0x%llx:0x%llx:0x%x:0x%x] "
1787 "is not code-signed\n",
1788 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1789 p->p_pid, p->p_comm,
1790 (void *)VM_KERNEL_ADDRPERM(vp), vp->v_name,
1791 i, mappings_count,
1792 mappings[i].sfm_address,
1793 mappings[i].sfm_size,
1794 mappings[i].sfm_file_offset,
1795 mappings[i].sfm_max_prot,
1796 mappings[i].sfm_init_prot));
1797 error = EINVAL;
1798 goto done;
1799 }
1800
1801 /* get the process's shared region (setup in vm_map_exec()) */
1802 shared_region = vm_shared_region_trim_and_get(current_task());
1803 if (shared_region == NULL) {
1804 SHARED_REGION_TRACE_ERROR(
1805 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1806 "no shared region\n",
1807 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1808 p->p_pid, p->p_comm,
1809 (void *)VM_KERNEL_ADDRPERM(vp), vp->v_name));
1810 error = EINVAL;
1811 goto done;
1812 }
1813
1814 /* map the file into that shared region's submap */
1815 kr = vm_shared_region_map_file(shared_region,
1816 mappings_count,
1817 mappings,
1818 file_control,
1819 file_size,
1820 (void *) p->p_fd->fd_rdir,
1821 slide,
1822 slide_start,
1823 slide_size);
1824 if (kr != KERN_SUCCESS) {
1825 SHARED_REGION_TRACE_ERROR(
1826 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1827 "vm_shared_region_map_file() failed kr=0x%x\n",
1828 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1829 p->p_pid, p->p_comm,
1830 (void *)VM_KERNEL_ADDRPERM(vp), vp->v_name, kr));
1831 switch (kr) {
1832 case KERN_INVALID_ADDRESS:
1833 error = EFAULT;
1834 break;
1835 case KERN_PROTECTION_FAILURE:
1836 error = EPERM;
1837 break;
1838 case KERN_NO_SPACE:
1839 error = ENOMEM;
1840 break;
1841 case KERN_FAILURE:
1842 case KERN_INVALID_ARGUMENT:
1843 default:
1844 error = EINVAL;
1845 break;
1846 }
1847 goto done;
1848 }
1849
1850 error = 0;
1851
1852 vnode_lock_spin(vp);
1853
1854 vp->v_flag |= VSHARED_DYLD;
1855
1856 vnode_unlock(vp);
1857
1858 /* update the vnode's access time */
1859 if (! (vnode_vfsvisflags(vp) & MNT_NOATIME)) {
1860 VATTR_INIT(&va);
1861 nanotime(&va.va_access_time);
1862 VATTR_SET_ACTIVE(&va, va_access_time);
1863 vnode_setattr(vp, &va, vfs_context_current());
1864 }
1865
1866 if (p->p_flag & P_NOSHLIB) {
1867 /* signal that this process is now using split libraries */
1868 OSBitAndAtomic(~((uint32_t)P_NOSHLIB), &p->p_flag);
1869 }
1870
1871done:
1872 if (vp != NULL) {
1873 /*
1874 * release the vnode...
1875 * ubc_map() still holds it for us in the non-error case
1876 */
1877 (void) vnode_put(vp);
1878 vp = NULL;
1879 }
1880 if (fp != NULL) {
1881 /* release the file descriptor */
1882 fp_drop(p, fd, fp, 0);
1883 fp = NULL;
1884 }
1885 if (scdir_vp != NULL) {
1886 (void)vnode_put(scdir_vp);
1887 scdir_vp = NULL;
1888 }
1889
1890 if (shared_region != NULL) {
1891 vm_shared_region_deallocate(shared_region);
1892 }
1893
1894 SHARED_REGION_TRACE_DEBUG(
1895 ("shared_region: %p [%d(%s)] <- map\n",
1896 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1897 p->p_pid, p->p_comm));
1898
1899 return error;
1900}
1901
1902int
1903shared_region_map_and_slide_np(
1904 struct proc *p,
1905 struct shared_region_map_and_slide_np_args *uap,
1906 __unused int *retvalp)
1907{
1908 struct shared_file_mapping_np *mappings;
1909 unsigned int mappings_count = uap->count;
1910 kern_return_t kr = KERN_SUCCESS;
1911 uint32_t slide = uap->slide;
1912
1913#define SFM_MAX_STACK 8
1914 struct shared_file_mapping_np stack_mappings[SFM_MAX_STACK];
1915
1916 /* Is the process chrooted?? */
1917 if (p->p_fd->fd_rdir != NULL) {
1918 kr = EINVAL;
1919 goto done;
1920 }
1921
1922 if ((kr = vm_shared_region_sliding_valid(slide)) != KERN_SUCCESS) {
1923 if (kr == KERN_INVALID_ARGUMENT) {
1924 /*
1925 * This will happen if we request sliding again
1926 * with the same slide value that was used earlier
1927 * for the very first sliding.
1928 */
1929 kr = KERN_SUCCESS;
1930 }
1931 goto done;
1932 }
1933
1934 if (mappings_count == 0) {
1935 SHARED_REGION_TRACE_INFO(
1936 ("shared_region: %p [%d(%s)] map(): "
1937 "no mappings\n",
1938 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1939 p->p_pid, p->p_comm));
1940 kr = 0; /* no mappings: we're done ! */
1941 goto done;
1942 } else if (mappings_count <= SFM_MAX_STACK) {
1943 mappings = &stack_mappings[0];
1944 } else {
1945 SHARED_REGION_TRACE_ERROR(
1946 ("shared_region: %p [%d(%s)] map(): "
1947 "too many mappings (%d)\n",
1948 (void *)VM_KERNEL_ADDRPERM(current_thread()),
1949 p->p_pid, p->p_comm,
1950 mappings_count));
1951 kr = KERN_FAILURE;
1952 goto done;
1953 }
1954
1955 if ( (kr = shared_region_copyin_mappings(p, uap->mappings, uap->count, mappings))) {
1956 goto done;
1957 }
1958
1959
1960 kr = _shared_region_map_and_slide(p, uap->fd, mappings_count, mappings,
1961 slide,
1962 uap->slide_start, uap->slide_size);
1963 if (kr != KERN_SUCCESS) {
1964 return kr;
1965 }
1966
1967done:
1968 return kr;
1969}
1970
1971/* sysctl overflow room */
1972
1973SYSCTL_INT (_vm, OID_AUTO, pagesize, CTLFLAG_RD | CTLFLAG_LOCKED,
1974 (int *) &page_size, 0, "vm page size");
1975
1976/* vm_page_free_target is provided as a makeshift solution for applications that want to
1977 allocate buffer space, possibly purgeable memory, but not cause inactive pages to be
1978 reclaimed. It allows the app to calculate how much memory is free outside the free target. */
1979extern unsigned int vm_page_free_target;
1980SYSCTL_INT(_vm, OID_AUTO, vm_page_free_target, CTLFLAG_RD | CTLFLAG_LOCKED,
1981 &vm_page_free_target, 0, "Pageout daemon free target");
1982
1983SYSCTL_INT(_vm, OID_AUTO, memory_pressure, CTLFLAG_RD | CTLFLAG_LOCKED,
1984 &vm_pageout_state.vm_memory_pressure, 0, "Memory pressure indicator");
1985
1986static int
1987vm_ctl_page_free_wanted SYSCTL_HANDLER_ARGS
1988{
1989#pragma unused(oidp, arg1, arg2)
1990 unsigned int page_free_wanted;
1991
1992 page_free_wanted = mach_vm_ctl_page_free_wanted();
1993 return SYSCTL_OUT(req, &page_free_wanted, sizeof (page_free_wanted));
1994}
1995SYSCTL_PROC(_vm, OID_AUTO, page_free_wanted,
1996 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
1997 0, 0, vm_ctl_page_free_wanted, "I", "");
1998
1999extern unsigned int vm_page_purgeable_count;
2000SYSCTL_INT(_vm, OID_AUTO, page_purgeable_count, CTLFLAG_RD | CTLFLAG_LOCKED,
2001 &vm_page_purgeable_count, 0, "Purgeable page count");
2002
2003extern unsigned int vm_page_purgeable_wired_count;
2004SYSCTL_INT(_vm, OID_AUTO, page_purgeable_wired_count, CTLFLAG_RD | CTLFLAG_LOCKED,
2005 &vm_page_purgeable_wired_count, 0, "Wired purgeable page count");
2006
2007#if DEVELOPMENT || DEBUG
2008extern uint64_t get_pages_grabbed_count(void);
2009
2010static int
2011pages_grabbed SYSCTL_HANDLER_ARGS
2012{
2013#pragma unused(arg1, arg2, oidp)
2014 uint64_t value = get_pages_grabbed_count();
2015 return SYSCTL_OUT(req, &value, sizeof(value));
2016}
2017
2018SYSCTL_PROC(_vm, OID_AUTO, pages_grabbed, CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
2019 0, 0, &pages_grabbed, "QU", "Total pages grabbed");
2020SYSCTL_ULONG(_vm, OID_AUTO, pages_freed, CTLFLAG_RD | CTLFLAG_LOCKED,
2021 &vm_pageout_vminfo.vm_page_pages_freed, "Total pages freed");
2022
2023SYSCTL_INT(_vm, OID_AUTO, pageout_purged_objects, CTLFLAG_RD | CTLFLAG_LOCKED,
2024 &vm_pageout_debug.vm_pageout_purged_objects, 0, "System purged object count");
2025SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_busy, CTLFLAG_RD | CTLFLAG_LOCKED,
2026 &vm_pageout_debug.vm_pageout_cleaned_busy, 0, "Cleaned pages busy (deactivated)");
2027SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_nolock, CTLFLAG_RD | CTLFLAG_LOCKED,
2028 &vm_pageout_debug.vm_pageout_cleaned_nolock, 0, "Cleaned pages no-lock (deactivated)");
2029
2030SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_volatile_reactivated, CTLFLAG_RD | CTLFLAG_LOCKED,
2031 &vm_pageout_debug.vm_pageout_cleaned_volatile_reactivated, 0, "Cleaned pages volatile reactivated");
2032SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_fault_reactivated, CTLFLAG_RD | CTLFLAG_LOCKED,
2033 &vm_pageout_debug.vm_pageout_cleaned_fault_reactivated, 0, "Cleaned pages fault reactivated");
2034SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_reactivated, CTLFLAG_RD | CTLFLAG_LOCKED,
2035 &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 */
2036SYSCTL_ULONG(_vm, OID_AUTO, pageout_cleaned, CTLFLAG_RD | CTLFLAG_LOCKED,
2037 &vm_pageout_vminfo.vm_pageout_freed_cleaned, "Cleaned pages freed");
2038SYSCTL_UINT(_vm, OID_AUTO, pageout_cleaned_reference_reactivated, CTLFLAG_RD | CTLFLAG_LOCKED,
2039 &vm_pageout_debug.vm_pageout_cleaned_reference_reactivated, 0, "Cleaned pages reference reactivated");
2040SYSCTL_UINT(_vm, OID_AUTO, pageout_enqueued_cleaned, CTLFLAG_RD | CTLFLAG_LOCKED,
2041 &vm_pageout_debug.vm_pageout_enqueued_cleaned, 0, ""); /* sum of next two */
2042#endif
2043
2044extern int madvise_free_debug;
2045SYSCTL_INT(_vm, OID_AUTO, madvise_free_debug, CTLFLAG_RW | CTLFLAG_LOCKED,
2046 &madvise_free_debug, 0, "zero-fill on madvise(MADV_FREE*)");
2047
2048SYSCTL_INT(_vm, OID_AUTO, page_reusable_count, CTLFLAG_RD | CTLFLAG_LOCKED,
2049 &vm_page_stats_reusable.reusable_count, 0, "Reusable page count");
2050SYSCTL_QUAD(_vm, OID_AUTO, reusable_success, CTLFLAG_RD | CTLFLAG_LOCKED,
2051 &vm_page_stats_reusable.reusable_pages_success, "");
2052SYSCTL_QUAD(_vm, OID_AUTO, reusable_failure, CTLFLAG_RD | CTLFLAG_LOCKED,
2053 &vm_page_stats_reusable.reusable_pages_failure, "");
2054SYSCTL_QUAD(_vm, OID_AUTO, reusable_pages_shared, CTLFLAG_RD | CTLFLAG_LOCKED,
2055 &vm_page_stats_reusable.reusable_pages_shared, "");
2056SYSCTL_QUAD(_vm, OID_AUTO, all_reusable_calls, CTLFLAG_RD | CTLFLAG_LOCKED,
2057 &vm_page_stats_reusable.all_reusable_calls, "");
2058SYSCTL_QUAD(_vm, OID_AUTO, partial_reusable_calls, CTLFLAG_RD | CTLFLAG_LOCKED,
2059 &vm_page_stats_reusable.partial_reusable_calls, "");
2060SYSCTL_QUAD(_vm, OID_AUTO, reuse_success, CTLFLAG_RD | CTLFLAG_LOCKED,
2061 &vm_page_stats_reusable.reuse_pages_success, "");
2062SYSCTL_QUAD(_vm, OID_AUTO, reuse_failure, CTLFLAG_RD | CTLFLAG_LOCKED,
2063 &vm_page_stats_reusable.reuse_pages_failure, "");
2064SYSCTL_QUAD(_vm, OID_AUTO, all_reuse_calls, CTLFLAG_RD | CTLFLAG_LOCKED,
2065 &vm_page_stats_reusable.all_reuse_calls, "");
2066SYSCTL_QUAD(_vm, OID_AUTO, partial_reuse_calls, CTLFLAG_RD | CTLFLAG_LOCKED,
2067 &vm_page_stats_reusable.partial_reuse_calls, "");
2068SYSCTL_QUAD(_vm, OID_AUTO, can_reuse_success, CTLFLAG_RD | CTLFLAG_LOCKED,
2069 &vm_page_stats_reusable.can_reuse_success, "");
2070SYSCTL_QUAD(_vm, OID_AUTO, can_reuse_failure, CTLFLAG_RD | CTLFLAG_LOCKED,
2071 &vm_page_stats_reusable.can_reuse_failure, "");
2072SYSCTL_QUAD(_vm, OID_AUTO, reusable_reclaimed, CTLFLAG_RD | CTLFLAG_LOCKED,
2073 &vm_page_stats_reusable.reusable_reclaimed, "");
2074SYSCTL_QUAD(_vm, OID_AUTO, reusable_nonwritable, CTLFLAG_RD | CTLFLAG_LOCKED,
2075 &vm_page_stats_reusable.reusable_nonwritable, "");
2076SYSCTL_QUAD(_vm, OID_AUTO, reusable_shared, CTLFLAG_RD | CTLFLAG_LOCKED,
2077 &vm_page_stats_reusable.reusable_shared, "");
2078SYSCTL_QUAD(_vm, OID_AUTO, free_shared, CTLFLAG_RD | CTLFLAG_LOCKED,
2079 &vm_page_stats_reusable.free_shared, "");
2080
2081
2082extern unsigned int vm_page_free_count, vm_page_speculative_count;
2083SYSCTL_UINT(_vm, OID_AUTO, page_free_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_free_count, 0, "");
2084SYSCTL_UINT(_vm, OID_AUTO, page_speculative_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_speculative_count, 0, "");
2085
2086extern unsigned int vm_page_cleaned_count;
2087SYSCTL_UINT(_vm, OID_AUTO, page_cleaned_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_cleaned_count, 0, "Cleaned queue size");
2088
2089extern unsigned int vm_page_pageable_internal_count, vm_page_pageable_external_count;
2090SYSCTL_UINT(_vm, OID_AUTO, page_pageable_internal_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_pageable_internal_count, 0, "");
2091SYSCTL_UINT(_vm, OID_AUTO, page_pageable_external_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_pageable_external_count, 0, "");
2092
2093/* pageout counts */
2094SYSCTL_UINT(_vm, OID_AUTO, pageout_inactive_clean, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_state.vm_pageout_inactive_clean, 0, "");
2095SYSCTL_UINT(_vm, OID_AUTO, pageout_inactive_used, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_state.vm_pageout_inactive_used, 0, "");
2096
2097SYSCTL_ULONG(_vm, OID_AUTO, pageout_inactive_dirty_internal, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_inactive_dirty_internal, "");
2098SYSCTL_ULONG(_vm, OID_AUTO, pageout_inactive_dirty_external, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_inactive_dirty_external, "");
2099SYSCTL_ULONG(_vm, OID_AUTO, pageout_speculative_clean, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_freed_speculative, "");
2100SYSCTL_ULONG(_vm, OID_AUTO, pageout_freed_external, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_freed_external, "");
2101SYSCTL_ULONG(_vm, OID_AUTO, pageout_freed_speculative, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_freed_speculative, "");
2102SYSCTL_ULONG(_vm, OID_AUTO, pageout_freed_cleaned, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_freed_cleaned, "");
2103
2104
2105/* counts of pages prefaulted when entering a memory object */
2106extern int64_t vm_prefault_nb_pages, vm_prefault_nb_bailout;
2107SYSCTL_QUAD(_vm, OID_AUTO, prefault_nb_pages, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_prefault_nb_pages, "");
2108SYSCTL_QUAD(_vm, OID_AUTO, prefault_nb_bailout, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_prefault_nb_bailout, "");
2109
2110#if defined (__x86_64__)
2111extern unsigned int vm_clump_promote_threshold;
2112SYSCTL_UINT(_vm, OID_AUTO, vm_clump_promote_threshold, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_clump_promote_threshold, 0, "clump size threshold for promotes");
2113#if DEVELOPMENT || DEBUG
2114extern unsigned long vm_clump_stats[];
2115SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats1, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[1], "free page allocations from clump of 1 page");
2116SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats2, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[2], "free page allocations from clump of 2 pages");
2117SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats3, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[3], "free page allocations from clump of 3 pages");
2118SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats4, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[4], "free page allocations from clump of 4 pages");
2119SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats5, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[5], "free page allocations from clump of 5 pages");
2120SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats6, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[6], "free page allocations from clump of 6 pages");
2121SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats7, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[7], "free page allocations from clump of 7 pages");
2122SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats8, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[8], "free page allocations from clump of 8 pages");
2123SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats9, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[9], "free page allocations from clump of 9 pages");
2124SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats10, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[10], "free page allocations from clump of 10 pages");
2125SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats11, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[11], "free page allocations from clump of 11 pages");
2126SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats12, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[12], "free page allocations from clump of 12 pages");
2127SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats13, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[13], "free page allocations from clump of 13 pages");
2128SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats14, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[14], "free page allocations from clump of 14 pages");
2129SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats15, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[15], "free page allocations from clump of 15 pages");
2130SYSCTL_LONG(_vm, OID_AUTO, vm_clump_stats16, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_stats[16], "free page allocations from clump of 16 pages");
2131extern unsigned long vm_clump_allocs, vm_clump_inserts, vm_clump_inrange, vm_clump_promotes;
2132SYSCTL_LONG(_vm, OID_AUTO, vm_clump_alloc, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_allocs, "free page allocations");
2133SYSCTL_LONG(_vm, OID_AUTO, vm_clump_inserts, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_inserts, "free page insertions");
2134SYSCTL_LONG(_vm, OID_AUTO, vm_clump_inrange, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_inrange, "free page insertions that are part of vm_pages");
2135SYSCTL_LONG(_vm, OID_AUTO, vm_clump_promotes, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_clump_promotes, "pages promoted to head");
2136#endif /* if DEVELOPMENT || DEBUG */
2137#endif /* #if defined (__x86_64__) */
2138
2139#if CONFIG_SECLUDED_MEMORY
2140
2141SYSCTL_UINT(_vm, OID_AUTO, num_tasks_can_use_secluded_mem, CTLFLAG_RD | CTLFLAG_LOCKED, &num_tasks_can_use_secluded_mem, 0, "");
2142extern unsigned int vm_page_secluded_target;
2143extern unsigned int vm_page_secluded_count;
2144extern unsigned int vm_page_secluded_count_free;
2145extern unsigned int vm_page_secluded_count_inuse;
2146SYSCTL_UINT(_vm, OID_AUTO, page_secluded_target, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded_target, 0, "");
2147SYSCTL_UINT(_vm, OID_AUTO, page_secluded_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded_count, 0, "");
2148SYSCTL_UINT(_vm, OID_AUTO, page_secluded_count_free, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded_count_free, 0, "");
2149SYSCTL_UINT(_vm, OID_AUTO, page_secluded_count_inuse, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded_count_inuse, 0, "");
2150
2151extern struct vm_page_secluded_data vm_page_secluded;
2152SYSCTL_UINT(_vm, OID_AUTO, page_secluded_eligible, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.eligible_for_secluded, 0, "");
2153SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_success_free, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_success_free, 0, "");
2154SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_success_other, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_success_other, 0, "");
2155SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_failure_locked, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_failure_locked, 0, "");
2156SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_failure_state, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_failure_state, 0, "");
2157SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_failure_dirty, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_failure_dirty, 0, "");
2158SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_for_iokit, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_for_iokit, 0, "");
2159SYSCTL_UINT(_vm, OID_AUTO, page_secluded_grab_for_iokit_success, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_secluded.grab_for_iokit_success, 0, "");
2160
2161#endif /* CONFIG_SECLUDED_MEMORY */
2162
2163#include <kern/thread.h>
2164#include <sys/user.h>
2165
2166void vm_pageout_io_throttle(void);
2167
2168void vm_pageout_io_throttle(void) {
2169 struct uthread *uthread = get_bsdthread_info(current_thread());
2170
2171 /*
2172 * thread is marked as a low priority I/O type
2173 * and the I/O we issued while in this cleaning operation
2174 * collided with normal I/O operations... we'll
2175 * delay in order to mitigate the impact of this
2176 * task on the normal operation of the system
2177 */
2178
2179 if (uthread->uu_lowpri_window) {
2180 throttle_lowpri_io(1);
2181 }
2182
2183}
2184
2185int
2186vm_pressure_monitor(
2187 __unused struct proc *p,
2188 struct vm_pressure_monitor_args *uap,
2189 int *retval)
2190{
2191 kern_return_t kr;
2192 uint32_t pages_reclaimed;
2193 uint32_t pages_wanted;
2194
2195 kr = mach_vm_pressure_monitor(
2196 (boolean_t) uap->wait_for_pressure,
2197 uap->nsecs_monitored,
2198 (uap->pages_reclaimed) ? &pages_reclaimed : NULL,
2199 &pages_wanted);
2200
2201 switch (kr) {
2202 case KERN_SUCCESS:
2203 break;
2204 case KERN_ABORTED:
2205 return EINTR;
2206 default:
2207 return EINVAL;
2208 }
2209
2210 if (uap->pages_reclaimed) {
2211 if (copyout((void *)&pages_reclaimed,
2212 uap->pages_reclaimed,
2213 sizeof (pages_reclaimed)) != 0) {
2214 return EFAULT;
2215 }
2216 }
2217
2218 *retval = (int) pages_wanted;
2219 return 0;
2220}
2221
2222int
2223kas_info(struct proc *p,
2224 struct kas_info_args *uap,
2225 int *retval __unused)
2226{
2227#ifdef SECURE_KERNEL
2228 (void)p;
2229 (void)uap;
2230 return ENOTSUP;
2231#else /* !SECURE_KERNEL */
2232 int selector = uap->selector;
2233 user_addr_t valuep = uap->value;
2234 user_addr_t sizep = uap->size;
2235 user_size_t size;
2236 int error;
2237
2238 if (!kauth_cred_issuser(kauth_cred_get())) {
2239 return EPERM;
2240 }
2241
2242#if CONFIG_MACF
2243 error = mac_system_check_kas_info(kauth_cred_get(), selector);
2244 if (error) {
2245 return error;
2246 }
2247#endif
2248
2249 if (IS_64BIT_PROCESS(p)) {
2250 user64_size_t size64;
2251 error = copyin(sizep, &size64, sizeof(size64));
2252 size = (user_size_t)size64;
2253 } else {
2254 user32_size_t size32;
2255 error = copyin(sizep, &size32, sizeof(size32));
2256 size = (user_size_t)size32;
2257 }
2258 if (error) {
2259 return error;
2260 }
2261
2262 switch (selector) {
2263 case KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR:
2264 {
2265 uint64_t slide = vm_kernel_slide;
2266
2267 if (sizeof(slide) != size) {
2268 return EINVAL;
2269 }
2270
2271 if (IS_64BIT_PROCESS(p)) {
2272 user64_size_t size64 = (user64_size_t)size;
2273 error = copyout(&size64, sizep, sizeof(size64));
2274 } else {
2275 user32_size_t size32 = (user32_size_t)size;
2276 error = copyout(&size32, sizep, sizeof(size32));
2277 }
2278 if (error) {
2279 return error;
2280 }
2281
2282 error = copyout(&slide, valuep, sizeof(slide));
2283 if (error) {
2284 return error;
2285 }
2286 }
2287 break;
2288 default:
2289 return EINVAL;
2290 }
2291
2292 return 0;
2293#endif /* !SECURE_KERNEL */
2294}
2295
2296
2297#pragma clang diagnostic push
2298#pragma clang diagnostic ignored "-Wcast-qual"
2299#pragma clang diagnostic ignored "-Wunused-function"
2300
2301static void asserts() {
2302 static_assert(sizeof(vm_min_kernel_address) == sizeof(unsigned long));
2303 static_assert(sizeof(vm_max_kernel_address) == sizeof(unsigned long));
2304}
2305
2306SYSCTL_ULONG(_vm, OID_AUTO, vm_min_kernel_address, CTLFLAG_RD, (unsigned long *) &vm_min_kernel_address, "");
2307SYSCTL_ULONG(_vm, OID_AUTO, vm_max_kernel_address, CTLFLAG_RD, (unsigned long *) &vm_max_kernel_address, "");
2308#pragma clang diagnostic pop
2309
2310extern uint32_t vm_page_pages;
2311SYSCTL_UINT(_vm, OID_AUTO, pages, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_pages, 0, "");
2312
2313extern uint32_t vm_page_busy_absent_skipped;
2314SYSCTL_UINT(_vm, OID_AUTO, page_busy_absent_skipped, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_busy_absent_skipped, 0, "");
2315
2316#if (__arm__ || __arm64__) && (DEVELOPMENT || DEBUG)
2317extern int vm_footprint_suspend_allowed;
2318SYSCTL_INT(_vm, OID_AUTO, footprint_suspend_allowed, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_footprint_suspend_allowed, 0, "");
2319
2320extern void pmap_footprint_suspend(vm_map_t map, boolean_t suspend);
2321static int
2322sysctl_vm_footprint_suspend SYSCTL_HANDLER_ARGS
2323{
2324#pragma unused(oidp, arg1, arg2)
2325 int error = 0;
2326 int new_value;
2327
2328 if (req->newptr == USER_ADDR_NULL) {
2329 return 0;
2330 }
2331 error = SYSCTL_IN(req, &new_value, sizeof(int));
2332 if (error) {
2333 return error;
2334 }
2335 if (!vm_footprint_suspend_allowed) {
2336 if (new_value != 0) {
2337 /* suspends are not allowed... */
2338 return 0;
2339 }
2340 /* ... but let resumes proceed */
2341 }
2342 DTRACE_VM2(footprint_suspend,
2343 vm_map_t, current_map(),
2344 int, new_value);
2345
2346 pmap_footprint_suspend(current_map(), new_value);
2347
2348 return 0;
2349}
2350SYSCTL_PROC(_vm, OID_AUTO, footprint_suspend,
2351 CTLTYPE_INT|CTLFLAG_WR|CTLFLAG_ANYBODY|CTLFLAG_LOCKED|CTLFLAG_MASKED,
2352 0, 0, &sysctl_vm_footprint_suspend, "I", "");
2353#endif /* (__arm__ || __arm64__) && (DEVELOPMENT || DEBUG) */
2354
2355extern uint64_t vm_map_corpse_footprint_count;
2356extern uint64_t vm_map_corpse_footprint_size_avg;
2357extern uint64_t vm_map_corpse_footprint_size_max;
2358extern uint64_t vm_map_corpse_footprint_full;
2359extern uint64_t vm_map_corpse_footprint_no_buf;
2360SYSCTL_QUAD(_vm, OID_AUTO, corpse_footprint_count,
2361 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_corpse_footprint_count, "");
2362SYSCTL_QUAD(_vm, OID_AUTO, corpse_footprint_size_avg,
2363 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_corpse_footprint_size_avg, "");
2364SYSCTL_QUAD(_vm, OID_AUTO, corpse_footprint_size_max,
2365 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_corpse_footprint_size_max, "");
2366SYSCTL_QUAD(_vm, OID_AUTO, corpse_footprint_full,
2367 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_corpse_footprint_full, "");
2368SYSCTL_QUAD(_vm, OID_AUTO, corpse_footprint_no_buf,
2369 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_corpse_footprint_no_buf, "");
2370
2371#if PMAP_CS
2372extern uint64_t vm_cs_defer_to_pmap_cs;
2373extern uint64_t vm_cs_defer_to_pmap_cs_not;
2374SYSCTL_QUAD(_vm, OID_AUTO, cs_defer_to_pmap_cs,
2375 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_cs_defer_to_pmap_cs, "");
2376SYSCTL_QUAD(_vm, OID_AUTO, cs_defer_to_pmap_cs_not,
2377 CTLFLAG_RD | CTLFLAG_LOCKED, &vm_cs_defer_to_pmap_cs_not, "");
2378#endif /* PMAP_CS */
2379
2380extern uint64_t shared_region_pager_copied;
2381extern uint64_t shared_region_pager_slid;
2382extern uint64_t shared_region_pager_slid_error;
2383extern uint64_t shared_region_pager_reclaimed;
2384SYSCTL_QUAD(_vm, OID_AUTO, shared_region_pager_copied,
2385 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pager_copied, "");
2386SYSCTL_QUAD(_vm, OID_AUTO, shared_region_pager_slid,
2387 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pager_slid, "");
2388SYSCTL_QUAD(_vm, OID_AUTO, shared_region_pager_slid_error,
2389 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pager_slid_error, "");
2390SYSCTL_QUAD(_vm, OID_AUTO, shared_region_pager_reclaimed,
2391 CTLFLAG_RD | CTLFLAG_LOCKED, &shared_region_pager_reclaimed, "");
2392
2393#if MACH_ASSERT
2394extern int pmap_ledgers_panic_leeway;
2395SYSCTL_INT(_vm, OID_AUTO, pmap_ledgers_panic_leeway, CTLFLAG_RW | CTLFLAG_LOCKED, &pmap_ledgers_panic_leeway, 0, "");
2396#endif /* MACH_ASSERT */
2397