]> git.saurik.com Git - apple/xnu.git/blame - bsd/vm/vm_unix.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / vm / vm_unix.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 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.
8f6c56a5 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.
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
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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 */
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 */
9bccf70c 40
1c79356b
A
41#include <meta_features.h>
42
43#include <kern/task.h>
44#include <kern/thread.h>
45#include <kern/debug.h>
46#include <kern/lock.h>
91447636 47#include <mach/mach_traps.h>
2d21ac55
A
48#include <mach/port.h>
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>
1c79356b 56
91447636 57#include <sys/file_internal.h>
1c79356b
A
58#include <sys/param.h>
59#include <sys/systm.h>
60#include <sys/dir.h>
61#include <sys/namei.h>
91447636
A
62#include <sys/proc_internal.h>
63#include <sys/kauth.h>
1c79356b
A
64#include <sys/vm.h>
65#include <sys/file.h>
91447636 66#include <sys/vnode_internal.h>
1c79356b
A
67#include <sys/mount.h>
68#include <sys/trace.h>
69#include <sys/kernel.h>
91447636
A
70#include <sys/ubc_internal.h>
71#include <sys/user.h>
0c530ab8 72#include <sys/syslog.h>
9bccf70c 73#include <sys/stat.h>
91447636
A
74#include <sys/sysproto.h>
75#include <sys/mman.h>
0c530ab8 76#include <sys/sysctl.h>
1c79356b 77
b0d623f7 78#include <security/audit/audit.h>
e5568f75
A
79#include <bsm/audit_kevents.h>
80
1c79356b 81#include <kern/kalloc.h>
1c79356b
A
82#include <vm/vm_map.h>
83#include <vm/vm_kern.h>
b0d623f7 84#include <vm/vm_pageout.h>
1c79356b
A
85
86#include <machine/spl.h>
9bccf70c 87
2d21ac55
A
88#include <mach/shared_region.h>
89#include <vm/vm_shared_region.h>
9bccf70c 90
91447636 91#include <vm/vm_protos.h>
9bccf70c 92
2d21ac55
A
93/*
94 * Sysctl's related to data/stack execution. See osfmk/vm/vm_map.c
95 */
96
4a3eedf9 97#ifndef SECURE_KERNEL
2d21ac55
A
98extern int allow_stack_exec, allow_data_exec;
99
100SYSCTL_INT(_vm, OID_AUTO, allow_stack_exec, CTLFLAG_RW, &allow_stack_exec, 0, "");
101SYSCTL_INT(_vm, OID_AUTO, allow_data_exec, CTLFLAG_RW, &allow_data_exec, 0, "");
4a3eedf9 102#endif /* !SECURE_KERNEL */
2d21ac55 103
2d21ac55
A
104static const char *prot_values[] = {
105 "none",
106 "read-only",
107 "write-only",
108 "read-write",
109 "execute-only",
110 "read-execute",
111 "write-execute",
112 "read-write-execute"
113};
114
0c530ab8 115void
2d21ac55 116log_stack_execution_failure(addr64_t vaddr, vm_prot_t prot)
0c530ab8 117{
2d21ac55
A
118 printf("Data/Stack execution not permitted: %s[pid %d] at virtual address 0x%qx, protections were %s\n",
119 current_proc()->p_comm, current_proc()->p_pid, vaddr, prot_values[prot & VM_PROT_ALL]);
0c530ab8
A
120}
121
b0d623f7
A
122int shared_region_unnest_logging = 1;
123
124SYSCTL_INT(_vm, OID_AUTO, shared_region_unnest_logging, CTLFLAG_RW,
125 &shared_region_unnest_logging, 0, "");
126
127int vm_shared_region_unnest_log_interval = 10;
128int shared_region_unnest_log_count_threshold = 5;
129
130/* These log rate throttling state variables aren't thread safe, but
131 * are sufficient unto the task.
132 */
133static int64_t last_unnest_log_time = 0;
134static int shared_region_unnest_log_count = 0;
135
136void log_unnest_badness(vm_map_t m, vm_map_offset_t s, vm_map_offset_t e) {
137 struct timeval tv;
138 const char *pcommstr;
139
140 if (shared_region_unnest_logging == 0)
141 return;
142
143 if (shared_region_unnest_logging == 1) {
144 microtime(&tv);
145 if ((tv.tv_sec - last_unnest_log_time) < vm_shared_region_unnest_log_interval) {
146 if (shared_region_unnest_log_count++ > shared_region_unnest_log_count_threshold)
147 return;
148 }
149 else {
150 last_unnest_log_time = tv.tv_sec;
151 shared_region_unnest_log_count = 0;
152 }
153 }
154
155 pcommstr = current_proc()->p_comm;
156
157 printf("%s (map: %p) triggered DYLD shared region unnest for map: %p, region 0x%qx->0x%qx. While not abnormal for debuggers, this increases system memory footprint until the target exits.\n", current_proc()->p_comm, get_task_map(current_proc()->task), m, (uint64_t)s, (uint64_t)e);
158}
1c79356b 159
91447636
A
160int
161useracc(
162 user_addr_t addr,
163 user_size_t len,
164 int prot)
1c79356b
A
165{
166 return (vm_map_check_protection(
167 current_map(),
91447636 168 vm_map_trunc_page(addr), vm_map_round_page(addr+len),
1c79356b
A
169 prot == B_READ ? VM_PROT_READ : VM_PROT_WRITE));
170}
171
91447636
A
172int
173vslock(
174 user_addr_t addr,
175 user_size_t len)
1c79356b 176{
91447636
A
177 kern_return_t kret;
178 kret = vm_map_wire(current_map(), vm_map_trunc_page(addr),
179 vm_map_round_page(addr+len),
1c79356b 180 VM_PROT_READ | VM_PROT_WRITE ,FALSE);
0b4e3aa0
A
181
182 switch (kret) {
183 case KERN_SUCCESS:
184 return (0);
185 case KERN_INVALID_ADDRESS:
186 case KERN_NO_SPACE:
187 return (ENOMEM);
188 case KERN_PROTECTION_FAILURE:
189 return (EACCES);
190 default:
191 return (EINVAL);
192 }
1c79356b
A
193}
194
91447636
A
195int
196vsunlock(
197 user_addr_t addr,
198 user_size_t len,
199 __unused int dirtied)
1c79356b 200{
1c79356b 201#if FIXME /* [ */
91447636 202 pmap_t pmap;
1c79356b 203 vm_page_t pg;
91447636
A
204 vm_map_offset_t vaddr;
205 ppnum_t paddr;
1c79356b 206#endif /* FIXME ] */
0b4e3aa0 207 kern_return_t kret;
1c79356b
A
208
209#if FIXME /* [ */
210 if (dirtied) {
211 pmap = get_task_pmap(current_task());
91447636
A
212 for (vaddr = vm_map_trunc_page(addr);
213 vaddr < vm_map_round_page(addr+len);
1c79356b
A
214 vaddr += PAGE_SIZE) {
215 paddr = pmap_extract(pmap, vaddr);
216 pg = PHYS_TO_VM_PAGE(paddr);
217 vm_page_set_modified(pg);
218 }
219 }
220#endif /* FIXME ] */
221#ifdef lint
222 dirtied++;
223#endif /* lint */
91447636
A
224 kret = vm_map_unwire(current_map(), vm_map_trunc_page(addr),
225 vm_map_round_page(addr+len), FALSE);
0b4e3aa0
A
226 switch (kret) {
227 case KERN_SUCCESS:
228 return (0);
229 case KERN_INVALID_ADDRESS:
230 case KERN_NO_SPACE:
231 return (ENOMEM);
232 case KERN_PROTECTION_FAILURE:
233 return (EACCES);
234 default:
235 return (EINVAL);
236 }
1c79356b
A
237}
238
91447636
A
239int
240subyte(
241 user_addr_t addr,
242 int byte)
1c79356b
A
243{
244 char character;
245
246 character = (char)byte;
247 return (copyout((void *)&(character), addr, sizeof(char)) == 0 ? 0 : -1);
248}
249
91447636
A
250int
251suibyte(
252 user_addr_t addr,
253 int byte)
1c79356b
A
254{
255 char character;
256
257 character = (char)byte;
91447636 258 return (copyout((void *)&(character), addr, sizeof(char)) == 0 ? 0 : -1);
1c79356b
A
259}
260
91447636 261int fubyte(user_addr_t addr)
1c79356b
A
262{
263 unsigned char byte;
264
265 if (copyin(addr, (void *) &byte, sizeof(char)))
266 return(-1);
267 return(byte);
268}
269
91447636 270int fuibyte(user_addr_t addr)
1c79356b
A
271{
272 unsigned char byte;
273
274 if (copyin(addr, (void *) &(byte), sizeof(char)))
275 return(-1);
276 return(byte);
277}
278
91447636
A
279int
280suword(
281 user_addr_t addr,
282 long word)
1c79356b
A
283{
284 return (copyout((void *) &word, addr, sizeof(int)) == 0 ? 0 : -1);
285}
286
91447636 287long fuword(user_addr_t addr)
1c79356b 288{
b0d623f7 289 long word = 0;
1c79356b
A
290
291 if (copyin(addr, (void *) &word, sizeof(int)))
292 return(-1);
293 return(word);
294}
295
296/* suiword and fuiword are the same as suword and fuword, respectively */
297
91447636
A
298int
299suiword(
300 user_addr_t addr,
301 long word)
1c79356b
A
302{
303 return (copyout((void *) &word, addr, sizeof(int)) == 0 ? 0 : -1);
304}
305
91447636 306long fuiword(user_addr_t addr)
1c79356b 307{
b0d623f7 308 long word = 0;
1c79356b
A
309
310 if (copyin(addr, (void *) &word, sizeof(int)))
311 return(-1);
312 return(word);
313}
91447636
A
314
315/*
316 * With a 32-bit kernel and mixed 32/64-bit user tasks, this interface allows the
317 * fetching and setting of process-sized size_t and pointer values.
318 */
319int
320sulong(user_addr_t addr, int64_t word)
321{
322
323 if (IS_64BIT_PROCESS(current_proc())) {
324 return(copyout((void *)&word, addr, sizeof(word)) == 0 ? 0 : -1);
325 } else {
326 return(suiword(addr, (long)word));
327 }
328}
329
330int64_t
331fulong(user_addr_t addr)
332{
333 int64_t longword;
334
335 if (IS_64BIT_PROCESS(current_proc())) {
336 if (copyin(addr, (void *)&longword, sizeof(longword)) != 0)
337 return(-1);
338 return(longword);
339 } else {
340 return((int64_t)fuiword(addr));
341 }
342}
1c79356b
A
343
344int
91447636
A
345suulong(user_addr_t addr, uint64_t uword)
346{
347
348 if (IS_64BIT_PROCESS(current_proc())) {
349 return(copyout((void *)&uword, addr, sizeof(uword)) == 0 ? 0 : -1);
350 } else {
b0d623f7 351 return(suiword(addr, (uint32_t)uword));
91447636
A
352 }
353}
354
355uint64_t
356fuulong(user_addr_t addr)
1c79356b 357{
91447636
A
358 uint64_t ulongword;
359
360 if (IS_64BIT_PROCESS(current_proc())) {
361 if (copyin(addr, (void *)&ulongword, sizeof(ulongword)) != 0)
362 return(-1ULL);
363 return(ulongword);
364 } else {
365 return((uint64_t)fuiword(addr));
366 }
367}
368
369int
2d21ac55 370swapon(__unused proc_t procp, __unused struct swapon_args *uap, __unused int *retval)
91447636
A
371{
372 return(ENOTSUP);
1c79356b
A
373}
374
b0d623f7
A
375/*
376 * pid_for_task
377 *
378 * Find the BSD process ID for the Mach task associated with the given Mach port
379 * name
380 *
381 * Parameters: args User argument descriptor (see below)
382 *
383 * Indirect parameters: args->t Mach port name
384 * args->pid Process ID (returned value; see below)
385 *
386 * Returns: KERL_SUCCESS Success
387 * KERN_FAILURE Not success
388 *
389 * Implicit returns: args->pid Process ID
390 *
391 */
1c79356b 392kern_return_t
91447636
A
393pid_for_task(
394 struct pid_for_task_args *args)
1c79356b 395{
91447636
A
396 mach_port_name_t t = args->t;
397 user_addr_t pid_addr = args->pid;
2d21ac55 398 proc_t p;
1c79356b 399 task_t t1;
1c79356b 400 int pid = -1;
0b4e3aa0 401 kern_return_t err = KERN_SUCCESS;
1c79356b 402
e5568f75
A
403 AUDIT_MACH_SYSCALL_ENTER(AUE_PIDFORTASK);
404 AUDIT_ARG(mach_port1, t);
405
1c79356b
A
406 t1 = port_name_to_task(t);
407
408 if (t1 == TASK_NULL) {
409 err = KERN_FAILURE;
0b4e3aa0 410 goto pftout;
1c79356b
A
411 } else {
412 p = get_bsdtask_info(t1);
413 if (p) {
91447636 414 pid = proc_pid(p);
1c79356b
A
415 err = KERN_SUCCESS;
416 } else {
417 err = KERN_FAILURE;
418 }
419 }
420 task_deallocate(t1);
1c79356b 421pftout:
e5568f75 422 AUDIT_ARG(pid, pid);
91447636 423 (void) copyout((char *) &pid, pid_addr, sizeof(int));
e5568f75 424 AUDIT_MACH_SYSCALL_EXIT(err);
1c79356b
A
425 return(err);
426}
427
2d21ac55
A
428/*
429 *
430 * tfp_policy = KERN_TFP_POLICY_DENY; Deny Mode: None allowed except for self
431 * tfp_policy = KERN_TFP_POLICY_DEFAULT; default mode: all posix checks and upcall via task port for authentication
432 *
433 */
434static int tfp_policy = KERN_TFP_POLICY_DEFAULT;
435
436/*
437 * Routine: task_for_pid_posix_check
438 * Purpose:
439 * Verify that the current process should be allowed to
440 * get the target process's task port. This is only
441 * permitted if:
442 * - The current process is root
443 * OR all of the following are true:
444 * - The target process's real, effective, and saved uids
445 * are the same as the current proc's euid,
446 * - The target process's group set is a subset of the
447 * calling process's group set, and
448 * - The target process hasn't switched credentials.
449 *
450 * Returns: TRUE: permitted
451 * FALSE: denied
452 */
453static int
454task_for_pid_posix_check(proc_t target)
455{
456 kauth_cred_t targetcred, mycred;
457 uid_t myuid;
458 int allowed;
459
460 /* No task_for_pid on bad targets */
461 if (target == PROC_NULL || target->p_stat == SZOMB) {
462 return FALSE;
463 }
464
465 mycred = kauth_cred_get();
466 myuid = kauth_cred_getuid(mycred);
467
468 /* If we're running as root, the check passes */
469 if (kauth_cred_issuser(mycred))
470 return TRUE;
471
472 /* We're allowed to get our own task port */
473 if (target == current_proc())
474 return TRUE;
475
476 /*
477 * Under DENY, only root can get another proc's task port,
478 * so no more checks are needed.
479 */
480 if (tfp_policy == KERN_TFP_POLICY_DENY) {
481 return FALSE;
482 }
483
484 targetcred = kauth_cred_proc_ref(target);
485 allowed = TRUE;
486
487 /* Do target's ruid, euid, and saved uid match my euid? */
488 if ((kauth_cred_getuid(targetcred) != myuid) ||
489 (targetcred->cr_ruid != myuid) ||
490 (targetcred->cr_svuid != myuid)) {
491 allowed = FALSE;
492 goto out;
493 }
494
495 /* Are target's groups a subset of my groups? */
496 if (kauth_cred_gid_subset(targetcred, mycred, &allowed) ||
497 allowed == 0) {
498 allowed = FALSE;
499 goto out;
500 }
501
502 /* Has target switched credentials? */
503 if (target->p_flag & P_SUGID) {
504 allowed = FALSE;
505 goto out;
506 }
507
508out:
509 kauth_cred_unref(&targetcred);
510 return allowed;
511}
512
1c79356b
A
513/*
514 * Routine: task_for_pid
515 * Purpose:
516 * Get the task port for another "process", named by its
517 * process ID on the same host as "target_task".
518 *
519 * Only permitted to privileged processes, or processes
520 * with the same user ID.
91447636 521 *
b0d623f7
A
522 * Note: if pid == 0, an error is return no matter who is calling.
523 *
91447636 524 * XXX This should be a BSD system call, not a Mach trap!!!
1c79356b
A
525 */
526kern_return_t
91447636
A
527task_for_pid(
528 struct task_for_pid_args *args)
1c79356b 529{
91447636
A
530 mach_port_name_t target_tport = args->target_tport;
531 int pid = args->pid;
532 user_addr_t task_addr = args->t;
2d21ac55
A
533 proc_t p = PROC_NULL;
534 task_t t1 = TASK_NULL;
535 mach_port_name_t tret = MACH_PORT_NULL;
536 ipc_port_t tfpport;
1c79356b
A
537 void * sright;
538 int error = 0;
1c79356b 539
e5568f75
A
540 AUDIT_MACH_SYSCALL_ENTER(AUE_TASKFORPID);
541 AUDIT_ARG(pid, pid);
542 AUDIT_ARG(mach_port1, target_tport);
543
b0d623f7
A
544 /* Always check if pid == 0 */
545 if (pid == 0) {
2d21ac55
A
546 (void ) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
547 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
548 return(KERN_FAILURE);
549 }
2d21ac55 550
1c79356b
A
551 t1 = port_name_to_task(target_tport);
552 if (t1 == TASK_NULL) {
2d21ac55 553 (void) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
e5568f75 554 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
0b4e3aa0 555 return(KERN_FAILURE);
1c79356b
A
556 }
557
91447636 558
2d21ac55 559 p = proc_find(pid);
b0d623f7
A
560#if CONFIG_AUDIT
561 if (p != PROC_NULL)
562 AUDIT_ARG(process, p);
563#endif
91447636 564
2d21ac55
A
565 if (!(task_for_pid_posix_check(p))) {
566 error = KERN_FAILURE;
567 goto tfpout;
568 }
0c530ab8 569
2d21ac55
A
570 if (p->task != TASK_NULL) {
571 /* If we aren't root and target's task access port is set... */
572 if (!kauth_cred_issuser(kauth_cred_get()) &&
cf7d32b8 573 p != current_proc() &&
2d21ac55
A
574 (task_get_task_access_port(p->task, &tfpport) == 0) &&
575 (tfpport != IPC_PORT_NULL)) {
0c530ab8 576
2d21ac55
A
577 if (tfpport == IPC_PORT_DEAD) {
578 error = KERN_PROTECTION_FAILURE;
579 goto tfpout;
580 }
0c530ab8 581
2d21ac55
A
582 /* Call up to the task access server */
583 error = check_task_access(tfpport, proc_selfpid(), kauth_getgid(), pid);
0c530ab8 584
2d21ac55
A
585 if (error != MACH_MSG_SUCCESS) {
586 if (error == MACH_RCV_INTERRUPTED)
587 error = KERN_ABORTED;
588 else
589 error = KERN_FAILURE;
590 goto tfpout;
591 }
592 }
593#if CONFIG_MACF
594 error = mac_proc_check_get_task(kauth_cred_get(), p);
595 if (error) {
596 error = KERN_FAILURE;
1c79356b 597 goto tfpout;
2d21ac55
A
598 }
599#endif
600
601 /* Grant task port access */
602 task_reference(p->task);
603 sright = (void *) convert_task_to_port(p->task);
604 tret = ipc_port_copyout_send(
605 sright,
606 get_task_ipcspace(current_task()));
607 }
608 error = KERN_SUCCESS;
0c530ab8 609
1c79356b 610tfpout:
2d21ac55
A
611 task_deallocate(t1);
612 AUDIT_ARG(mach_port2, tret);
613 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
614 if (p != PROC_NULL)
615 proc_rele(p);
e5568f75 616 AUDIT_MACH_SYSCALL_EXIT(error);
1c79356b
A
617 return(error);
618}
619
0c530ab8
A
620/*
621 * Routine: task_name_for_pid
622 * Purpose:
623 * Get the task name port for another "process", named by its
624 * process ID on the same host as "target_task".
625 *
626 * Only permitted to privileged processes, or processes
627 * with the same user ID.
628 *
629 * XXX This should be a BSD system call, not a Mach trap!!!
630 */
631
632kern_return_t
633task_name_for_pid(
634 struct task_name_for_pid_args *args)
635{
636 mach_port_name_t target_tport = args->target_tport;
637 int pid = args->pid;
638 user_addr_t task_addr = args->t;
2d21ac55 639 proc_t p = PROC_NULL;
0c530ab8
A
640 task_t t1;
641 mach_port_name_t tret;
642 void * sright;
2d21ac55
A
643 int error = 0, refheld = 0;
644 kauth_cred_t target_cred;
0c530ab8
A
645
646 AUDIT_MACH_SYSCALL_ENTER(AUE_TASKNAMEFORPID);
647 AUDIT_ARG(pid, pid);
648 AUDIT_ARG(mach_port1, target_tport);
649
650 t1 = port_name_to_task(target_tport);
651 if (t1 == TASK_NULL) {
2d21ac55 652 (void) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
0c530ab8
A
653 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
654 return(KERN_FAILURE);
655 }
656
2d21ac55 657 p = proc_find(pid);
2d21ac55 658 if (p != PROC_NULL) {
b0d623f7 659 AUDIT_ARG(process, p);
2d21ac55
A
660 target_cred = kauth_cred_proc_ref(p);
661 refheld = 1;
662
663 if ((p->p_stat != SZOMB)
664 && ((current_proc() == p)
665 || kauth_cred_issuser(kauth_cred_get())
666 || ((kauth_cred_getuid(target_cred) == kauth_cred_getuid(kauth_cred_get())) &&
667 ((target_cred->cr_ruid == kauth_cred_get()->cr_ruid))))) {
668
669 if (p->task != TASK_NULL) {
670 task_reference(p->task);
671#if CONFIG_MACF
672 error = mac_proc_check_get_task_name(kauth_cred_get(), p);
673 if (error) {
674 task_deallocate(p->task);
675 goto noperm;
676 }
677#endif
678 sright = (void *)convert_task_name_to_port(p->task);
679 tret = ipc_port_copyout_send(sright,
0c530ab8 680 get_task_ipcspace(current_task()));
2d21ac55
A
681 } else
682 tret = MACH_PORT_NULL;
683
684 AUDIT_ARG(mach_port2, tret);
685 (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
686 task_deallocate(t1);
687 error = KERN_SUCCESS;
688 goto tnfpout;
689 }
0c530ab8
A
690 }
691
2d21ac55
A
692#if CONFIG_MACF
693noperm:
694#endif
695 task_deallocate(t1);
0c530ab8
A
696 tret = MACH_PORT_NULL;
697 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
698 error = KERN_FAILURE;
699tnfpout:
2d21ac55
A
700 if (refheld != 0)
701 kauth_cred_unref(&target_cred);
702 if (p != PROC_NULL)
703 proc_rele(p);
0c530ab8
A
704 AUDIT_MACH_SYSCALL_EXIT(error);
705 return(error);
706}
707
d1ecb069
A
708kern_return_t
709pid_suspend(struct proc *p __unused, struct pid_suspend_args *args, int *ret)
710{
711 task_t target = NULL;
712 proc_t targetproc = PROC_NULL;
713 int pid = args->pid;
714 int error = 0;
715
716#if CONFIG_MACF
717 error = mac_proc_check_suspend_resume(p, 0); /* 0 for suspend */
718 if (error) {
719 error = KERN_FAILURE;
720 goto out;
721 }
722#endif
723
724 if (pid == 0) {
725 error = KERN_FAILURE;
726 goto out;
727 }
728
729 targetproc = proc_find(pid);
730 if (!task_for_pid_posix_check(targetproc)) {
731 error = KERN_FAILURE;
732 goto out;
733 }
734
735 target = targetproc->task;
736#ifndef CONFIG_EMBEDDED
737 if (target != TASK_NULL) {
738 mach_port_t tfpport;
739
740 /* If we aren't root and target's task access port is set... */
741 if (!kauth_cred_issuser(kauth_cred_get()) &&
742 targetproc != current_proc() &&
743 (task_get_task_access_port(target, &tfpport) == 0) &&
744 (tfpport != IPC_PORT_NULL)) {
745
746 if (tfpport == IPC_PORT_DEAD) {
747 error = KERN_PROTECTION_FAILURE;
748 goto out;
749 }
750
751 /* Call up to the task access server */
752 error = check_task_access(tfpport, proc_selfpid(), kauth_getgid(), pid);
753
754 if (error != MACH_MSG_SUCCESS) {
755 if (error == MACH_RCV_INTERRUPTED)
756 error = KERN_ABORTED;
757 else
758 error = KERN_FAILURE;
759 goto out;
760 }
761 }
762 }
763#endif
764
765 task_reference(target);
766 error = task_suspend(target);
767 task_deallocate(target);
768
769out:
770 if (targetproc != PROC_NULL)
771 proc_rele(targetproc);
772 *ret = error;
773 return error;
774}
775
776kern_return_t
777pid_resume(struct proc *p __unused, struct pid_resume_args *args, int *ret)
778{
779 task_t target = NULL;
780 proc_t targetproc = PROC_NULL;
781 int pid = args->pid;
782 int error = 0;
783
784#if CONFIG_MACF
785 error = mac_proc_check_suspend_resume(p, 1); /* 1 for resume */
786 if (error) {
787 error = KERN_FAILURE;
788 goto out;
789 }
790#endif
791
792 if (pid == 0) {
793 error = KERN_FAILURE;
794 goto out;
795 }
796
797 targetproc = proc_find(pid);
798 if (!task_for_pid_posix_check(targetproc)) {
799 error = KERN_FAILURE;
800 goto out;
801 }
802
803 target = targetproc->task;
804#ifndef CONFIG_EMBEDDED
805 if (target != TASK_NULL) {
806 mach_port_t tfpport;
807
808 /* If we aren't root and target's task access port is set... */
809 if (!kauth_cred_issuser(kauth_cred_get()) &&
810 targetproc != current_proc() &&
811 (task_get_task_access_port(target, &tfpport) == 0) &&
812 (tfpport != IPC_PORT_NULL)) {
813
814 if (tfpport == IPC_PORT_DEAD) {
815 error = KERN_PROTECTION_FAILURE;
816 goto out;
817 }
818
819 /* Call up to the task access server */
820 error = check_task_access(tfpport, proc_selfpid(), kauth_getgid(), pid);
821
822 if (error != MACH_MSG_SUCCESS) {
823 if (error == MACH_RCV_INTERRUPTED)
824 error = KERN_ABORTED;
825 else
826 error = KERN_FAILURE;
827 goto out;
828 }
829 }
830 }
831#endif
832
833 task_reference(target);
834 error = task_resume(target);
835 task_deallocate(target);
836
837out:
838 if (targetproc != PROC_NULL)
839 proc_rele(targetproc);
840 *ret = error;
841 return error;
842
843 return 0;
844}
845
0c530ab8
A
846static int
847sysctl_settfp_policy(__unused struct sysctl_oid *oidp, void *arg1,
848 __unused int arg2, struct sysctl_req *req)
849{
850 int error = 0;
851 int new_value;
852
853 error = SYSCTL_OUT(req, arg1, sizeof(int));
854 if (error || req->newptr == USER_ADDR_NULL)
855 return(error);
856
857 if (!is_suser())
858 return(EPERM);
859
860 if ((error = SYSCTL_IN(req, &new_value, sizeof(int)))) {
861 goto out;
862 }
863 if ((new_value == KERN_TFP_POLICY_DENY)
2d21ac55 864 || (new_value == KERN_TFP_POLICY_DEFAULT))
0c530ab8
A
865 tfp_policy = new_value;
866 else
867 error = EINVAL;
868out:
869 return(error);
870
871}
872
2d21ac55
A
873#if defined(SECURE_KERNEL)
874static int kern_secure_kernel = 1;
875#else
876static int kern_secure_kernel = 0;
877#endif
0c530ab8 878
2d21ac55 879SYSCTL_INT(_kern, OID_AUTO, secure_kernel, CTLFLAG_RD, &kern_secure_kernel, 0, "");
0c530ab8 880
2d21ac55 881SYSCTL_NODE(_kern, KERN_TFP, tfp, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "tfp");
0c530ab8
A
882SYSCTL_PROC(_kern_tfp, KERN_TFP_POLICY, policy, CTLTYPE_INT | CTLFLAG_RW,
883 &tfp_policy, sizeof(uint32_t), &sysctl_settfp_policy ,"I","policy");
0c530ab8 884
2d21ac55
A
885SYSCTL_INT(_vm, OID_AUTO, shared_region_trace_level, CTLFLAG_RW,
886 &shared_region_trace_level, 0, "");
887SYSCTL_INT(_vm, OID_AUTO, shared_region_version, CTLFLAG_RD,
888 &shared_region_version, 0, "");
889SYSCTL_INT(_vm, OID_AUTO, shared_region_persistence, CTLFLAG_RW,
890 &shared_region_persistence, 0, "");
1c79356b 891
91447636 892/*
2d21ac55 893 * shared_region_check_np:
91447636 894 *
2d21ac55
A
895 * This system call is intended for dyld.
896 *
897 * dyld calls this when any process starts to see if the process's shared
898 * region is already set up and ready to use.
899 * This call returns the base address of the first mapping in the
900 * process's shared region's first mapping.
901 * dyld will then check what's mapped at that address.
902 *
903 * If the shared region is empty, dyld will then attempt to map the shared
904 * cache file in the shared region via the shared_region_map_np() system call.
905 *
906 * If something's already mapped in the shared region, dyld will check if it
907 * matches the shared cache it would like to use for that process.
908 * If it matches, evrything's ready and the process can proceed and use the
909 * shared region.
910 * If it doesn't match, dyld will unmap the shared region and map the shared
911 * cache into the process's address space via mmap().
912 *
913 * ERROR VALUES
914 * EINVAL no shared region
915 * ENOMEM shared region is empty
916 * EFAULT bad address for "start_address"
91447636
A
917 */
918int
2d21ac55
A
919shared_region_check_np(
920 __unused struct proc *p,
921 struct shared_region_check_np_args *uap,
922 __unused int *retvalp)
91447636 923{
2d21ac55
A
924 vm_shared_region_t shared_region;
925 mach_vm_offset_t start_address;
926 int error;
927 kern_return_t kr;
928
929 SHARED_REGION_TRACE_DEBUG(
930 ("shared_region: %p [%d(%s)] -> check_np(0x%llx)\n",
931 current_thread(), p->p_pid, p->p_comm,
932 (uint64_t)uap->start_address));
933
934 /* retrieve the current tasks's shared region */
935 shared_region = vm_shared_region_get(current_task());
936 if (shared_region != NULL) {
937 /* retrieve address of its first mapping... */
938 kr = vm_shared_region_start_address(shared_region,
939 &start_address);
91447636
A
940 if (kr != KERN_SUCCESS) {
941 error = ENOMEM;
2d21ac55
A
942 } else {
943 /* ... and give it to the caller */
944 error = copyout(&start_address,
945 (user_addr_t) uap->start_address,
946 sizeof (start_address));
947 if (error) {
948 SHARED_REGION_TRACE_ERROR(
949 ("shared_region: %p [%d(%s)] "
950 "check_np(0x%llx) "
951 "copyout(0x%llx) error %d\n",
952 current_thread(), p->p_pid, p->p_comm,
953 (uint64_t)uap->start_address, (uint64_t)start_address,
954 error));
955 }
91447636 956 }
2d21ac55 957 vm_shared_region_deallocate(shared_region);
91447636 958 } else {
2d21ac55 959 /* no shared region ! */
91447636 960 error = EINVAL;
91447636 961 }
0c530ab8 962
2d21ac55
A
963 SHARED_REGION_TRACE_DEBUG(
964 ("shared_region: %p [%d(%s)] check_np(0x%llx) <- 0x%llx %d\n",
0c530ab8 965 current_thread(), p->p_pid, p->p_comm,
2d21ac55 966 (uint64_t)uap->start_address, (uint64_t)start_address, error));
0c530ab8 967
91447636
A
968 return error;
969}
970
91447636 971/*
2d21ac55 972 * shared_region_map_np()
91447636 973 *
2d21ac55 974 * This system call is intended for dyld.
91447636 975 *
2d21ac55
A
976 * dyld uses this to map a shared cache file into a shared region.
977 * This is usually done only the first time a shared cache is needed.
978 * Subsequent processes will just use the populated shared region without
979 * requiring any further setup.
91447636
A
980 */
981int
2d21ac55 982shared_region_map_np(
91447636 983 struct proc *p,
2d21ac55 984 struct shared_region_map_np_args *uap,
91447636
A
985 __unused int *retvalp)
986{
2d21ac55
A
987 int error;
988 kern_return_t kr;
989 int fd;
990 struct fileproc *fp;
991 struct vnode *vp, *root_vp;
992 struct vnode_attr va;
993 off_t fs;
994 memory_object_size_t file_size;
995 user_addr_t user_mappings;
996 struct shared_file_mapping_np *mappings;
4a3eedf9 997#define SFM_MAX_STACK 8
2d21ac55
A
998 struct shared_file_mapping_np stack_mappings[SFM_MAX_STACK];
999 unsigned int mappings_count;
1000 vm_size_t mappings_size;
1001 memory_object_control_t file_control;
1002 struct vm_shared_region *shared_region;
1003
1004 SHARED_REGION_TRACE_DEBUG(
1005 ("shared_region: %p [%d(%s)] -> map\n",
1006 current_thread(), p->p_pid, p->p_comm));
1007
1008 shared_region = NULL;
1009 mappings_count = 0;
8ad349bb 1010 mappings_size = 0;
91447636 1011 mappings = NULL;
91447636
A
1012 fp = NULL;
1013 vp = NULL;
1014
2d21ac55 1015 /* get file descriptor for shared region cache file */
91447636
A
1016 fd = uap->fd;
1017
1018 /* get file structure from file descriptor */
1019 error = fp_lookup(p, fd, &fp, 0);
1020 if (error) {
2d21ac55
A
1021 SHARED_REGION_TRACE_ERROR(
1022 ("shared_region: %p [%d(%s)] map: "
0c530ab8
A
1023 "fd=%d lookup failed (error=%d)\n",
1024 current_thread(), p->p_pid, p->p_comm, fd, error));
91447636
A
1025 goto done;
1026 }
1027
1028 /* make sure we're attempting to map a vnode */
1029 if (fp->f_fglob->fg_type != DTYPE_VNODE) {
2d21ac55
A
1030 SHARED_REGION_TRACE_ERROR(
1031 ("shared_region: %p [%d(%s)] map: "
0c530ab8
A
1032 "fd=%d not a vnode (type=%d)\n",
1033 current_thread(), p->p_pid, p->p_comm,
1034 fd, fp->f_fglob->fg_type));
91447636
A
1035 error = EINVAL;
1036 goto done;
1037 }
1038
1039 /* we need at least read permission on the file */
1040 if (! (fp->f_fglob->fg_flag & FREAD)) {
2d21ac55
A
1041 SHARED_REGION_TRACE_ERROR(
1042 ("shared_region: %p [%d(%s)] map: "
0c530ab8
A
1043 "fd=%d not readable\n",
1044 current_thread(), p->p_pid, p->p_comm, fd));
91447636
A
1045 error = EPERM;
1046 goto done;
1047 }
1048
1049 /* get vnode from file structure */
2d21ac55 1050 error = vnode_getwithref((vnode_t) fp->f_fglob->fg_data);
91447636 1051 if (error) {
2d21ac55
A
1052 SHARED_REGION_TRACE_ERROR(
1053 ("shared_region: %p [%d(%s)] map: "
0c530ab8
A
1054 "fd=%d getwithref failed (error=%d)\n",
1055 current_thread(), p->p_pid, p->p_comm, fd, error));
91447636
A
1056 goto done;
1057 }
1058 vp = (struct vnode *) fp->f_fglob->fg_data;
1059
1060 /* make sure the vnode is a regular file */
1061 if (vp->v_type != VREG) {
2d21ac55
A
1062 SHARED_REGION_TRACE_ERROR(
1063 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
0c530ab8
A
1064 "not a file (type=%d)\n",
1065 current_thread(), p->p_pid, p->p_comm,
1066 vp, vp->v_name, vp->v_type));
91447636
A
1067 error = EINVAL;
1068 goto done;
1069 }
1070
2d21ac55
A
1071 /* make sure vnode is on the process's root volume */
1072 root_vp = p->p_fd->fd_rdir;
1073 if (root_vp == NULL) {
1074 root_vp = rootvnode;
91447636 1075 }
2d21ac55
A
1076 if (vp->v_mount != root_vp->v_mount) {
1077 SHARED_REGION_TRACE_ERROR(
1078 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1079 "not on process's root volume\n",
0c530ab8
A
1080 current_thread(), p->p_pid, p->p_comm,
1081 vp, vp->v_name));
2d21ac55 1082 error = EPERM;
91447636 1083 goto done;
91447636
A
1084 }
1085
2d21ac55
A
1086 /* make sure vnode is owned by "root" */
1087 VATTR_INIT(&va);
1088 VATTR_WANTED(&va, va_uid);
1089 error = vnode_getattr(vp, &va, vfs_context_current());
1090 if (error) {
1091 SHARED_REGION_TRACE_ERROR(
1092 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1093 "vnode_getattr(%p) failed (error=%d)\n",
0c530ab8 1094 current_thread(), p->p_pid, p->p_comm,
2d21ac55 1095 vp, vp->v_name, vp, error));
91447636
A
1096 goto done;
1097 }
2d21ac55
A
1098 if (va.va_uid != 0) {
1099 SHARED_REGION_TRACE_ERROR(
1100 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1101 "owned by uid=%d instead of 0\n",
1102 current_thread(), p->p_pid, p->p_comm,
1103 vp, vp->v_name, va.va_uid));
1104 error = EPERM;
1105 goto done;
91447636 1106 }
2d21ac55
A
1107
1108 /* get vnode size */
1109 error = vnode_size(vp, &fs, vfs_context_current());
1110 if (error) {
1111 SHARED_REGION_TRACE_ERROR(
1112 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1113 "vnode_size(%p) failed (error=%d)\n",
1114 current_thread(), p->p_pid, p->p_comm,
1115 vp, vp->v_name, vp, error));
1116 goto done;
91447636 1117 }
2d21ac55 1118 file_size = fs;
91447636
A
1119
1120 /* get the file's memory object handle */
91447636
A
1121 file_control = ubc_getobject(vp, UBC_HOLDOBJECT);
1122 if (file_control == MEMORY_OBJECT_CONTROL_NULL) {
2d21ac55
A
1123 SHARED_REGION_TRACE_ERROR(
1124 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1125 "no memory object\n",
0c530ab8
A
1126 current_thread(), p->p_pid, p->p_comm,
1127 vp, vp->v_name));
91447636
A
1128 error = EINVAL;
1129 goto done;
1130 }
2d21ac55
A
1131
1132 /* get the list of mappings the caller wants us to establish */
1133 mappings_count = uap->count; /* number of mappings */
1134 mappings_size = (vm_size_t) (mappings_count * sizeof (mappings[0]));
1135 if (mappings_count == 0) {
1136 SHARED_REGION_TRACE_INFO(
1137 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1138 "no mappings\n",
1139 current_thread(), p->p_pid, p->p_comm,
1140 vp, vp->v_name));
1141 error = 0; /* no mappings: we're done ! */
1142 goto done;
1143 } else if (mappings_count <= SFM_MAX_STACK) {
1144 mappings = &stack_mappings[0];
91447636 1145 } else {
2d21ac55
A
1146 SHARED_REGION_TRACE_ERROR(
1147 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1148 "too many mappings (%d)\n",
1149 current_thread(), p->p_pid, p->p_comm,
1150 vp, vp->v_name, mappings_count));
1151 error = EINVAL;
1152 goto done;
91447636 1153 }
91447636 1154
2d21ac55
A
1155 user_mappings = uap->mappings; /* the mappings, in user space */
1156 error = copyin(user_mappings,
1157 mappings,
1158 mappings_size);
1159 if (error) {
1160 SHARED_REGION_TRACE_ERROR(
1161 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1162 "copyin(0x%llx, %d) failed (error=%d)\n",
0c530ab8 1163 current_thread(), p->p_pid, p->p_comm,
2d21ac55 1164 vp, vp->v_name, (uint64_t)user_mappings, mappings_count, error));
91447636
A
1165 goto done;
1166 }
1167
2d21ac55
A
1168 /* get the process's shared region (setup in vm_map_exec()) */
1169 shared_region = vm_shared_region_get(current_task());
1170 if (shared_region == NULL) {
1171 SHARED_REGION_TRACE_ERROR(
1172 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1173 "no shared region\n",
1174 current_thread(), p->p_pid, p->p_comm,
1175 vp, vp->v_name));
1176 goto done;
1177 }
91447636 1178
2d21ac55
A
1179 /* map the file into that shared region's submap */
1180 kr = vm_shared_region_map_file(shared_region,
1181 mappings_count,
1182 mappings,
1183 file_control,
1184 file_size,
1185 (void *) p->p_fd->fd_rdir);
1186 if (kr != KERN_SUCCESS) {
1187 SHARED_REGION_TRACE_ERROR(
1188 ("shared_region: %p [%d(%s)] map(%p:'%s'): "
1189 "vm_shared_region_map_file() failed kr=0x%x\n",
0c530ab8
A
1190 current_thread(), p->p_pid, p->p_comm,
1191 vp, vp->v_name, kr));
1192 switch (kr) {
1193 case KERN_INVALID_ADDRESS:
1194 error = EFAULT;
2d21ac55 1195 break;
0c530ab8
A
1196 case KERN_PROTECTION_FAILURE:
1197 error = EPERM;
2d21ac55 1198 break;
0c530ab8
A
1199 case KERN_NO_SPACE:
1200 error = ENOMEM;
2d21ac55 1201 break;
0c530ab8
A
1202 case KERN_FAILURE:
1203 case KERN_INVALID_ARGUMENT:
1204 default:
1205 error = EINVAL;
2d21ac55 1206 break;
0c530ab8 1207 }
2d21ac55 1208 goto done;
91447636
A
1209 }
1210
2d21ac55
A
1211 error = 0;
1212
1213 /* update the vnode's access time */
1214 if (! (vnode_vfsvisflags(vp) & MNT_NOATIME)) {
1215 VATTR_INIT(&va);
1216 nanotime(&va.va_access_time);
1217 VATTR_SET_ACTIVE(&va, va_access_time);
1218 vnode_setattr(vp, &va, vfs_context_current());
91447636
A
1219 }
1220
2d21ac55
A
1221 if (p->p_flag & P_NOSHLIB) {
1222 /* signal that this process is now using split libraries */
b0d623f7 1223 OSBitAndAtomic(~((uint32_t)P_NOSHLIB), &p->p_flag);
91447636
A
1224 }
1225
1226done:
1227 if (vp != NULL) {
1228 /*
1229 * release the vnode...
1230 * ubc_map() still holds it for us in the non-error case
1231 */
1232 (void) vnode_put(vp);
1233 vp = NULL;
1234 }
1235 if (fp != NULL) {
1236 /* release the file descriptor */
1237 fp_drop(p, fd, fp, 0);
1238 fp = NULL;
1239 }
9bccf70c 1240
2d21ac55
A
1241 if (shared_region != NULL) {
1242 vm_shared_region_deallocate(shared_region);
9bccf70c
A
1243 }
1244
2d21ac55
A
1245 SHARED_REGION_TRACE_DEBUG(
1246 ("shared_region: %p [%d(%s)] <- map\n",
1247 current_thread(), p->p_pid, p->p_comm));
9bccf70c 1248
2d21ac55 1249 return error;
9bccf70c
A
1250}
1251
9bccf70c 1252
2d21ac55 1253/* sysctl overflow room */
9bccf70c 1254
2d21ac55
A
1255/* vm_page_free_target is provided as a makeshift solution for applications that want to
1256 allocate buffer space, possibly purgeable memory, but not cause inactive pages to be
1257 reclaimed. It allows the app to calculate how much memory is free outside the free target. */
1258extern unsigned int vm_page_free_target;
1259SYSCTL_INT(_vm, OID_AUTO, vm_page_free_target, CTLFLAG_RD,
1260 &vm_page_free_target, 0, "Pageout daemon free target");
9bccf70c 1261
b0d623f7
A
1262extern unsigned int vm_memory_pressure;
1263SYSCTL_INT(_vm, OID_AUTO, memory_pressure, CTLFLAG_RD,
1264 &vm_memory_pressure, 0, "Memory pressure indicator");
1265
1266static int
1267vm_ctl_page_free_wanted SYSCTL_HANDLER_ARGS
1268{
1269#pragma unused(oidp, arg1, arg2)
1270 unsigned int page_free_wanted;
1271
1272 page_free_wanted = mach_vm_ctl_page_free_wanted();
1273 return SYSCTL_OUT(req, &page_free_wanted, sizeof (page_free_wanted));
1274}
1275SYSCTL_PROC(_vm, OID_AUTO, page_free_wanted,
1276 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
1277 0, 0, vm_ctl_page_free_wanted, "I", "");
1278
1279extern unsigned int vm_page_purgeable_count;
1280SYSCTL_INT(_vm, OID_AUTO, page_purgeable_count, CTLFLAG_RD,
1281 &vm_page_purgeable_count, 0, "Purgeable page count");
1282
1283extern unsigned int vm_page_purgeable_wired_count;
1284SYSCTL_INT(_vm, OID_AUTO, page_purgeable_wired_count, CTLFLAG_RD,
1285 &vm_page_purgeable_wired_count, 0, "Wired purgeable page count");
1286
1287SYSCTL_INT(_vm, OID_AUTO, page_reusable_count, CTLFLAG_RD,
1288 &vm_page_stats_reusable.reusable_count, 0, "Reusable page count");
1289SYSCTL_QUAD(_vm, OID_AUTO, reusable_success, CTLFLAG_RD,
1290 &vm_page_stats_reusable.reusable_pages_success, "");
1291SYSCTL_QUAD(_vm, OID_AUTO, reusable_failure, CTLFLAG_RD,
1292 &vm_page_stats_reusable.reusable_pages_failure, "");
1293SYSCTL_QUAD(_vm, OID_AUTO, reusable_shared, CTLFLAG_RD,
1294 &vm_page_stats_reusable.reusable_pages_shared, "");
1295SYSCTL_QUAD(_vm, OID_AUTO, all_reusable_calls, CTLFLAG_RD,
1296 &vm_page_stats_reusable.all_reusable_calls, "");
1297SYSCTL_QUAD(_vm, OID_AUTO, partial_reusable_calls, CTLFLAG_RD,
1298 &vm_page_stats_reusable.partial_reusable_calls, "");
1299SYSCTL_QUAD(_vm, OID_AUTO, reuse_success, CTLFLAG_RD,
1300 &vm_page_stats_reusable.reuse_pages_success, "");
1301SYSCTL_QUAD(_vm, OID_AUTO, reuse_failure, CTLFLAG_RD,
1302 &vm_page_stats_reusable.reuse_pages_failure, "");
1303SYSCTL_QUAD(_vm, OID_AUTO, all_reuse_calls, CTLFLAG_RD,
1304 &vm_page_stats_reusable.all_reuse_calls, "");
1305SYSCTL_QUAD(_vm, OID_AUTO, partial_reuse_calls, CTLFLAG_RD,
1306 &vm_page_stats_reusable.partial_reuse_calls, "");
1307SYSCTL_QUAD(_vm, OID_AUTO, can_reuse_success, CTLFLAG_RD,
1308 &vm_page_stats_reusable.can_reuse_success, "");
1309SYSCTL_QUAD(_vm, OID_AUTO, can_reuse_failure, CTLFLAG_RD,
1310 &vm_page_stats_reusable.can_reuse_failure, "");
1311
1312
1313int
1314vm_pressure_monitor(
1315 __unused struct proc *p,
1316 struct vm_pressure_monitor_args *uap,
1317 int *retval)
1318{
1319 kern_return_t kr;
1320 uint32_t pages_reclaimed;
1321 uint32_t pages_wanted;
1322
1323 kr = mach_vm_pressure_monitor(
1324 (boolean_t) uap->wait_for_pressure,
1325 uap->nsecs_monitored,
1326 (uap->pages_reclaimed) ? &pages_reclaimed : NULL,
1327 &pages_wanted);
1328
1329 switch (kr) {
1330 case KERN_SUCCESS:
1331 break;
1332 case KERN_ABORTED:
1333 return EINTR;
1334 default:
1335 return EINVAL;
1336 }
1337
1338 if (uap->pages_reclaimed) {
1339 if (copyout((void *)&pages_reclaimed,
1340 uap->pages_reclaimed,
1341 sizeof (pages_reclaimed)) != 0) {
1342 return EFAULT;
1343 }
1344 }
1345
1346 *retval = (int) pages_wanted;
1347 return 0;
1348}