]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_proc.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / kern_proc.c
CommitLineData
1c79356b 1/*
f427ee49 2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1982, 1986, 1989, 1991, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * @(#)kern_proc.c 8.4 (Berkeley) 1/4/94
62 */
2d21ac55
A
63/*
64 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
65 * support for mandatory and extensible security protections. This notice
66 * is included in support of clause 2.2 (b) of the Apple Public License,
67 * Version 2.0.
68 */
1c79356b
A
69/* HISTORY
70 * 04-Aug-97 Umesh Vaishampayan (umeshv@apple.com)
71 * Added current_proc_EXTERNAL() function for the use of kernel
0a7de745 72 * lodable modules.
1c79356b
A
73 *
74 * 05-Jun-95 Mac Gillon (mgillon) at NeXT
75 * New version based on 3.3NS and 4.4
76 */
77
78
79#include <sys/param.h>
80#include <sys/systm.h>
81#include <sys/kernel.h>
91447636 82#include <sys/proc_internal.h>
1c79356b
A
83#include <sys/acct.h>
84#include <sys/wait.h>
91447636 85#include <sys/file_internal.h>
1c79356b
A
86#include <sys/uio.h>
87#include <sys/malloc.h>
2d21ac55 88#include <sys/lock.h>
1c79356b
A
89#include <sys/mbuf.h>
90#include <sys/ioctl.h>
91#include <sys/tty.h>
92#include <sys/signalvar.h>
e5568f75 93#include <sys/syslog.h>
2d21ac55
A
94#include <sys/sysctl.h>
95#include <sys/sysproto.h>
96#include <sys/kauth.h>
97#include <sys/codesign.h>
91447636 98#include <sys/kernel_types.h>
6d2010ae 99#include <sys/ubc.h>
2d21ac55
A
100#include <kern/kalloc.h>
101#include <kern/task.h>
fe8ab488
A
102#include <kern/coalition.h>
103#include <sys/coalition.h>
2d21ac55
A
104#include <kern/assert.h>
105#include <vm/vm_protos.h>
0a7de745 106#include <vm/vm_map.h> /* vm_map_switch_protect() */
fe8ab488 107#include <vm/vm_pageout.h>
b0d623f7 108#include <mach/task.h>
316670eb 109#include <mach/message.h>
fe8ab488
A
110#include <sys/priv.h>
111#include <sys/proc_info.h>
112#include <sys/bsdtask_info.h>
490019cf 113#include <sys/persona.h>
cb323159
A
114#include <sys/sysent.h>
115#include <sys/reason.h>
f427ee49 116#include <sys/proc_require.h>
4ba76501 117#include <IOKit/IOBSD.h> /* IOTaskHasEntitlement() */
f427ee49 118#include <kern/ipc_kobject.h> /* ipc_kobject_set_kobjidx() */
2d21ac55 119
527f9951
A
120#ifdef CONFIG_32BIT_TELEMETRY
121#include <sys/kasl.h>
122#endif /* CONFIG_32BIT_TELEMETRY */
123
5ba3f43e
A
124#if CONFIG_CSR
125#include <sys/csr.h>
126#endif
127
39236c6e
A
128#if CONFIG_MEMORYSTATUS
129#include <sys/kern_memorystatus.h>
130#endif
131
2d21ac55
A
132#if CONFIG_MACF
133#include <security/mac_framework.h>
f427ee49 134#include <security/mac_mach_internal.h>
2d21ac55
A
135#endif
136
137#include <libkern/crypto/sha1.h>
1c79356b 138
527f9951
A
139#ifdef CONFIG_32BIT_TELEMETRY
140#define MAX_32BIT_EXEC_SIG_SIZE 160
141#endif /* CONFIG_32BIT_TELEMETRY */
142
1c79356b
A
143/*
144 * Structure associated with user cacheing.
145 */
146struct uidinfo {
147 LIST_ENTRY(uidinfo) ui_hash;
0a7de745 148 uid_t ui_uid;
f427ee49 149 size_t ui_proccnt;
1c79356b 150};
0a7de745
A
151#define UIHASH(uid) (&uihashtbl[(uid) & uihash])
152LIST_HEAD(uihashhead, uidinfo) * uihashtbl;
153u_long uihash; /* size of hash table - 1 */
1c79356b
A
154
155/*
156 * Other process lists
157 */
158struct pidhashhead *pidhashtbl;
159u_long pidhash;
160struct pgrphashhead *pgrphashtbl;
161u_long pgrphash;
2d21ac55
A
162struct sesshashhead *sesshashtbl;
163u_long sesshash;
164
1c79356b
A
165struct proclist allproc;
166struct proclist zombproc;
91447636 167extern struct tty cons;
1c79356b 168
39236c6e 169extern int cs_debug;
c331a0be 170
cb323159
A
171#if DEVELOPMENT || DEBUG
172int syscallfilter_disable = 0;
173#endif // DEVELOPMENT || DEBUG
174
593a1d5f 175#if DEBUG
2d21ac55 176#define __PROC_INTERNAL_DEBUG 1
593a1d5f 177#endif
39037602 178#if CONFIG_COREDUMP
e5568f75 179/* Name to give to core files */
5c9f4661 180#if defined(XNU_TARGET_OS_BRIDGE)
0a7de745 181__XNU_PRIVATE_EXTERN char corefilename[MAXPATHLEN + 1] = {"/private/var/internal/%N.core"};
f427ee49 182#elif defined(XNU_TARGET_OS_OSX)
0a7de745 183__XNU_PRIVATE_EXTERN char corefilename[MAXPATHLEN + 1] = {"/cores/core.%P"};
f427ee49
A
184#else
185__XNU_PRIVATE_EXTERN char corefilename[MAXPATHLEN + 1] = {"/private/var/cores/%N.core"};
39037602 186#endif
5ba3f43e 187#endif
e5568f75 188
3e170ce0 189#if PROC_REF_DEBUG
39037602 190#include <kern/backtrace.h>
3e170ce0
A
191#endif
192
c3c9b80d
A
193static LCK_MTX_DECLARE_ATTR(proc_klist_mlock, &proc_mlock_grp, &proc_lck_attr);
194
f427ee49
A
195ZONE_DECLARE(pgrp_zone, "pgrp",
196 sizeof(struct pgrp), ZC_ZFREE_CLEARMEM);
197ZONE_DECLARE(session_zone, "session",
198 sizeof(struct session), ZC_ZFREE_CLEARMEM);
c3c9b80d
A
199/*
200 * If you need accounting for KM_PROC consider using
201 * ZONE_VIEW_DEFINE to define a zone view.
202 */
203#define KM_PROC KHEAP_DEFAULT
f427ee49 204
a39ff7e2
A
205typedef uint64_t unaligned_u64 __attribute__((aligned(1)));
206
39037602
A
207static void orphanpg(struct pgrp * pg);
208void proc_name_kdp(task_t t, char * buf, int size);
cb323159 209boolean_t proc_binary_uuid_kdp(task_t task, uuid_t uuid);
39037602 210int proc_threadname_kdp(void * uth, char * buf, size_t size);
a39ff7e2 211void proc_starttime_kdp(void * p, unaligned_u64 *tv_sec, unaligned_u64 *tv_usec, unaligned_u64 *abstime);
f427ee49 212void proc_archinfo_kdp(void* p, cpu_type_t* cputype, cpu_subtype_t* cpusubtype);
39037602 213char * proc_name_address(void * p);
f427ee49 214char * proc_longname_address(void *);
39037602 215
2d21ac55
A
216static void pgrp_add(struct pgrp * pgrp, proc_t parent, proc_t child);
217static void pgrp_remove(proc_t p);
218static void pgrp_replace(proc_t p, struct pgrp *pgrp);
219static void pgdelete_dropref(struct pgrp *pgrp);
2d21ac55 220extern void pg_rele_dropref(struct pgrp * pgrp);
316670eb 221static int csops_internal(pid_t pid, int ops, user_addr_t uaddr, user_size_t usersize, user_addr_t uaddittoken);
39236c6e 222static boolean_t proc_parent_is_currentproc(proc_t p);
2d21ac55
A
223
224struct fixjob_iterargs {
225 struct pgrp * pg;
226 struct session * mysession;
227 int entering;
228};
229
230int fixjob_callback(proc_t, void *);
e5568f75 231
39037602
A
232uint64_t
233get_current_unique_pid(void)
234{
0a7de745 235 proc_t p = current_proc();
39037602 236
0a7de745 237 if (p) {
39037602 238 return p->p_uniqueid;
0a7de745 239 } else {
39037602 240 return 0;
0a7de745 241 }
39037602
A
242}
243
1c79356b
A
244/*
245 * Initialize global process hashing structures.
246 */
247void
2d21ac55 248procinit(void)
1c79356b 249{
1c79356b
A
250 LIST_INIT(&allproc);
251 LIST_INIT(&zombproc);
252 pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
253 pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
2d21ac55 254 sesshashtbl = hashinit(maxproc / 4, M_PROC, &sesshash);
1c79356b 255 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
490019cf
A
256#if CONFIG_PERSONAS
257 personas_bootstrap();
258#endif
1c79356b
A
259}
260
261/*
262 * Change the count associated with number of processes
2d21ac55
A
263 * a given user is using. This routine protects the uihash
264 * with the list lock
1c79356b 265 */
f427ee49 266size_t
2d21ac55 267chgproccnt(uid_t uid, int diff)
1c79356b 268{
2d21ac55
A
269 struct uidinfo *uip;
270 struct uidinfo *newuip = NULL;
271 struct uihashhead *uipp;
f427ee49 272 size_t retval;
1c79356b 273
2d21ac55
A
274again:
275 proc_list_lock();
1c79356b 276 uipp = UIHASH(uid);
0a7de745
A
277 for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next) {
278 if (uip->ui_uid == uid) {
1c79356b 279 break;
0a7de745
A
280 }
281 }
1c79356b
A
282 if (uip) {
283 uip->ui_proccnt += diff;
2d21ac55
A
284 if (uip->ui_proccnt > 0) {
285 retval = uip->ui_proccnt;
286 proc_list_unlock();
287 goto out;
288 }
1c79356b 289 LIST_REMOVE(uip, ui_hash);
2d21ac55
A
290 retval = 0;
291 proc_list_unlock();
c3c9b80d 292 kheap_free(KM_PROC, uip, sizeof(struct uidinfo));
2d21ac55 293 goto out;
1c79356b
A
294 }
295 if (diff <= 0) {
2d21ac55
A
296 if (diff == 0) {
297 retval = 0;
298 proc_list_unlock();
299 goto out;
300 }
1c79356b
A
301 panic("chgproccnt: lost user");
302 }
2d21ac55
A
303 if (newuip != NULL) {
304 uip = newuip;
305 newuip = NULL;
306 LIST_INSERT_HEAD(uipp, uip, ui_hash);
307 uip->ui_uid = uid;
308 uip->ui_proccnt = diff;
309 retval = diff;
310 proc_list_unlock();
311 goto out;
312 }
313 proc_list_unlock();
c3c9b80d 314 newuip = kheap_alloc(KM_PROC, sizeof(struct uidinfo), Z_WAITOK);
0a7de745 315 if (newuip == NULL) {
91447636 316 panic("chgproccnt: M_PROC zone depleted");
0a7de745 317 }
2d21ac55
A
318 goto again;
319out:
c3c9b80d 320 kheap_free(KM_PROC, newuip, sizeof(struct uidinfo));
0a7de745 321 return retval;
1c79356b
A
322}
323
324/*
325 * Is p an inferior of the current process?
326 */
327int
2d21ac55 328inferior(proc_t p)
1c79356b 329{
2d21ac55 330 int retval = 0;
1c79356b 331
2d21ac55 332 proc_list_lock();
0a7de745
A
333 for (; p != current_proc(); p = p->p_pptr) {
334 if (p->p_pid == 0) {
2d21ac55 335 goto out;
0a7de745
A
336 }
337 }
2d21ac55
A
338 retval = 1;
339out:
340 proc_list_unlock();
0a7de745 341 return retval;
1c79356b 342}
2d21ac55 343
9bccf70c
A
344/*
345 * Is p an inferior of t ?
346 */
347int
2d21ac55 348isinferior(proc_t p, proc_t t)
9bccf70c 349{
593a1d5f
A
350 int retval = 0;
351 int nchecked = 0;
352 proc_t start = p;
9bccf70c
A
353
354 /* if p==t they are not inferior */
0a7de745
A
355 if (p == t) {
356 return 0;
357 }
2d21ac55
A
358
359 proc_list_lock();
593a1d5f
A
360 for (; p != t; p = p->p_pptr) {
361 nchecked++;
362
363 /* Detect here if we're in a cycle */
0a7de745 364 if ((p->p_pid == 0) || (p->p_pptr == start) || (nchecked >= nprocs)) {
2d21ac55 365 goto out;
0a7de745 366 }
593a1d5f 367 }
2d21ac55
A
368 retval = 1;
369out:
370 proc_list_unlock();
0a7de745 371 return retval;
9bccf70c 372}
1c79356b 373
91447636
A
374int
375proc_isinferior(int pid1, int pid2)
376{
2d21ac55
A
377 proc_t p = PROC_NULL;
378 proc_t t = PROC_NULL;
379 int retval = 0;
0a7de745
A
380
381 if (((p = proc_find(pid1)) != (proc_t)0) && ((t = proc_find(pid2)) != (proc_t)0)) {
2d21ac55 382 retval = isinferior(p, t);
0a7de745 383 }
91447636 384
0a7de745 385 if (p != PROC_NULL) {
2d21ac55 386 proc_rele(p);
0a7de745
A
387 }
388 if (t != PROC_NULL) {
2d21ac55 389 proc_rele(t);
0a7de745 390 }
2d21ac55 391
0a7de745 392 return retval;
91447636
A
393}
394
395proc_t
396proc_find(int pid)
397{
0a7de745 398 return proc_findinternal(pid, 0);
91447636
A
399}
400
2d21ac55
A
401proc_t
402proc_findinternal(int pid, int locked)
91447636 403{
2d21ac55
A
404 proc_t p = PROC_NULL;
405
406 if (locked == 0) {
407 proc_list_lock();
408 }
409
410 p = pfind_locked(pid);
0a7de745 411 if ((p == PROC_NULL) || (p != proc_ref_locked(p))) {
2d21ac55 412 p = PROC_NULL;
0a7de745 413 }
2d21ac55
A
414
415 if (locked == 0) {
416 proc_list_unlock();
417 }
418
0a7de745 419 return p;
91447636
A
420}
421
316670eb
A
422proc_t
423proc_findthread(thread_t thread)
424{
425 proc_t p = PROC_NULL;
426 struct uthread *uth;
427
428 proc_list_lock();
429 uth = get_bsdthread_info(thread);
0a7de745 430 if (uth && (uth->uu_flag & UT_VFORK)) {
316670eb 431 p = uth->uu_proc;
0a7de745 432 } else {
316670eb 433 p = (proc_t)(get_bsdthreadtask_info(thread));
0a7de745 434 }
316670eb
A
435 p = proc_ref_locked(p);
436 proc_list_unlock();
0a7de745 437 return p;
316670eb
A
438}
439
f427ee49
A
440/*
441 * Returns process identity of a given process. Calling this function is not
442 * racy for a current process or if a reference to the process is held.
443 */
444struct proc_ident
445proc_ident(proc_t p)
446{
447 struct proc_ident ident = {
448 .p_pid = proc_pid(p),
449 .p_uniqueid = proc_uniqueid(p),
450 .p_idversion = proc_pidversion(p),
451 };
452
453 return ident;
454}
455
456proc_t
457proc_find_ident(struct proc_ident const *ident)
458{
459 proc_t proc = PROC_NULL;
460
461 proc = proc_find(ident->p_pid);
462 if (proc == PROC_NULL) {
463 return PROC_NULL;
464 }
465
466 if (proc_uniqueid(proc) != ident->p_uniqueid ||
467 proc_pidversion(proc) != ident->p_idversion) {
468 proc_rele(proc);
469 return PROC_NULL;
470 }
471
472 return proc;
473}
474
3e170ce0 475void
0a7de745
A
476uthread_reset_proc_refcount(void *uthread)
477{
3e170ce0
A
478 uthread_t uth;
479
813fb2f6
A
480 uth = (uthread_t) uthread;
481 uth->uu_proc_refcount = 0;
482
483#if PROC_REF_DEBUG
3e170ce0
A
484 if (proc_ref_tracking_disabled) {
485 return;
486 }
487
3e170ce0 488 uth->uu_pindex = 0;
813fb2f6 489#endif
3e170ce0
A
490}
491
813fb2f6 492#if PROC_REF_DEBUG
3e170ce0 493int
0a7de745
A
494uthread_get_proc_refcount(void *uthread)
495{
3e170ce0
A
496 uthread_t uth;
497
498 if (proc_ref_tracking_disabled) {
499 return 0;
500 }
501
502 uth = (uthread_t) uthread;
503
504 return uth->uu_proc_refcount;
505}
813fb2f6 506#endif
3e170ce0
A
507
508static void
0a7de745
A
509record_procref(proc_t p __unused, int count)
510{
3e170ce0
A
511 uthread_t uth;
512
813fb2f6
A
513 uth = current_uthread();
514 uth->uu_proc_refcount += count;
515
516#if PROC_REF_DEBUG
3e170ce0
A
517 if (proc_ref_tracking_disabled) {
518 return;
519 }
520
cb323159
A
521 if (uth->uu_pindex < NUM_PROC_REFS_TO_TRACK) {
522 backtrace((uintptr_t *) &uth->uu_proc_pcs[uth->uu_pindex],
523 PROC_REF_STACK_DEPTH, NULL);
3e170ce0 524
cb323159
A
525 uth->uu_proc_ps[uth->uu_pindex] = p;
526 uth->uu_pindex++;
3e170ce0 527 }
3e170ce0 528#endif
813fb2f6
A
529}
530
531static boolean_t
0a7de745
A
532uthread_needs_to_wait_in_proc_refwait(void)
533{
813fb2f6
A
534 uthread_t uth = current_uthread();
535
536 /*
537 * Allow threads holding no proc refs to wait
538 * in proc_refwait, allowing threads holding
539 * proc refs to wait in proc_refwait causes
540 * deadlocks and makes proc_find non-reentrant.
541 */
0a7de745 542 if (uth->uu_proc_refcount == 0) {
813fb2f6 543 return TRUE;
0a7de745 544 }
813fb2f6
A
545
546 return FALSE;
547}
3e170ce0 548
0a7de745 549int
2d21ac55 550proc_rele(proc_t p)
91447636 551{
2d21ac55
A
552 proc_list_lock();
553 proc_rele_locked(p);
554 proc_list_unlock();
555
0a7de745 556 return 0;
91447636
A
557}
558
ff6e181a 559proc_t
2d21ac55 560proc_self(void)
ff6e181a 561{
2d21ac55 562 struct proc * p;
ff6e181a 563
2d21ac55
A
564 p = current_proc();
565
566 proc_list_lock();
0a7de745 567 if (p != proc_ref_locked(p)) {
ff6e181a 568 p = PROC_NULL;
0a7de745 569 }
2d21ac55 570 proc_list_unlock();
0a7de745 571 return p;
ff6e181a
A
572}
573
2d21ac55 574
6d2010ae
A
575proc_t
576proc_ref_locked(proc_t p)
ff6e181a 577{
2d21ac55 578 proc_t p1 = p;
5ba3f43e 579 int pid = proc_pid(p);
0a7de745 580
743345f9 581retry:
5ba3f43e
A
582 /*
583 * if process still in creation or proc got recycled
584 * during msleep then return failure.
585 */
0a7de745
A
586 if ((p == PROC_NULL) || (p1 != p) || ((p->p_listflag & P_LIST_INCREATE) != 0)) {
587 return PROC_NULL;
588 }
5ba3f43e 589
743345f9
A
590 /*
591 * Do not return process marked for termination
592 * or proc_refdrain called without ref wait.
593 * Wait for proc_refdrain_with_refwait to complete if
813fb2f6
A
594 * process in refdrain and refwait flag is set, unless
595 * the current thread is holding to a proc_ref
596 * for any proc.
743345f9
A
597 */
598 if ((p->p_stat != SZOMB) &&
599 ((p->p_listflag & P_LIST_EXITED) == 0) &&
600 ((p->p_listflag & P_LIST_DEAD) == 0) &&
601 (((p->p_listflag & (P_LIST_DRAIN | P_LIST_DRAINWAIT)) == 0) ||
0a7de745 602 ((p->p_listflag & P_LIST_REFWAIT) != 0))) {
813fb2f6 603 if ((p->p_listflag & P_LIST_REFWAIT) != 0 && uthread_needs_to_wait_in_proc_refwait()) {
c3c9b80d 604 msleep(&p->p_listflag, &proc_list_mlock, 0, "proc_refwait", 0);
5ba3f43e
A
605 /*
606 * the proc might have been recycled since we dropped
607 * the proc list lock, get the proc again.
608 */
609 p = pfind_locked(pid);
743345f9
A
610 goto retry;
611 }
2d21ac55 612 p->p_refcount++;
3e170ce0 613 record_procref(p, 1);
0a7de745 614 } else {
2d21ac55 615 p1 = PROC_NULL;
0a7de745 616 }
ff6e181a 617
0a7de745 618 return p1;
ff6e181a
A
619}
620
2d21ac55
A
621void
622proc_rele_locked(proc_t p)
623{
2d21ac55
A
624 if (p->p_refcount > 0) {
625 p->p_refcount--;
3e170ce0 626 record_procref(p, -1);
2d21ac55
A
627 if ((p->p_refcount == 0) && ((p->p_listflag & P_LIST_DRAINWAIT) == P_LIST_DRAINWAIT)) {
628 p->p_listflag &= ~P_LIST_DRAINWAIT;
629 wakeup(&p->p_refcount);
630 }
0a7de745 631 } else {
2d21ac55 632 panic("proc_rele_locked -ve ref\n");
0a7de745 633 }
2d21ac55
A
634}
635
6d2010ae 636proc_t
2d21ac55 637proc_find_zombref(int pid)
ff6e181a 638{
39236c6e 639 proc_t p;
ff6e181a 640
2d21ac55 641 proc_list_lock();
ff6e181a 642
0a7de745 643again:
2d21ac55
A
644 p = pfind_locked(pid);
645
39236c6e 646 /* should we bail? */
0a7de745
A
647 if ((p == PROC_NULL) /* not found */
648 || ((p->p_listflag & P_LIST_INCREATE) != 0) /* not created yet */
649 || ((p->p_listflag & P_LIST_EXITED) == 0)) { /* not started exit */
2d21ac55 650 proc_list_unlock();
0a7de745 651 return PROC_NULL;
2d21ac55
A
652 }
653
39236c6e
A
654 /* If someone else is controlling the (unreaped) zombie - wait */
655 if ((p->p_listflag & P_LIST_WAITING) != 0) {
c3c9b80d 656 (void)msleep(&p->p_stat, &proc_list_mlock, PWAIT, "waitcoll", 0);
39236c6e
A
657 goto again;
658 }
659 p->p_listflag |= P_LIST_WAITING;
ff6e181a 660
2d21ac55
A
661 proc_list_unlock();
662
0a7de745 663 return p;
ff6e181a
A
664}
665
6d2010ae 666void
2d21ac55
A
667proc_drop_zombref(proc_t p)
668{
669 proc_list_lock();
0a7de745 670 if ((p->p_listflag & P_LIST_WAITING) == P_LIST_WAITING) {
2d21ac55
A
671 p->p_listflag &= ~P_LIST_WAITING;
672 wakeup(&p->p_stat);
673 }
674 proc_list_unlock();
675}
676
677
ff6e181a 678void
2d21ac55
A
679proc_refdrain(proc_t p)
680{
743345f9
A
681 proc_refdrain_with_refwait(p, FALSE);
682}
2d21ac55 683
743345f9
A
684proc_t
685proc_refdrain_with_refwait(proc_t p, boolean_t get_ref_and_allow_wait)
686{
687 boolean_t initexec = FALSE;
2d21ac55
A
688 proc_list_lock();
689
690 p->p_listflag |= P_LIST_DRAIN;
743345f9
A
691 if (get_ref_and_allow_wait) {
692 /*
693 * All the calls to proc_ref_locked will wait
813fb2f6
A
694 * for the flag to get cleared before returning a ref,
695 * unless the current thread is holding to a proc ref
696 * for any proc.
743345f9
A
697 */
698 p->p_listflag |= P_LIST_REFWAIT;
699 if (p == initproc) {
700 initexec = TRUE;
701 }
702 }
703
704 /* Do not wait in ref drain for launchd exec */
705 while (p->p_refcount && !initexec) {
2d21ac55 706 p->p_listflag |= P_LIST_DRAINWAIT;
c3c9b80d 707 msleep(&p->p_refcount, &proc_list_mlock, 0, "proc_refdrain", 0);
2d21ac55 708 }
743345f9 709
2d21ac55 710 p->p_listflag &= ~P_LIST_DRAIN;
743345f9
A
711 if (!get_ref_and_allow_wait) {
712 p->p_listflag |= P_LIST_DEAD;
713 } else {
714 /* Return a ref to the caller */
715 p->p_refcount++;
743345f9 716 record_procref(p, 1);
743345f9 717 }
2d21ac55
A
718
719 proc_list_unlock();
720
743345f9 721 if (get_ref_and_allow_wait) {
0a7de745 722 return p;
743345f9
A
723 }
724 return NULL;
725}
2d21ac55 726
743345f9
A
727void
728proc_refwake(proc_t p)
729{
730 proc_list_lock();
731 p->p_listflag &= ~P_LIST_REFWAIT;
732 wakeup(&p->p_listflag);
733 proc_list_unlock();
2d21ac55
A
734}
735
0a7de745 736proc_t
2d21ac55 737proc_parentholdref(proc_t p)
ff6e181a 738{
2d21ac55
A
739 proc_t parent = PROC_NULL;
740 proc_t pp;
741 int loopcnt = 0;
742
ff6e181a 743
2d21ac55
A
744 proc_list_lock();
745loop:
746 pp = p->p_pptr;
747 if ((pp == PROC_NULL) || (pp->p_stat == SZOMB) || ((pp->p_listflag & (P_LIST_CHILDDRSTART | P_LIST_CHILDDRAINED)) == (P_LIST_CHILDDRSTART | P_LIST_CHILDDRAINED))) {
748 parent = PROC_NULL;
749 goto out;
750 }
0a7de745 751
2d21ac55
A
752 if ((pp->p_listflag & (P_LIST_CHILDDRSTART | P_LIST_CHILDDRAINED)) == P_LIST_CHILDDRSTART) {
753 pp->p_listflag |= P_LIST_CHILDDRWAIT;
c3c9b80d 754 msleep(&pp->p_childrencnt, &proc_list_mlock, 0, "proc_parent", 0);
2d21ac55
A
755 loopcnt++;
756 if (loopcnt == 5) {
757 parent = PROC_NULL;
758 goto out;
759 }
760 goto loop;
761 }
ff6e181a 762
2d21ac55
A
763 if ((pp->p_listflag & (P_LIST_CHILDDRSTART | P_LIST_CHILDDRAINED)) == 0) {
764 pp->p_parentref++;
765 parent = pp;
766 goto out;
767 }
0a7de745 768
2d21ac55
A
769out:
770 proc_list_unlock();
0a7de745 771 return parent;
2d21ac55 772}
0a7de745 773int
2d21ac55
A
774proc_parentdropref(proc_t p, int listlocked)
775{
0a7de745 776 if (listlocked == 0) {
2d21ac55 777 proc_list_lock();
0a7de745 778 }
2d21ac55
A
779
780 if (p->p_parentref > 0) {
781 p->p_parentref--;
782 if ((p->p_parentref == 0) && ((p->p_listflag & P_LIST_PARENTREFWAIT) == P_LIST_PARENTREFWAIT)) {
783 p->p_listflag &= ~P_LIST_PARENTREFWAIT;
784 wakeup(&p->p_parentref);
ff6e181a 785 }
0a7de745 786 } else {
2d21ac55 787 panic("proc_parentdropref -ve ref\n");
0a7de745
A
788 }
789 if (listlocked == 0) {
2d21ac55 790 proc_list_unlock();
0a7de745 791 }
2d21ac55 792
0a7de745 793 return 0;
2d21ac55 794}
ff6e181a 795
2d21ac55
A
796void
797proc_childdrainstart(proc_t p)
798{
799#if __PROC_INTERNAL_DEBUG
0a7de745 800 if ((p->p_listflag & P_LIST_CHILDDRSTART) == P_LIST_CHILDDRSTART) {
2d21ac55 801 panic("proc_childdrainstart: childdrain already started\n");
0a7de745 802 }
2d21ac55
A
803#endif
804 p->p_listflag |= P_LIST_CHILDDRSTART;
805 /* wait for all that hold parentrefs to drop */
806 while (p->p_parentref > 0) {
807 p->p_listflag |= P_LIST_PARENTREFWAIT;
c3c9b80d 808 msleep(&p->p_parentref, &proc_list_mlock, 0, "proc_childdrainstart", 0);
2d21ac55
A
809 }
810}
811
812
813void
814proc_childdrainend(proc_t p)
815{
816#if __PROC_INTERNAL_DEBUG
0a7de745 817 if (p->p_childrencnt > 0) {
2d21ac55 818 panic("exiting: children stil hanging around\n");
0a7de745 819 }
2d21ac55
A
820#endif
821 p->p_listflag |= P_LIST_CHILDDRAINED;
0a7de745
A
822 if ((p->p_listflag & (P_LIST_CHILDLKWAIT | P_LIST_CHILDDRWAIT)) != 0) {
823 p->p_listflag &= ~(P_LIST_CHILDLKWAIT | P_LIST_CHILDDRWAIT);
2d21ac55
A
824 wakeup(&p->p_childrencnt);
825 }
ff6e181a
A
826}
827
2d21ac55 828void
593a1d5f 829proc_checkdeadrefs(__unused proc_t p)
2d21ac55 830{
593a1d5f 831#if __PROC_INTERNAL_DEBUG
0a7de745 832 if ((p->p_listflag & P_LIST_INHASH) != 0) {
b0d623f7 833 panic("proc being freed and still in hash %p: %u\n", p, p->p_listflag);
0a7de745
A
834 }
835 if (p->p_childrencnt != 0) {
b0d623f7 836 panic("proc being freed and pending children cnt %p:%d\n", p, p->p_childrencnt);
0a7de745
A
837 }
838 if (p->p_refcount != 0) {
b0d623f7 839 panic("proc being freed and pending refcount %p:%d\n", p, p->p_refcount);
0a7de745
A
840 }
841 if (p->p_parentref != 0) {
b0d623f7 842 panic("proc being freed and pending parentrefs %p:%d\n", p, p->p_parentref);
0a7de745 843 }
593a1d5f 844#endif
2d21ac55 845}
91447636 846
f427ee49
A
847
848__attribute__((always_inline, visibility("hidden")))
849void
850proc_require(proc_t proc, proc_require_flags_t flags)
851{
852 if ((flags & PROC_REQUIRE_ALLOW_NULL) && proc == PROC_NULL) {
853 return;
854 }
855 if ((flags & PROC_REQUIRE_ALLOW_KERNPROC) && proc == &proc0) {
856 return;
857 }
858 zone_id_require(ZONE_ID_PROC, sizeof(struct proc), proc);
859}
860
91447636
A
861int
862proc_pid(proc_t p)
863{
0a7de745 864 if (p != NULL) {
c3c9b80d 865 proc_require(p, PROC_REQUIRE_ALLOW_KERNPROC);
0a7de745
A
866 return p->p_pid;
867 }
3e170ce0 868 return -1;
91447636
A
869}
870
3e170ce0 871int
91447636
A
872proc_ppid(proc_t p)
873{
0a7de745 874 if (p != NULL) {
c3c9b80d 875 proc_require(p, PROC_REQUIRE_ALLOW_KERNPROC);
0a7de745
A
876 return p->p_ppid;
877 }
3e170ce0 878 return -1;
91447636
A
879}
880
cb323159
A
881int
882proc_original_ppid(proc_t p)
883{
884 if (p != NULL) {
c3c9b80d 885 proc_require(p, PROC_REQUIRE_ALLOW_KERNPROC);
cb323159
A
886 return p->p_original_ppid;
887 }
888 return -1;
889}
890
f427ee49
A
891int
892proc_starttime(proc_t p, struct timeval *tv)
893{
894 if (p != NULL && tv != NULL) {
895 tv->tv_sec = p->p_start.tv_sec;
896 tv->tv_usec = p->p_start.tv_usec;
897 return 0;
898 }
899 return EINVAL;
900}
901
39236c6e 902int
91447636
A
903proc_selfpid(void)
904{
0a7de745 905 return current_proc()->p_pid;
91447636
A
906}
907
39236c6e 908int
91447636
A
909proc_selfppid(void)
910{
0a7de745 911 return current_proc()->p_ppid;
39236c6e
A
912}
913
ea3f0419 914uint64_t
490019cf
A
915proc_selfcsflags(void)
916{
ea3f0419
A
917 return (uint64_t)current_proc()->p_csflags;
918}
919
920int
921proc_csflags(proc_t p, uint64_t *flags)
922{
923 if (p && flags) {
c3c9b80d 924 proc_require(p, PROC_REQUIRE_ALLOW_KERNPROC);
ea3f0419
A
925 *flags = (uint64_t)p->p_csflags;
926 return 0;
927 }
928 return EINVAL;
490019cf
A
929}
930
cb323159 931uint32_t
f427ee49 932proc_platform(const proc_t p)
cb323159
A
933{
934 if (p != NULL) {
935 return p->p_platform;
936 }
937 return (uint32_t)-1;
938}
939
f427ee49
A
940uint32_t
941proc_min_sdk(proc_t p)
942{
943 if (p != NULL) {
944 return p->p_min_sdk;
945 }
946 return (uint32_t)-1;
947}
948
cb323159
A
949uint32_t
950proc_sdk(proc_t p)
951{
952 if (p != NULL) {
953 return p->p_sdk;
954 }
955 return (uint32_t)-1;
956}
957
39236c6e
A
958#if CONFIG_DTRACE
959static proc_t
960dtrace_current_proc_vforking(void)
961{
962 thread_t th = current_thread();
963 struct uthread *ut = get_bsdthread_info(th);
964
965 if (ut &&
0a7de745 966 ((ut->uu_flag & (UT_VFORK | UT_VFORKING)) == (UT_VFORK | UT_VFORKING))) {
39236c6e
A
967 /*
968 * Handle the narrow window where we're in the vfork syscall,
969 * but we're not quite ready to claim (in particular, to DTrace)
970 * that we're running as the child.
971 */
0a7de745 972 return get_bsdtask_info(get_threadtask(th));
39236c6e 973 }
0a7de745 974 return current_proc();
39236c6e
A
975}
976
977int
978dtrace_proc_selfpid(void)
979{
0a7de745 980 return dtrace_current_proc_vforking()->p_pid;
2d21ac55
A
981}
982
0a7de745 983int
39236c6e
A
984dtrace_proc_selfppid(void)
985{
0a7de745 986 return dtrace_current_proc_vforking()->p_ppid;
39236c6e
A
987}
988
989uid_t
990dtrace_proc_selfruid(void)
991{
0a7de745 992 return dtrace_current_proc_vforking()->p_ruid;
39236c6e
A
993}
994#endif /* CONFIG_DTRACE */
995
0a7de745 996proc_t
2d21ac55
A
997proc_parent(proc_t p)
998{
999 proc_t parent;
1000 proc_t pp;
1001
1002 proc_list_lock();
1003loop:
1004 pp = p->p_pptr;
6d2010ae 1005 parent = proc_ref_locked(pp);
0a7de745 1006 if ((parent == PROC_NULL) && (pp != PROC_NULL) && (pp->p_stat != SZOMB) && ((pp->p_listflag & P_LIST_EXITED) != 0) && ((pp->p_listflag & P_LIST_CHILDDRAINED) == 0)) {
2d21ac55 1007 pp->p_listflag |= P_LIST_CHILDLKWAIT;
c3c9b80d 1008 msleep(&pp->p_childrencnt, &proc_list_mlock, 0, "proc_parent", 0);
2d21ac55
A
1009 goto loop;
1010 }
1011 proc_list_unlock();
0a7de745 1012 return parent;
91447636
A
1013}
1014
39236c6e
A
1015static boolean_t
1016proc_parent_is_currentproc(proc_t p)
1017{
1018 boolean_t ret = FALSE;
0a7de745 1019
39236c6e 1020 proc_list_lock();
0a7de745 1021 if (p->p_pptr == current_proc()) {
39236c6e 1022 ret = TRUE;
0a7de745 1023 }
39236c6e
A
1024
1025 proc_list_unlock();
1026 return ret;
1027}
2d21ac55 1028
91447636
A
1029void
1030proc_name(int pid, char * buf, int size)
1031{
2d21ac55 1032 proc_t p;
91447636 1033
ea3f0419
A
1034 if (size <= 0) {
1035 return;
1036 }
1037
1038 bzero(buf, size);
1039
2d21ac55
A
1040 if ((p = proc_find(pid)) != PROC_NULL) {
1041 strlcpy(buf, &p->p_comm[0], size);
1042 proc_rele(p);
91447636
A
1043 }
1044}
1045
2d21ac55
A
1046void
1047proc_name_kdp(task_t t, char * buf, int size)
1048{
1049 proc_t p = get_bsdtask_info(t);
0a7de745 1050 if (p == PROC_NULL) {
3e170ce0 1051 return;
0a7de745 1052 }
2d21ac55 1053
0a7de745 1054 if ((size_t)size > sizeof(p->p_comm)) {
3e170ce0 1055 strlcpy(buf, &p->p_name[0], MIN((int)sizeof(p->p_name), size));
0a7de745 1056 } else {
3e170ce0 1057 strlcpy(buf, &p->p_comm[0], MIN((int)sizeof(p->p_comm), size));
0a7de745 1058 }
2d21ac55
A
1059}
1060
cb323159
A
1061boolean_t
1062proc_binary_uuid_kdp(task_t task, uuid_t uuid)
1063{
1064 proc_t p = get_bsdtask_info(task);
1065 if (p == PROC_NULL) {
1066 return FALSE;
1067 }
1068
1069 proc_getexecutableuuid(p, uuid, sizeof(uuid_t));
1070
1071 return TRUE;
1072}
1073
fe8ab488 1074int
39037602 1075proc_threadname_kdp(void * uth, char * buf, size_t size)
fe8ab488
A
1076{
1077 if (size < MAXTHREADNAMESIZE) {
1078 /* this is really just a protective measure for the future in
1079 * case the thread name size in stackshot gets out of sync with
1080 * the BSD max thread name size. Note that bsd_getthreadname
1081 * doesn't take input buffer size into account. */
1082 return -1;
1083 }
1084
1085 if (uth != NULL) {
1086 bsd_getthreadname(uth, buf);
1087 }
1088 return 0;
1089}
1090
a39ff7e2 1091
fe8ab488
A
1092/* note that this function is generally going to be called from stackshot,
1093 * and the arguments will be coming from a struct which is declared packed
1094 * thus the input arguments will in general be unaligned. We have to handle
1095 * that here. */
1096void
a39ff7e2 1097proc_starttime_kdp(void *p, unaligned_u64 *tv_sec, unaligned_u64 *tv_usec, unaligned_u64 *abstime)
fe8ab488
A
1098{
1099 proc_t pp = (proc_t)p;
fe8ab488 1100 if (pp != PROC_NULL) {
0a7de745 1101 if (tv_sec != NULL) {
a39ff7e2 1102 *tv_sec = pp->p_start.tv_sec;
0a7de745
A
1103 }
1104 if (tv_usec != NULL) {
a39ff7e2 1105 *tv_usec = pp->p_start.tv_usec;
0a7de745 1106 }
39037602 1107 if (abstime != NULL) {
0a7de745 1108 if (pp->p_stats != NULL) {
39037602 1109 *abstime = pp->p_stats->ps_start;
0a7de745 1110 } else {
39037602 1111 *abstime = 0;
0a7de745 1112 }
39037602 1113 }
fe8ab488
A
1114 }
1115}
1116
f427ee49
A
1117void
1118proc_archinfo_kdp(void* p, cpu_type_t* cputype, cpu_subtype_t* cpusubtype)
1119{
1120 proc_t pp = (proc_t)p;
1121 if (pp != PROC_NULL) {
1122 *cputype = pp->p_cputype;
1123 *cpusubtype = pp->p_cpusubtype;
1124 }
1125}
1126
2d21ac55
A
1127char *
1128proc_name_address(void *p)
1129{
1130 return &((proc_t)p)->p_comm[0];
1131}
1132
f427ee49
A
1133char *
1134proc_longname_address(void *p)
1135{
1136 return &((proc_t)p)->p_name[0];
1137}
1138
39037602
A
1139char *
1140proc_best_name(proc_t p)
1141{
f427ee49 1142 if (p->p_name[0] != '\0') {
0a7de745
A
1143 return &p->p_name[0];
1144 }
1145 return &p->p_comm[0];
39037602
A
1146}
1147
91447636
A
1148void
1149proc_selfname(char * buf, int size)
1150{
2d21ac55 1151 proc_t p;
91447636 1152
0a7de745 1153 if ((p = current_proc()) != (proc_t)0) {
2d21ac55 1154 strlcpy(buf, &p->p_comm[0], size);
91447636
A
1155 }
1156}
1157
1158void
1159proc_signal(int pid, int signum)
1160{
1161 proc_t p;
1162
2d21ac55 1163 if ((p = proc_find(pid)) != PROC_NULL) {
0a7de745
A
1164 psignal(p, signum);
1165 proc_rele(p);
1166 }
91447636
A
1167}
1168
1169int
1170proc_issignal(int pid, sigset_t mask)
1171{
1172 proc_t p;
0a7de745 1173 int error = 0;
91447636 1174
2d21ac55
A
1175 if ((p = proc_find(pid)) != PROC_NULL) {
1176 error = proc_pendingsignals(p, mask);
1177 proc_rele(p);
0a7de745 1178 }
2d21ac55 1179
0a7de745 1180 return error;
91447636
A
1181}
1182
1183int
1184proc_noremotehang(proc_t p)
1185{
1186 int retval = 0;
1187
0a7de745 1188 if (p) {
91447636 1189 retval = p->p_flag & P_NOREMOTEHANG;
0a7de745
A
1190 }
1191 return retval? 1: 0;
91447636
A
1192}
1193
1194int
1195proc_exiting(proc_t p)
1196{
1197 int retval = 0;
1198
0a7de745 1199 if (p) {
2d21ac55 1200 retval = p->p_lflag & P_LEXIT;
0a7de745
A
1201 }
1202 return retval? 1: 0;
91447636
A
1203}
1204
d9a64523
A
1205int
1206proc_in_teardown(proc_t p)
1207{
1208 int retval = 0;
1209
0a7de745 1210 if (p) {
d9a64523 1211 retval = p->p_lflag & P_LPEXIT;
0a7de745
A
1212 }
1213 return retval? 1: 0;
d9a64523
A
1214}
1215
91447636
A
1216int
1217proc_forcequota(proc_t p)
1218{
1219 int retval = 0;
1220
0a7de745 1221 if (p) {
91447636 1222 retval = p->p_flag & P_FORCEQUOTA;
0a7de745
A
1223 }
1224 return retval? 1: 0;
91447636
A
1225}
1226
91447636
A
1227int
1228proc_suser(proc_t p)
1229{
2d21ac55
A
1230 kauth_cred_t my_cred;
1231 int error;
1232
1233 my_cred = kauth_cred_proc_ref(p);
1234 error = suser(my_cred, &p->p_acflag);
1235 kauth_cred_unref(&my_cred);
0a7de745 1236 return error;
91447636
A
1237}
1238
316670eb
A
1239task_t
1240proc_task(proc_t proc)
1241{
1242 return (task_t)proc->task;
1243}
1244
0a7de745 1245/*
2d21ac55
A
1246 * Obtain the first thread in a process
1247 *
1248 * XXX This is a bad thing to do; it exists predominantly to support the
1249 * XXX use of proc_t's in places that should really be using
1250 * XXX thread_t's instead. This maintains historical behaviour, but really
1251 * XXX needs an audit of the context (proxy vs. not) to clean up.
1252 */
1253thread_t
0a7de745
A
1254proc_thread(proc_t proc)
1255{
f427ee49
A
1256 LCK_MTX_ASSERT(&proc->p_mlock, LCK_MTX_ASSERT_OWNED);
1257
0a7de745 1258 uthread_t uth = TAILQ_FIRST(&proc->p_uthlist);
2d21ac55 1259
0a7de745
A
1260 if (uth != NULL) {
1261 return uth->uu_context.vc_thread;
1262 }
2d21ac55 1263
0a7de745
A
1264 return NULL;
1265}
2d21ac55 1266
91447636
A
1267kauth_cred_t
1268proc_ucred(proc_t p)
1269{
0a7de745 1270 return p->p_ucred;
91447636
A
1271}
1272
b0d623f7
A
1273struct uthread *
1274current_uthread()
1275{
1276 thread_t th = current_thread();
1277
0a7de745 1278 return (struct uthread *)get_bsdthread_info(th);
b0d623f7
A
1279}
1280
1281
91447636
A
1282int
1283proc_is64bit(proc_t p)
1284{
0a7de745 1285 return IS_64BIT_PROCESS(p);
91447636
A
1286}
1287
d9a64523
A
1288int
1289proc_is64bit_data(proc_t p)
1290{
1291 assert(p->task);
1292 return (int)task_get_64bit_data(p->task);
1293}
1294
f427ee49
A
1295int
1296proc_isinitproc(proc_t p)
1297{
1298 if (initproc == NULL) {
1299 return 0;
1300 }
1301 return p == initproc;
1302}
1303
593a1d5f
A
1304int
1305proc_pidversion(proc_t p)
1306{
0a7de745 1307 return p->p_idversion;
593a1d5f
A
1308}
1309
490019cf
A
1310uint32_t
1311proc_persona_id(proc_t p)
1312{
1313 return (uint32_t)persona_id_from_proc(p);
1314}
1315
1316uint32_t
1317proc_getuid(proc_t p)
1318{
0a7de745 1319 return p->p_uid;
490019cf
A
1320}
1321
1322uint32_t
1323proc_getgid(proc_t p)
1324{
0a7de745 1325 return p->p_gid;
490019cf
A
1326}
1327
6d2010ae
A
1328uint64_t
1329proc_uniqueid(proc_t p)
1330{
0a7de745 1331 return p->p_uniqueid;
6d2010ae
A
1332}
1333
1334uint64_t
39236c6e 1335proc_puniqueid(proc_t p)
6d2010ae 1336{
0a7de745 1337 return p->p_puniqueid;
39236c6e
A
1338}
1339
3e170ce0
A
1340void
1341proc_coalitionids(__unused proc_t p, __unused uint64_t ids[COALITION_NUM_TYPES])
fe8ab488
A
1342{
1343#if CONFIG_COALITIONS
3e170ce0 1344 task_coalition_ids(p->task, ids);
fe8ab488 1345#else
0a7de745 1346 memset(ids, 0, sizeof(uint64_t[COALITION_NUM_TYPES]));
fe8ab488 1347#endif
3e170ce0 1348 return;
fe8ab488
A
1349}
1350
39236c6e
A
1351uint64_t
1352proc_was_throttled(proc_t p)
1353{
0a7de745 1354 return p->was_throttled;
39236c6e
A
1355}
1356
1357uint64_t
1358proc_did_throttle(proc_t p)
1359{
0a7de745 1360 return p->did_throttle;
6d2010ae
A
1361}
1362
593a1d5f
A
1363int
1364proc_getcdhash(proc_t p, unsigned char *cdhash)
1365{
1366 return vn_getcdhash(p->p_textvp, p->p_textoff, cdhash);
1367}
1368
cb323159
A
1369int
1370proc_exitstatus(proc_t p)
1371{
1372 return p->p_xstat & 0xffff;
1373}
1374
6d2010ae
A
1375void
1376proc_getexecutableuuid(proc_t p, unsigned char *uuidbuf, unsigned long size)
1377{
1378 if (size >= sizeof(p->p_uuid)) {
1379 memcpy(uuidbuf, p->p_uuid, sizeof(p->p_uuid));
1380 }
1381}
1382
fe8ab488
A
1383/* Return vnode for executable with an iocount. Must be released with vnode_put() */
1384vnode_t
1385proc_getexecutablevnode(proc_t p)
1386{
1387 vnode_t tvp = p->p_textvp;
1388
0a7de745 1389 if (tvp != NULLVP) {
fe8ab488
A
1390 if (vnode_getwithref(tvp) == 0) {
1391 return tvp;
1392 }
527f9951 1393 }
fe8ab488
A
1394
1395 return NULLVP;
1396}
1397
ea3f0419
A
1398int
1399proc_gettty(proc_t p, vnode_t *vp)
1400{
1401 if (!p || !vp) {
1402 return EINVAL;
1403 }
1404
1405 struct session *procsp = proc_session(p);
1406 int err = EINVAL;
1407
1408 if (procsp != SESSION_NULL) {
1409 session_lock(procsp);
1410 vnode_t ttyvp = procsp->s_ttyvp;
1411 int ttyvid = procsp->s_ttyvid;
1412 session_unlock(procsp);
1413
1414 if (ttyvp) {
1415 if (vnode_getwithvid(ttyvp, ttyvid) == 0) {
bca245ac 1416 *vp = ttyvp;
ea3f0419
A
1417 err = 0;
1418 }
1419 } else {
1420 err = ENOENT;
1421 }
1422
1423 session_rele(procsp);
1424 }
1425
1426 return err;
1427}
1428
1429int
1430proc_gettty_dev(proc_t p, dev_t *dev)
1431{
1432 struct session *procsp = proc_session(p);
1433 boolean_t has_tty = FALSE;
1434
1435 if (procsp != SESSION_NULL) {
1436 session_lock(procsp);
1437
1438 struct tty * tp = SESSION_TP(procsp);
1439 if (tp != TTY_NULL) {
1440 *dev = tp->t_dev;
1441 has_tty = TRUE;
1442 }
1443
1444 session_unlock(procsp);
1445 session_rele(procsp);
1446 }
1447
1448 if (has_tty) {
1449 return 0;
1450 } else {
1451 return EINVAL;
1452 }
1453}
1454
cb323159
A
1455int
1456proc_selfexecutableargs(uint8_t *buf, size_t *buflen)
1457{
1458 proc_t p = current_proc();
1459
1460 // buflen must always be provided
1461 if (buflen == NULL) {
1462 return EINVAL;
1463 }
1464
1465 // If a buf is provided, there must be at least enough room to fit argc
1466 if (buf && *buflen < sizeof(p->p_argc)) {
1467 return EINVAL;
1468 }
1469
1470 if (!p->user_stack) {
1471 return EINVAL;
1472 }
1473
1474 if (buf == NULL) {
1475 *buflen = p->p_argslen + sizeof(p->p_argc);
1476 return 0;
1477 }
1478
1479 // Copy in argc to the first 4 bytes
1480 memcpy(buf, &p->p_argc, sizeof(p->p_argc));
1481
1482 if (*buflen > sizeof(p->p_argc) && p->p_argslen > 0) {
1483 // See memory layout comment in kern_exec.c:exec_copyout_strings()
1484 // We want to copy starting from `p_argslen` bytes away from top of stack
1485 return copyin(p->user_stack - p->p_argslen,
1486 buf + sizeof(p->p_argc),
1487 MIN(p->p_argslen, *buflen - sizeof(p->p_argc)));
1488 } else {
1489 return 0;
1490 }
1491}
1492
1493off_t
1494proc_getexecutableoffset(proc_t p)
1495{
1496 return p->p_textoff;
1497}
6d2010ae 1498
2d21ac55
A
1499void
1500bsd_set_dependency_capable(task_t task)
1501{
0a7de745 1502 proc_t p = get_bsdtask_info(task);
2d21ac55 1503
0a7de745
A
1504 if (p) {
1505 OSBitOrAtomic(P_DEPENDENCY_CAPABLE, &p->p_flag);
1506 }
2d21ac55
A
1507}
1508
1509
0a7de745 1510#ifndef __arm__
91447636
A
1511int
1512IS_64BIT_PROCESS(proc_t p)
1513{
0a7de745
A
1514 if (p && (p->p_flag & P_LP64)) {
1515 return 1;
1516 } else {
1517 return 0;
1518 }
91447636 1519}
5ba3f43e 1520#endif
91447636 1521
1c79356b
A
1522/*
1523 * Locate a process by number
1524 */
2d21ac55
A
1525proc_t
1526pfind_locked(pid_t pid)
1c79356b 1527{
2d21ac55 1528 proc_t p;
b0d623f7 1529#if DEBUG
2d21ac55
A
1530 proc_t q;
1531#endif
1c79356b 1532
0a7de745
A
1533 if (!pid) {
1534 return kernproc;
1535 }
1c79356b 1536
2d21ac55
A
1537 for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next) {
1538 if (p->p_pid == pid) {
b0d623f7 1539#if DEBUG
2d21ac55 1540 for (q = p->p_hash.le_next; q != 0; q = q->p_hash.le_next) {
0a7de745 1541 if ((p != q) && (q->p_pid == pid)) {
b0d623f7 1542 panic("two procs with same pid %p:%p:%d:%d\n", p, q, p->p_pid, q->p_pid);
0a7de745 1543 }
2d21ac55
A
1544 }
1545#endif
0a7de745 1546 return p;
2d21ac55
A
1547 }
1548 }
0a7de745 1549 return NULL;
1c79356b
A
1550}
1551
55e303ae
A
1552/*
1553 * Locate a zombie by PID
1554 */
2d21ac55
A
1555__private_extern__ proc_t
1556pzfind(pid_t pid)
55e303ae 1557{
2d21ac55
A
1558 proc_t p;
1559
1560
1561 proc_list_lock();
55e303ae 1562
0a7de745
A
1563 for (p = zombproc.lh_first; p != 0; p = p->p_list.le_next) {
1564 if (p->p_pid == pid) {
2d21ac55 1565 break;
0a7de745
A
1566 }
1567 }
2d21ac55
A
1568
1569 proc_list_unlock();
1570
0a7de745 1571 return p;
55e303ae
A
1572}
1573
1c79356b
A
1574/*
1575 * Locate a process group by number
1576 */
2d21ac55 1577
1c79356b 1578struct pgrp *
2d21ac55 1579pgfind(pid_t pgid)
1c79356b 1580{
2d21ac55
A
1581 struct pgrp * pgrp;
1582
1583 proc_list_lock();
1584 pgrp = pgfind_internal(pgid);
0a7de745 1585 if ((pgrp == NULL) || ((pgrp->pg_listflags & PGRP_FLAG_TERMINATE) != 0)) {
2d21ac55 1586 pgrp = PGRP_NULL;
0a7de745 1587 } else {
2d21ac55 1588 pgrp->pg_refcount++;
0a7de745 1589 }
2d21ac55 1590 proc_list_unlock();
0a7de745 1591 return pgrp;
2d21ac55
A
1592}
1593
1594
1595
1596struct pgrp *
1597pgfind_internal(pid_t pgid)
1598{
1599 struct pgrp *pgrp;
1c79356b 1600
0a7de745
A
1601 for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
1602 if (pgrp->pg_id == pgid) {
1603 return pgrp;
1604 }
1605 }
1606 return NULL;
1c79356b
A
1607}
1608
2d21ac55
A
1609void
1610pg_rele(struct pgrp * pgrp)
1611{
0a7de745 1612 if (pgrp == PGRP_NULL) {
2d21ac55 1613 return;
0a7de745 1614 }
2d21ac55
A
1615 pg_rele_dropref(pgrp);
1616}
1617
1618void
1619pg_rele_dropref(struct pgrp * pgrp)
1620{
1621 proc_list_lock();
1622 if ((pgrp->pg_refcount == 1) && ((pgrp->pg_listflags & PGRP_FLAG_TERMINATE) == PGRP_FLAG_TERMINATE)) {
1623 proc_list_unlock();
1624 pgdelete_dropref(pgrp);
1625 return;
1626 }
1627
1628 pgrp->pg_refcount--;
1629 proc_list_unlock();
1630}
1631
1632struct session *
1633session_find_internal(pid_t sessid)
1634{
1635 struct session *sess;
1636
0a7de745
A
1637 for (sess = SESSHASH(sessid)->lh_first; sess != 0; sess = sess->s_hash.le_next) {
1638 if (sess->s_sid == sessid) {
1639 return sess;
1640 }
1641 }
1642 return NULL;
2d21ac55
A
1643}
1644
1645
1646/*
1647 * Make a new process ready to become a useful member of society by making it
1648 * visible in all the right places and initialize its own lists to empty.
1649 *
1650 * Parameters: parent The parent of the process to insert
1651 * child The child process to insert
1652 *
1653 * Returns: (void)
1654 *
1655 * Notes: Insert a child process into the parents process group, assign
1656 * the child the parent process pointer and PPID of the parent,
1657 * place it on the parents p_children list as a sibling,
1658 * initialize its own child list, place it in the allproc list,
1659 * insert it in the proper hash bucket, and initialize its
1660 * event list.
1661 */
1662void
1663pinsertchild(proc_t parent, proc_t child)
1664{
1665 struct pgrp * pg;
1666
1667 LIST_INIT(&child->p_children);
2d21ac55
A
1668 child->p_pptr = parent;
1669 child->p_ppid = parent->p_pid;
cb323159 1670 child->p_original_ppid = parent->p_pid;
39236c6e 1671 child->p_puniqueid = parent->p_uniqueid;
5ba3f43e 1672 child->p_xhighbits = 0;
2d21ac55
A
1673
1674 pg = proc_pgrp(parent);
1675 pgrp_add(pg, parent, child);
1676 pg_rele(pg);
1677
1678 proc_list_lock();
0a7de745 1679
39236c6e
A
1680#if CONFIG_MEMORYSTATUS
1681 memorystatus_add(child, TRUE);
1682#endif
0a7de745 1683
2d21ac55
A
1684 parent->p_childrencnt++;
1685 LIST_INSERT_HEAD(&parent->p_children, child, p_sibling);
1686
1687 LIST_INSERT_HEAD(&allproc, child, p_list);
1688 /* mark the completion of proc creation */
1689 child->p_listflag &= ~P_LIST_INCREATE;
1690
1691 proc_list_unlock();
2d21ac55 1692}
1c79356b
A
1693
1694/*
1695 * Move p to a new or existing process group (and session)
2d21ac55
A
1696 *
1697 * Returns: 0 Success
1698 * ESRCH No such process
1c79356b
A
1699 */
1700int
2d21ac55 1701enterpgrp(proc_t p, pid_t pgid, int mksess)
1c79356b 1702{
2d21ac55
A
1703 struct pgrp *pgrp;
1704 struct pgrp *mypgrp;
1705 struct session * procsp;
1706
1707 pgrp = pgfind(pgid);
1708 mypgrp = proc_pgrp(p);
1709 procsp = proc_session(p);
1c79356b
A
1710
1711#if DIAGNOSTIC
0a7de745 1712 if (pgrp != NULL && mksess) { /* firewalls */
1c79356b 1713 panic("enterpgrp: setsid into non-empty pgrp");
0a7de745
A
1714 }
1715 if (SESS_LEADER(p, procsp)) {
1c79356b 1716 panic("enterpgrp: session leader attempted setpgrp");
0a7de745 1717 }
1c79356b 1718#endif
2d21ac55 1719 if (pgrp == PGRP_NULL) {
1c79356b 1720 pid_t savepid = p->p_pid;
2d21ac55 1721 proc_t np = PROC_NULL;
1c79356b
A
1722 /*
1723 * new process group
1724 */
1725#if DIAGNOSTIC
0a7de745 1726 if (p->p_pid != pgid) {
1c79356b 1727 panic("enterpgrp: new pgrp and pid != pgid");
0a7de745 1728 }
1c79356b 1729#endif
f427ee49 1730 pgrp = zalloc_flags(pgrp_zone, Z_WAITOK | Z_ZERO);
2d21ac55 1731 if ((np = proc_find(savepid)) == NULL || np != p) {
0a7de745 1732 if (np != PROC_NULL) {
2d21ac55 1733 proc_rele(np);
0a7de745
A
1734 }
1735 if (mypgrp != PGRP_NULL) {
2d21ac55 1736 pg_rele(mypgrp);
0a7de745
A
1737 }
1738 if (procsp != SESSION_NULL) {
2d21ac55 1739 session_rele(procsp);
0a7de745 1740 }
f427ee49 1741 zfree(pgrp_zone, pgrp);
0a7de745 1742 return ESRCH;
9bccf70c 1743 }
2d21ac55 1744 proc_rele(np);
1c79356b 1745 if (mksess) {
2d21ac55 1746 struct session *sess;
1c79356b
A
1747
1748 /*
1749 * new session
1750 */
f427ee49 1751 sess = zalloc_flags(session_zone, Z_WAITOK | Z_ZERO);
1c79356b 1752 sess->s_leader = p;
9bccf70c 1753 sess->s_sid = p->p_pid;
1c79356b 1754 sess->s_count = 1;
2d21ac55 1755 sess->s_ttypgrpid = NO_PID;
0a7de745 1756
c3c9b80d 1757 lck_mtx_init(&sess->s_mlock, &proc_mlock_grp, &proc_lck_attr);
0a7de745 1758
2d21ac55 1759 bcopy(procsp->s_login, sess->s_login,
1c79356b 1760 sizeof(sess->s_login));
b0d623f7 1761 OSBitAndAtomic(~((uint32_t)P_CONTROLT), &p->p_flag);
2d21ac55
A
1762 proc_list_lock();
1763 LIST_INSERT_HEAD(SESSHASH(sess->s_sid), sess, s_hash);
1764 proc_list_unlock();
1c79356b 1765 pgrp->pg_session = sess;
f427ee49 1766 p->p_sessionid = sess->s_sid;
1c79356b 1767#if DIAGNOSTIC
0a7de745 1768 if (p != current_proc()) {
1c79356b 1769 panic("enterpgrp: mksession and p != curproc");
0a7de745 1770 }
1c79356b
A
1771#endif
1772 } else {
2d21ac55
A
1773 proc_list_lock();
1774 pgrp->pg_session = procsp;
f427ee49 1775 p->p_sessionid = procsp->s_sid;
0a7de745
A
1776
1777 if ((pgrp->pg_session->s_listflags & (S_LIST_TERM | S_LIST_DEAD)) != 0) {
1778 panic("enterpgrp: providing ref to terminating session ");
1779 }
1c79356b 1780 pgrp->pg_session->s_count++;
2d21ac55 1781 proc_list_unlock();
1c79356b
A
1782 }
1783 pgrp->pg_id = pgid;
0a7de745 1784
c3c9b80d 1785 lck_mtx_init(&pgrp->pg_mlock, &proc_mlock_grp, &proc_lck_attr);
0a7de745 1786
1c79356b 1787 LIST_INIT(&pgrp->pg_members);
2d21ac55
A
1788 proc_list_lock();
1789 pgrp->pg_refcount = 1;
2d21ac55
A
1790 LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
1791 proc_list_unlock();
1792 } else if (pgrp == mypgrp) {
1793 pg_rele(pgrp);
0a7de745 1794 if (mypgrp != NULL) {
2d21ac55 1795 pg_rele(mypgrp);
0a7de745
A
1796 }
1797 if (procsp != SESSION_NULL) {
2d21ac55 1798 session_rele(procsp);
0a7de745
A
1799 }
1800 return 0;
2d21ac55 1801 }
1c79356b 1802
0a7de745 1803 if (procsp != SESSION_NULL) {
2d21ac55 1804 session_rele(procsp);
0a7de745 1805 }
1c79356b
A
1806 /*
1807 * Adjust eligibility of affected pgrps to participate in job control.
1808 * Increment eligibility counts before decrementing, otherwise we
1809 * could reach 0 spuriously during the first call.
1810 */
1811 fixjobc(p, pgrp, 1);
2d21ac55 1812 fixjobc(p, mypgrp, 0);
1c79356b 1813
0a7de745 1814 if (mypgrp != PGRP_NULL) {
2d21ac55 1815 pg_rele(mypgrp);
0a7de745 1816 }
2d21ac55
A
1817 pgrp_replace(p, pgrp);
1818 pg_rele(pgrp);
1819
0a7de745 1820 return 0;
1c79356b
A
1821}
1822
1823/*
1824 * remove process from process group
1825 */
1826int
2d21ac55 1827leavepgrp(proc_t p)
1c79356b 1828{
2d21ac55 1829 pgrp_remove(p);
0a7de745 1830 return 0;
1c79356b
A
1831}
1832
1833/*
1834 * delete a process group
1835 */
2d21ac55
A
1836static void
1837pgdelete_dropref(struct pgrp *pgrp)
1c79356b 1838{
b0d623f7 1839 struct tty *ttyp;
2d21ac55
A
1840 int emptypgrp = 1;
1841 struct session *sessp;
1c79356b 1842
2d21ac55
A
1843
1844 pgrp_lock(pgrp);
1845 if (pgrp->pg_membercnt != 0) {
1846 emptypgrp = 0;
1847 }
1848 pgrp_unlock(pgrp);
1849
1850 proc_list_lock();
1851 pgrp->pg_refcount--;
1852 if ((emptypgrp == 0) || (pgrp->pg_membercnt != 0)) {
1853 proc_list_unlock();
1854 return;
1855 }
1856
1857 pgrp->pg_listflags |= PGRP_FLAG_TERMINATE;
0a7de745 1858
2d21ac55
A
1859 if (pgrp->pg_refcount > 0) {
1860 proc_list_unlock();
1861 return;
91447636 1862 }
2d21ac55
A
1863
1864 pgrp->pg_listflags |= PGRP_FLAG_DEAD;
1c79356b 1865 LIST_REMOVE(pgrp, pg_hash);
2d21ac55
A
1866
1867 proc_list_unlock();
0a7de745 1868
b0d623f7
A
1869 ttyp = SESSION_TP(pgrp->pg_session);
1870 if (ttyp != TTY_NULL) {
1871 if (ttyp->t_pgrp == pgrp) {
1872 tty_lock(ttyp);
1873 /* Re-check after acquiring the lock */
1874 if (ttyp->t_pgrp == pgrp) {
1875 ttyp->t_pgrp = NULL;
1876 pgrp->pg_session->s_ttypgrpid = NO_PID;
1877 }
1878 tty_unlock(ttyp);
1879 }
91447636 1880 }
2d21ac55
A
1881
1882 proc_list_lock();
1883
1884 sessp = pgrp->pg_session;
0a7de745
A
1885 if ((sessp->s_listflags & (S_LIST_TERM | S_LIST_DEAD)) != 0) {
1886 panic("pg_deleteref: manipulating refs of already terminating session");
1887 }
2d21ac55 1888 if (--sessp->s_count == 0) {
0a7de745 1889 if ((sessp->s_listflags & (S_LIST_TERM | S_LIST_DEAD)) != 0) {
2d21ac55 1890 panic("pg_deleteref: terminating already terminated session");
0a7de745 1891 }
2d21ac55 1892 sessp->s_listflags |= S_LIST_TERM;
b0d623f7 1893 ttyp = SESSION_TP(sessp);
2d21ac55
A
1894 LIST_REMOVE(sessp, s_hash);
1895 proc_list_unlock();
b0d623f7
A
1896 if (ttyp != TTY_NULL) {
1897 tty_lock(ttyp);
0a7de745 1898 if (ttyp->t_session == sessp) {
b0d623f7 1899 ttyp->t_session = NULL;
0a7de745 1900 }
b0d623f7
A
1901 tty_unlock(ttyp);
1902 }
2d21ac55
A
1903 proc_list_lock();
1904 sessp->s_listflags |= S_LIST_DEAD;
0a7de745
A
1905 if (sessp->s_count != 0) {
1906 panic("pg_deleteref: freeing session in use");
1907 }
2d21ac55 1908 proc_list_unlock();
c3c9b80d 1909 lck_mtx_destroy(&sessp->s_mlock, &proc_mlock_grp);
0a7de745 1910
f427ee49 1911 zfree(session_zone, sessp);
0a7de745 1912 } else {
2d21ac55 1913 proc_list_unlock();
0a7de745 1914 }
c3c9b80d 1915 lck_mtx_destroy(&pgrp->pg_mlock, &proc_mlock_grp);
f427ee49 1916 zfree(pgrp_zone, pgrp);
1c79356b
A
1917}
1918
1c79356b 1919
1c79356b
A
1920/*
1921 * Adjust pgrp jobc counters when specified process changes process group.
1922 * We count the number of processes in each process group that "qualify"
1923 * the group for terminal job control (those with a parent in a different
1924 * process group of the same session). If that count reaches zero, the
1925 * process group becomes orphaned. Check both the specified process'
1926 * process group and that of its children.
1927 * entering == 0 => p is leaving specified group.
1928 * entering == 1 => p is entering specified group.
1929 */
2d21ac55
A
1930int
1931fixjob_callback(proc_t p, void * arg)
1c79356b 1932{
2d21ac55
A
1933 struct fixjob_iterargs *fp;
1934 struct pgrp * pg, *hispg;
1935 struct session * mysession, *hissess;
1936 int entering;
1937
1938 fp = (struct fixjob_iterargs *)arg;
1939 pg = fp->pg;
1940 mysession = fp->mysession;
1941 entering = fp->entering;
1942
1943 hispg = proc_pgrp(p);
1944 hissess = proc_session(p);
1945
0a7de745 1946 if ((hispg != pg) &&
2d21ac55
A
1947 (hissess == mysession)) {
1948 pgrp_lock(hispg);
1949 if (entering) {
1950 hispg->pg_jobc++;
1951 pgrp_unlock(hispg);
1952 } else if (--hispg->pg_jobc == 0) {
1953 pgrp_unlock(hispg);
1954 orphanpg(hispg);
0a7de745 1955 } else {
2d21ac55 1956 pgrp_unlock(hispg);
0a7de745 1957 }
2d21ac55 1958 }
0a7de745 1959 if (hissess != SESSION_NULL) {
2d21ac55 1960 session_rele(hissess);
0a7de745
A
1961 }
1962 if (hispg != PGRP_NULL) {
2d21ac55 1963 pg_rele(hispg);
0a7de745 1964 }
1c79356b 1965
0a7de745 1966 return PROC_RETURNED;
2d21ac55
A
1967}
1968
1969void
1970fixjobc(proc_t p, struct pgrp *pgrp, int entering)
1971{
1972 struct pgrp *hispgrp = PGRP_NULL;
1973 struct session *hissess = SESSION_NULL;
1974 struct session *mysession = pgrp->pg_session;
1975 proc_t parent;
1976 struct fixjob_iterargs fjarg;
39236c6e
A
1977 boolean_t proc_parent_self;
1978
1979 /*
0a7de745
A
1980 * Check if p's parent is current proc, if yes then no need to take
1981 * a ref; calling proc_parent with current proc as parent may
39236c6e
A
1982 * deadlock if current proc is exiting.
1983 */
1984 proc_parent_self = proc_parent_is_currentproc(p);
0a7de745 1985 if (proc_parent_self) {
39236c6e 1986 parent = current_proc();
0a7de745 1987 } else {
39236c6e 1988 parent = proc_parent(p);
0a7de745 1989 }
2d21ac55 1990
2d21ac55 1991 if (parent != PROC_NULL) {
0a7de745 1992 hispgrp = proc_pgrp(parent);
2d21ac55 1993 hissess = proc_session(parent);
0a7de745 1994 if (!proc_parent_self) {
39236c6e 1995 proc_rele(parent);
0a7de745 1996 }
2d21ac55
A
1997 }
1998
1999
2000 /*
2001 * Check p's parent to see whether p qualifies its own process
1c79356b
A
2002 * group; if so, adjust count for p's process group.
2003 */
2d21ac55
A
2004 if ((hispgrp != pgrp) &&
2005 (hissess == mysession)) {
2006 pgrp_lock(pgrp);
2007 if (entering) {
1c79356b 2008 pgrp->pg_jobc++;
2d21ac55 2009 pgrp_unlock(pgrp);
0a7de745 2010 } else if (--pgrp->pg_jobc == 0) {
2d21ac55 2011 pgrp_unlock(pgrp);
1c79356b 2012 orphanpg(pgrp);
0a7de745 2013 } else {
2d21ac55 2014 pgrp_unlock(pgrp);
0a7de745 2015 }
e5568f75 2016 }
1c79356b 2017
0a7de745 2018 if (hissess != SESSION_NULL) {
2d21ac55 2019 session_rele(hissess);
0a7de745
A
2020 }
2021 if (hispgrp != PGRP_NULL) {
2d21ac55 2022 pg_rele(hispgrp);
0a7de745 2023 }
2d21ac55 2024
1c79356b
A
2025 /*
2026 * Check this process' children to see whether they qualify
2027 * their process groups; if so, adjust counts for children's
2028 * process groups.
2029 */
2d21ac55
A
2030 fjarg.pg = pgrp;
2031 fjarg.mysession = mysession;
2032 fjarg.entering = entering;
2033 proc_childrenwalk(p, fixjob_callback, &fjarg);
e5568f75 2034}
1c79356b 2035
cb323159
A
2036/*
2037 * The pidlist_* routines support the functions in this file that
2038 * walk lists of processes applying filters and callouts to the
2039 * elements of the list.
2040 *
2041 * A prior implementation used a single linear array, which can be
2042 * tricky to allocate on large systems. This implementation creates
2043 * an SLIST of modestly sized arrays of PIDS_PER_ENTRY elements.
2044 *
2045 * The array should be sized large enough to keep the overhead of
2046 * walking the list low, but small enough that blocking allocations of
2047 * pidlist_entry_t structures always succeed.
2048 */
2049
2050#define PIDS_PER_ENTRY 1021
2051
2052typedef struct pidlist_entry {
2053 SLIST_ENTRY(pidlist_entry) pe_link;
2054 u_int pe_nused;
2055 pid_t pe_pid[PIDS_PER_ENTRY];
2056} pidlist_entry_t;
2057
2058typedef struct {
2059 SLIST_HEAD(, pidlist_entry) pl_head;
2060 struct pidlist_entry *pl_active;
2061 u_int pl_nalloc;
2062} pidlist_t;
2063
2064static __inline__ pidlist_t *
2065pidlist_init(pidlist_t *pl)
2066{
2067 SLIST_INIT(&pl->pl_head);
2068 pl->pl_active = NULL;
2069 pl->pl_nalloc = 0;
2070 return pl;
2071}
2072
2073static u_int
2074pidlist_alloc(pidlist_t *pl, u_int needed)
2075{
2076 while (pl->pl_nalloc < needed) {
f427ee49
A
2077 pidlist_entry_t *pe = kheap_alloc(KHEAP_TEMP, sizeof(*pe),
2078 Z_WAITOK | Z_ZERO);
cb323159
A
2079 if (NULL == pe) {
2080 panic("no space for pidlist entry");
2081 }
cb323159
A
2082 SLIST_INSERT_HEAD(&pl->pl_head, pe, pe_link);
2083 pl->pl_nalloc += (sizeof(pe->pe_pid) / sizeof(pe->pe_pid[0]));
2084 }
2085 return pl->pl_nalloc;
2086}
2087
2088static void
2089pidlist_free(pidlist_t *pl)
2090{
2091 pidlist_entry_t *pe;
2092 while (NULL != (pe = SLIST_FIRST(&pl->pl_head))) {
2093 SLIST_FIRST(&pl->pl_head) = SLIST_NEXT(pe, pe_link);
f427ee49 2094 kheap_free(KHEAP_TEMP, pe, sizeof(*pe));
cb323159
A
2095 }
2096 pl->pl_nalloc = 0;
2097}
2098
2099static __inline__ void
2100pidlist_set_active(pidlist_t *pl)
2101{
2102 pl->pl_active = SLIST_FIRST(&pl->pl_head);
2103 assert(pl->pl_active);
2104}
2105
2106static void
2107pidlist_add_pid(pidlist_t *pl, pid_t pid)
2108{
2109 pidlist_entry_t *pe = pl->pl_active;
2110 if (pe->pe_nused >= sizeof(pe->pe_pid) / sizeof(pe->pe_pid[0])) {
2111 if (NULL == (pe = SLIST_NEXT(pe, pe_link))) {
2112 panic("pidlist allocation exhausted");
2113 }
2114 pl->pl_active = pe;
2115 }
2116 pe->pe_pid[pe->pe_nused++] = pid;
2117}
2118
2119static __inline__ u_int
2120pidlist_nalloc(const pidlist_t *pl)
2121{
2122 return pl->pl_nalloc;
2123}
2124
39037602
A
2125/*
2126 * A process group has become orphaned; if there are any stopped processes in
2127 * the group, hang-up all process in that group.
1c79356b
A
2128 */
2129static void
39037602 2130orphanpg(struct pgrp *pgrp)
1c79356b 2131{
cb323159
A
2132 pidlist_t pid_list, *pl = pidlist_init(&pid_list);
2133 u_int pid_count_available = 0;
2d21ac55 2134 proc_t p;
39037602
A
2135
2136 /* allocate outside of the pgrp_lock */
2137 for (;;) {
2138 pgrp_lock(pgrp);
2139
2140 boolean_t should_iterate = FALSE;
2141 pid_count_available = 0;
2142
2143 PGMEMBERS_FOREACH(pgrp, p) {
2144 pid_count_available++;
39037602
A
2145 if (p->p_stat == SSTOP) {
2146 should_iterate = TRUE;
2147 }
2148 }
39037602
A
2149 if (pid_count_available == 0 || !should_iterate) {
2150 pgrp_unlock(pgrp);
cb323159 2151 goto out; /* no orphaned processes OR nothing stopped */
39037602 2152 }
cb323159 2153 if (pidlist_nalloc(pl) >= pid_count_available) {
39037602
A
2154 break;
2155 }
2156 pgrp_unlock(pgrp);
2157
cb323159 2158 pidlist_alloc(pl, pid_count_available);
39037602 2159 }
cb323159 2160 pidlist_set_active(pl);
39037602 2161
cb323159 2162 u_int pid_count = 0;
39037602 2163 PGMEMBERS_FOREACH(pgrp, p) {
cb323159
A
2164 pidlist_add_pid(pl, proc_pid(p));
2165 if (++pid_count >= pid_count_available) {
39037602 2166 break;
1c79356b
A
2167 }
2168 }
2d21ac55 2169 pgrp_unlock(pgrp);
2d21ac55 2170
cb323159
A
2171 const pidlist_entry_t *pe;
2172 SLIST_FOREACH(pe, &(pl->pl_head), pe_link) {
2173 for (u_int i = 0; i < pe->pe_nused; i++) {
2174 const pid_t pid = pe->pe_pid[i];
2175 if (0 == pid) {
2176 continue; /* skip kernproc */
2177 }
2178 p = proc_find(pid);
2179 if (!p) {
2180 continue;
2181 }
2182 proc_transwait(p, 0);
2183 pt_setrunnable(p);
2184 psignal(p, SIGHUP);
2185 psignal(p, SIGCONT);
2186 proc_rele(p);
2d21ac55
A
2187 }
2188 }
2189out:
cb323159 2190 pidlist_free(pl);
1c79356b 2191}
2d21ac55 2192
f427ee49
A
2193boolean_t
2194proc_is_translated(proc_t p __unused)
2195{
2196 return 0;
2197}
2198
55e303ae 2199int
3e170ce0 2200proc_is_classic(proc_t p __unused)
55e303ae 2201{
0a7de745 2202 return 0;
55e303ae
A
2203}
2204
f427ee49
A
2205bool
2206proc_is_exotic(
2207 proc_t p)
2208{
2209 if (p == NULL) {
2210 return false;
2211 }
2212 return task_is_exotic(proc_task(p));
2213}
2214
2215bool
2216proc_is_alien(
2217 proc_t p)
2218{
2219 if (p == NULL) {
2220 return false;
2221 }
2222 return task_is_alien(proc_task(p));
2223}
2224
e5568f75 2225/* XXX Why does this function exist? Need to kill it off... */
2d21ac55 2226proc_t
e5568f75 2227current_proc_EXTERNAL(void)
1c79356b 2228{
0a7de745 2229 return current_proc();
1c79356b 2230}
e5568f75 2231
39236c6e
A
2232int
2233proc_is_forcing_hfs_case_sensitivity(proc_t p)
2234{
2235 return (p->p_vfs_iopolicy & P_VFS_IOPOLICY_FORCE_HFS_CASE_SENSITIVITY) ? 1 : 0;
2236}
2237
f427ee49
A
2238bool
2239proc_ignores_content_protection(proc_t p)
2240{
2241 return os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_IGNORE_CONTENT_PROTECTION;
2242}
2243
c3c9b80d
A
2244bool
2245proc_ignores_node_permissions(proc_t p)
2246{
2247 return os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_IGNORE_NODE_PERMISSIONS;
2248}
2249
2250bool
2251proc_skip_mtime_update(proc_t p)
2252{
2253 return os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_SKIP_MTIME_UPDATE;
2254}
2255
39037602 2256#if CONFIG_COREDUMP
e5568f75
A
2257/*
2258 * proc_core_name(name, uid, pid)
2259 * Expand the name described in corefilename, using name, uid, and pid.
2260 * corefilename is a printf-like string, with three format specifiers:
2261 * %N name of process ("name")
2262 * %P process id (pid)
2263 * %U user id (uid)
2264 * For example, "%N.core" is the default; they can be disabled completely
2265 * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
2266 * This is controlled by the sysctl variable kern.corefile (see above).
2267 */
2d21ac55
A
2268__private_extern__ int
2269proc_core_name(const char *name, uid_t uid, pid_t pid, char *cf_name,
0a7de745 2270 size_t cf_name_len)
e5568f75
A
2271{
2272 const char *format, *appendstr;
0a7de745 2273 char id_buf[11]; /* Buffer for pid/uid -- max 4B */
e5568f75
A
2274 size_t i, l, n;
2275
0a7de745 2276 if (cf_name == NULL) {
2d21ac55 2277 goto toolong;
0a7de745 2278 }
2d21ac55 2279
e5568f75 2280 format = corefilename;
2d21ac55 2281 for (i = 0, n = 0; n < cf_name_len && format[i]; i++) {
e5568f75 2282 switch (format[i]) {
0a7de745 2283 case '%': /* Format character */
e5568f75
A
2284 i++;
2285 switch (format[i]) {
2286 case '%':
2287 appendstr = "%";
2288 break;
0a7de745 2289 case 'N': /* process name */
e5568f75
A
2290 appendstr = name;
2291 break;
0a7de745 2292 case 'P': /* process id */
2d21ac55 2293 snprintf(id_buf, sizeof(id_buf), "%u", pid);
e5568f75
A
2294 appendstr = id_buf;
2295 break;
0a7de745 2296 case 'U': /* user id */
2d21ac55 2297 snprintf(id_buf, sizeof(id_buf), "%u", uid);
e5568f75
A
2298 appendstr = id_buf;
2299 break;
39037602
A
2300 case '\0': /* format string ended in % symbol */
2301 goto endofstring;
e5568f75
A
2302 default:
2303 appendstr = "";
0a7de745 2304 log(LOG_ERR,
e5568f75
A
2305 "Unknown format character %c in `%s'\n",
2306 format[i], format);
2307 }
2308 l = strlen(appendstr);
0a7de745 2309 if ((n + l) >= cf_name_len) {
e5568f75 2310 goto toolong;
0a7de745 2311 }
2d21ac55 2312 bcopy(appendstr, cf_name + n, l);
e5568f75
A
2313 n += l;
2314 break;
2315 default:
2d21ac55 2316 cf_name[n++] = format[i];
e5568f75
A
2317 }
2318 }
0a7de745 2319 if (format[i] != '\0') {
e5568f75 2320 goto toolong;
0a7de745
A
2321 }
2322 return 0;
e5568f75 2323toolong:
b0d623f7
A
2324 log(LOG_ERR, "pid %ld (%s), uid (%u): corename is too long\n",
2325 (long)pid, name, (uint32_t)uid);
0a7de745 2326 return 1;
39037602
A
2327endofstring:
2328 log(LOG_ERR, "pid %ld (%s), uid (%u): unexpected end of string after %% token\n",
2329 (long)pid, name, (uint32_t)uid);
0a7de745 2330 return 1;
2d21ac55 2331}
39037602 2332#endif /* CONFIG_COREDUMP */
2d21ac55 2333
2d21ac55
A
2334/* Code Signing related routines */
2335
0a7de745 2336int
b0d623f7 2337csops(__unused proc_t p, struct csops_args *uap, __unused int32_t *retval)
2d21ac55 2338{
0a7de745
A
2339 return csops_internal(uap->pid, uap->ops, uap->useraddr,
2340 uap->usersize, USER_ADDR_NULL);
316670eb
A
2341}
2342
0a7de745 2343int
316670eb
A
2344csops_audittoken(__unused proc_t p, struct csops_audittoken_args *uap, __unused int32_t *retval)
2345{
0a7de745
A
2346 if (uap->uaudittoken == USER_ADDR_NULL) {
2347 return EINVAL;
2348 }
2349 return csops_internal(uap->pid, uap->ops, uap->useraddr,
2350 uap->usersize, uap->uaudittoken);
316670eb
A
2351}
2352
39236c6e
A
2353static int
2354csops_copy_token(void *start, size_t length, user_size_t usize, user_addr_t uaddr)
2355{
2356 char fakeheader[8] = { 0 };
2357 int error;
2358
0a7de745 2359 if (usize < sizeof(fakeheader)) {
39236c6e 2360 return ERANGE;
0a7de745 2361 }
39236c6e
A
2362
2363 /* if no blob, fill in zero header */
2364 if (NULL == start) {
2365 start = fakeheader;
2366 length = sizeof(fakeheader);
2367 } else if (usize < length) {
2368 /* ... if input too short, copy out length of entitlement */
2369 uint32_t length32 = htonl((uint32_t)length);
2370 memcpy(&fakeheader[4], &length32, sizeof(length32));
0a7de745 2371
39236c6e 2372 error = copyout(fakeheader, uaddr, sizeof(fakeheader));
0a7de745 2373 if (error == 0) {
39236c6e 2374 return ERANGE; /* input buffer to short, ERANGE signals that */
0a7de745 2375 }
39236c6e
A
2376 return error;
2377 }
2378 return copyout(start, uaddr, length);
2379}
2380
316670eb
A
2381static int
2382csops_internal(pid_t pid, int ops, user_addr_t uaddr, user_size_t usersize, user_addr_t uaudittoken)
2383{
2384 size_t usize = (size_t)CAST_DOWN(size_t, usersize);
2d21ac55 2385 proc_t pt;
39236c6e 2386 int forself;
2d21ac55
A
2387 int error;
2388 vnode_t tvp;
2389 off_t toff;
2d21ac55 2390 unsigned char cdhash[SHA1_RESULTLEN];
316670eb 2391 audit_token_t token;
0a7de745
A
2392 unsigned int upid = 0, uidversion = 0;
2393
2d21ac55
A
2394 forself = error = 0;
2395
0a7de745 2396 if (pid == 0) {
2d21ac55 2397 pid = proc_selfpid();
0a7de745
A
2398 }
2399 if (pid == proc_selfpid()) {
2d21ac55 2400 forself = 1;
0a7de745 2401 }
2d21ac55
A
2402
2403
39236c6e 2404 switch (ops) {
0a7de745
A
2405 case CS_OPS_STATUS:
2406 case CS_OPS_CDHASH:
2407 case CS_OPS_PIDOFFSET:
2408 case CS_OPS_ENTITLEMENTS_BLOB:
2409 case CS_OPS_IDENTITY:
2410 case CS_OPS_BLOB:
2411 case CS_OPS_TEAMID:
4ba76501 2412 case CS_OPS_CLEAR_LV:
0a7de745
A
2413 break; /* not restricted to root */
2414 default:
2415 if (forself == 0 && kauth_cred_issuser(kauth_cred_get()) != TRUE) {
2416 return EPERM;
2417 }
2418 break;
2d21ac55
A
2419 }
2420
2421 pt = proc_find(pid);
0a7de745
A
2422 if (pt == PROC_NULL) {
2423 return ESRCH;
2424 }
2d21ac55 2425
316670eb
A
2426 upid = pt->p_pid;
2427 uidversion = pt->p_idversion;
2428 if (uaudittoken != USER_ADDR_NULL) {
316670eb 2429 error = copyin(uaudittoken, &token, sizeof(audit_token_t));
0a7de745 2430 if (error != 0) {
316670eb 2431 goto out;
0a7de745 2432 }
316670eb
A
2433 /* verify the audit token pid/idversion matches with proc */
2434 if ((token.val[5] != upid) || (token.val[7] != uidversion)) {
2435 error = ESRCH;
2436 goto out;
2437 }
2438 }
2d21ac55 2439
7e41aa88
A
2440#if CONFIG_MACF
2441 switch (ops) {
0a7de745
A
2442 case CS_OPS_MARKINVALID:
2443 case CS_OPS_MARKHARD:
2444 case CS_OPS_MARKKILL:
2445 case CS_OPS_MARKRESTRICT:
2446 case CS_OPS_SET_STATUS:
2447 case CS_OPS_CLEARINSTALLER:
2448 case CS_OPS_CLEARPLATFORM:
4ba76501 2449 case CS_OPS_CLEAR_LV:
0a7de745
A
2450 if ((error = mac_proc_check_set_cs_info(current_proc(), pt, ops))) {
2451 goto out;
2452 }
2453 break;
2454 default:
2455 if ((error = mac_proc_check_get_cs_info(current_proc(), pt, ops))) {
2456 goto out;
2457 }
7e41aa88
A
2458 }
2459#endif
2460
2d21ac55 2461 switch (ops) {
0a7de745
A
2462 case CS_OPS_STATUS: {
2463 uint32_t retflags;
2d21ac55 2464
0a7de745
A
2465 proc_lock(pt);
2466 retflags = pt->p_csflags;
2467 if (cs_process_enforcement(pt)) {
2468 retflags |= CS_ENFORCEMENT;
39236c6e 2469 }
0a7de745
A
2470 if (csproc_get_platform_binary(pt)) {
2471 retflags |= CS_PLATFORM_BINARY;
2472 }
2473 if (csproc_get_platform_path(pt)) {
2474 retflags |= CS_PLATFORM_PATH;
2475 }
2476 //Don't return CS_REQUIRE_LV if we turned it on with CS_FORCED_LV but still report CS_FORCED_LV
2477 if ((pt->p_csflags & CS_FORCED_LV) == CS_FORCED_LV) {
2478 retflags &= (~CS_REQUIRE_LV);
2479 }
2480 proc_unlock(pt);
2d21ac55 2481
0a7de745
A
2482 if (uaddr != USER_ADDR_NULL) {
2483 error = copyout(&retflags, uaddr, sizeof(uint32_t));
2484 }
2485 break;
2486 }
2487 case CS_OPS_MARKINVALID:
2488 proc_lock(pt);
2489 if ((pt->p_csflags & CS_VALID) == CS_VALID) { /* is currently valid */
2490 pt->p_csflags &= ~CS_VALID; /* set invalid */
f427ee49 2491 cs_process_invalidated(pt);
0a7de745
A
2492 if ((pt->p_csflags & CS_KILL) == CS_KILL) {
2493 pt->p_csflags |= CS_KILLED;
2d21ac55 2494 proc_unlock(pt);
0a7de745
A
2495 if (cs_debug) {
2496 printf("CODE SIGNING: marked invalid by pid %d: "
2497 "p=%d[%s] honoring CS_KILL, final status 0x%x\n",
2498 proc_selfpid(), pt->p_pid, pt->p_comm, pt->p_csflags);
2499 }
2d21ac55 2500 psignal(pt, SIGKILL);
0a7de745 2501 } else {
2d21ac55 2502 proc_unlock(pt);
0a7de745
A
2503 }
2504 } else {
2505 proc_unlock(pt);
2506 }
2d21ac55 2507
0a7de745 2508 break;
2d21ac55 2509
0a7de745
A
2510 case CS_OPS_MARKHARD:
2511 proc_lock(pt);
2512 pt->p_csflags |= CS_HARD;
2513 if ((pt->p_csflags & CS_VALID) == 0) {
2514 /* @@@ allow? reject? kill? @@@ */
2515 proc_unlock(pt);
2516 error = EINVAL;
2517 goto out;
2518 } else {
2519 proc_unlock(pt);
2520 }
2521 break;
2d21ac55 2522
0a7de745
A
2523 case CS_OPS_MARKKILL:
2524 proc_lock(pt);
2525 pt->p_csflags |= CS_KILL;
2526 if ((pt->p_csflags & CS_VALID) == 0) {
2527 proc_unlock(pt);
2528 psignal(pt, SIGKILL);
2529 } else {
2530 proc_unlock(pt);
2531 }
2532 break;
2d21ac55 2533
0a7de745
A
2534 case CS_OPS_PIDOFFSET:
2535 toff = pt->p_textoff;
2536 proc_rele(pt);
2537 error = copyout(&toff, uaddr, sizeof(toff));
2538 return error;
b0d623f7 2539
0a7de745
A
2540 case CS_OPS_CDHASH:
2541
2542 /* pt already holds a reference on its p_textvp */
2543 tvp = pt->p_textvp;
2544 toff = pt->p_textoff;
2545
2546 if (tvp == NULLVP || usize != SHA1_RESULTLEN) {
2d21ac55 2547 proc_rele(pt);
0a7de745
A
2548 return EINVAL;
2549 }
2d21ac55 2550
0a7de745
A
2551 error = vn_getcdhash(tvp, toff, cdhash);
2552 proc_rele(pt);
2d21ac55 2553
0a7de745
A
2554 if (error == 0) {
2555 error = copyout(cdhash, uaddr, sizeof(cdhash));
2556 }
6d2010ae 2557
0a7de745 2558 return error;
6d2010ae 2559
0a7de745
A
2560 case CS_OPS_ENTITLEMENTS_BLOB: {
2561 void *start;
2562 size_t length;
39236c6e 2563
0a7de745 2564 proc_lock(pt);
39236c6e 2565
0a7de745 2566 if ((pt->p_csflags & (CS_VALID | CS_DEBUGGED)) == 0) {
39236c6e 2567 proc_unlock(pt);
0a7de745 2568 error = EINVAL;
39236c6e
A
2569 break;
2570 }
39236c6e 2571
0a7de745
A
2572 error = cs_entitlements_blob_get(pt, &start, &length);
2573 proc_unlock(pt);
2574 if (error) {
2575 break;
2576 }
39236c6e 2577
0a7de745
A
2578 error = csops_copy_token(start, length, usize, uaddr);
2579 break;
2580 }
2581 case CS_OPS_MARKRESTRICT:
2582 proc_lock(pt);
2583 pt->p_csflags |= CS_RESTRICT;
2584 proc_unlock(pt);
2585 break;
39236c6e 2586
0a7de745
A
2587 case CS_OPS_SET_STATUS: {
2588 uint32_t flags;
39236c6e 2589
0a7de745
A
2590 if (usize < sizeof(flags)) {
2591 error = ERANGE;
2592 break;
2593 }
39236c6e 2594
0a7de745
A
2595 error = copyin(uaddr, &flags, sizeof(flags));
2596 if (error) {
39236c6e
A
2597 break;
2598 }
39236c6e 2599
0a7de745
A
2600 /* only allow setting a subset of all code sign flags */
2601 flags &=
2602 CS_HARD | CS_EXEC_SET_HARD |
2603 CS_KILL | CS_EXEC_SET_KILL |
2604 CS_RESTRICT |
2605 CS_REQUIRE_LV |
2606 CS_ENFORCEMENT | CS_EXEC_SET_ENFORCEMENT;
2607
2608 proc_lock(pt);
2609 if (pt->p_csflags & CS_VALID) {
f427ee49
A
2610 if ((flags & CS_ENFORCEMENT) &&
2611 !(pt->p_csflags & CS_ENFORCEMENT)) {
2612 vm_map_cs_enforcement_set(get_task_map(pt->task), TRUE);
2613 }
0a7de745
A
2614 pt->p_csflags |= flags;
2615 } else {
2616 error = EINVAL;
2617 }
2618 proc_unlock(pt);
2619
2620 break;
2621 }
4ba76501
A
2622 case CS_OPS_CLEAR_LV: {
2623 /*
2624 * This option is used to remove library validation from
2625 * a running process. This is used in plugin architectures
2626 * when a program needs to load untrusted libraries. This
2627 * allows the process to maintain library validation as
2628 * long as possible, then drop it only when required.
2629 * Once a process has loaded the untrusted library,
2630 * relying on library validation in the future will
2631 * not be effective. An alternative is to re-exec
2632 * your application without library validation, or
2633 * fork an untrusted child.
2634 */
f427ee49
A
2635#if !defined(XNU_TARGET_OS_OSX)
2636 // We only support dropping library validation on macOS
4ba76501
A
2637 error = ENOTSUP;
2638#else
2639 /*
2640 * if we have the flag set, and the caller wants
2641 * to remove it, and they're entitled to, then
2642 * we remove it from the csflags
2643 *
2644 * NOTE: We are fine to poke into the task because
2645 * we get a ref to pt when we do the proc_find
2646 * at the beginning of this function.
2647 *
2648 * We also only allow altering ourselves.
2649 */
2650 if (forself == 1 && IOTaskHasEntitlement(pt->task, CLEAR_LV_ENTITLEMENT)) {
2651 proc_lock(pt);
ea3f0419 2652 pt->p_csflags &= (~(CS_REQUIRE_LV | CS_FORCED_LV));
4ba76501
A
2653 proc_unlock(pt);
2654 error = 0;
2655 } else {
2656 error = EPERM;
2657 }
2658#endif
2659 break;
2660 }
0a7de745
A
2661 case CS_OPS_BLOB: {
2662 void *start;
2663 size_t length;
39236c6e 2664
0a7de745
A
2665 proc_lock(pt);
2666 if ((pt->p_csflags & (CS_VALID | CS_DEBUGGED)) == 0) {
39236c6e 2667 proc_unlock(pt);
0a7de745
A
2668 error = EINVAL;
2669 break;
2670 }
39236c6e 2671
0a7de745
A
2672 error = cs_blob_get(pt, &start, &length);
2673 proc_unlock(pt);
2674 if (error) {
6d2010ae
A
2675 break;
2676 }
39236c6e 2677
0a7de745
A
2678 error = csops_copy_token(start, length, usize, uaddr);
2679 break;
2680 }
2681 case CS_OPS_IDENTITY:
2682 case CS_OPS_TEAMID: {
2683 const char *identity;
2684 uint8_t fakeheader[8];
2685 uint32_t idlen;
2686 size_t length;
6d2010ae 2687
0a7de745
A
2688 /*
2689 * Make identity have a blob header to make it
2690 * easier on userland to guess the identity
2691 * length.
2692 */
2693 if (usize < sizeof(fakeheader)) {
2694 error = ERANGE;
2695 break;
2696 }
2697 memset(fakeheader, 0, sizeof(fakeheader));
39236c6e 2698
0a7de745
A
2699 proc_lock(pt);
2700 if ((pt->p_csflags & (CS_VALID | CS_DEBUGGED)) == 0) {
6d2010ae 2701 proc_unlock(pt);
0a7de745
A
2702 error = EINVAL;
2703 break;
2704 }
39236c6e 2705
0a7de745
A
2706 identity = ops == CS_OPS_TEAMID ? csproc_get_teamid(pt) : cs_identity_get(pt);
2707 proc_unlock(pt);
2708 if (identity == NULL) {
2709 error = ENOENT;
2710 break;
2711 }
39236c6e 2712
0a7de745 2713 length = strlen(identity) + 1; /* include NUL */
f427ee49 2714 idlen = htonl((uint32_t)(length + sizeof(fakeheader)));
0a7de745 2715 memcpy(&fakeheader[4], &idlen, sizeof(idlen));
39236c6e 2716
0a7de745
A
2717 error = copyout(fakeheader, uaddr, sizeof(fakeheader));
2718 if (error) {
39236c6e
A
2719 break;
2720 }
2721
0a7de745
A
2722 if (usize < sizeof(fakeheader) + length) {
2723 error = ERANGE;
2724 } else if (usize > sizeof(fakeheader)) {
2725 error = copyout(identity, uaddr + sizeof(fakeheader), length);
2726 }
39037602 2727
0a7de745
A
2728 break;
2729 }
2730
2731 case CS_OPS_CLEARINSTALLER:
2732 proc_lock(pt);
2733 pt->p_csflags &= ~(CS_INSTALLER | CS_DATAVAULT_CONTROLLER | CS_EXEC_INHERIT_SIP);
2734 proc_unlock(pt);
2735 break;
2736
2737 case CS_OPS_CLEARPLATFORM:
5ba3f43e 2738#if DEVELOPMENT || DEBUG
0a7de745
A
2739 if (cs_process_global_enforcement()) {
2740 error = ENOTSUP;
2741 break;
2742 }
5ba3f43e
A
2743
2744#if CONFIG_CSR
0a7de745
A
2745 if (csr_check(CSR_ALLOW_APPLE_INTERNAL) != 0) {
2746 error = ENOTSUP;
2747 break;
2748 }
5ba3f43e
A
2749#endif
2750
0a7de745
A
2751 proc_lock(pt);
2752 pt->p_csflags &= ~(CS_PLATFORM_BINARY | CS_PLATFORM_PATH);
2753 csproc_clear_platform_binary(pt);
2754 proc_unlock(pt);
2755 break;
5ba3f43e 2756#else
0a7de745
A
2757 error = ENOTSUP;
2758 break;
5ba3f43e
A
2759#endif /* !DEVELOPMENT || DEBUG */
2760
0a7de745
A
2761 default:
2762 error = EINVAL;
2763 break;
2d21ac55
A
2764 }
2765out:
2766 proc_rele(pt);
0a7de745 2767 return error;
e5568f75 2768}
2d21ac55 2769
cb323159 2770void
39037602
A
2771proc_iterate(
2772 unsigned int flags,
2773 proc_iterate_fn_t callout,
2774 void *arg,
2775 proc_iterate_fn_t filterfn,
2776 void *filterarg)
2777{
cb323159
A
2778 pidlist_t pid_list, *pl = pidlist_init(&pid_list);
2779 u_int pid_count_available = 0;
39037602
A
2780
2781 assert(callout != NULL);
2782
2783 /* allocate outside of the proc_list_lock */
2784 for (;;) {
2785 proc_list_lock();
cb323159 2786 pid_count_available = nprocs + 1; /* kernel_task not counted in nprocs */
39037602 2787 assert(pid_count_available > 0);
c3c9b80d 2788 if (pidlist_nalloc(pl) >= pid_count_available) {
39037602
A
2789 break;
2790 }
2791 proc_list_unlock();
2d21ac55 2792
cb323159 2793 pidlist_alloc(pl, pid_count_available);
39037602 2794 }
cb323159 2795 pidlist_set_active(pl);
2d21ac55 2796
cb323159 2797 /* filter pids into the pid_list */
2d21ac55 2798
cb323159 2799 u_int pid_count = 0;
2d21ac55 2800 if (flags & PROC_ALLPROCLIST) {
39037602
A
2801 proc_t p;
2802 ALLPROC_FOREACH(p) {
2803 /* ignore processes that are being forked */
2804 if (p->p_stat == SIDL) {
2805 continue;
2806 }
2807 if ((filterfn != NULL) && (filterfn(p, filterarg) == 0)) {
2d21ac55 2808 continue;
39037602 2809 }
cb323159
A
2810 pidlist_add_pid(pl, proc_pid(p));
2811 if (++pid_count >= pid_count_available) {
39037602 2812 break;
2d21ac55
A
2813 }
2814 }
2815 }
39037602
A
2816
2817 if ((pid_count < pid_count_available) &&
0a7de745 2818 (flags & PROC_ZOMBPROCLIST)) {
39037602
A
2819 proc_t p;
2820 ZOMBPROC_FOREACH(p) {
2821 if ((filterfn != NULL) && (filterfn(p, filterarg) == 0)) {
2822 continue;
2823 }
cb323159
A
2824 pidlist_add_pid(pl, proc_pid(p));
2825 if (++pid_count >= pid_count_available) {
39037602 2826 break;
2d21ac55
A
2827 }
2828 }
2829 }
2d21ac55
A
2830
2831 proc_list_unlock();
2832
39037602 2833 /* call callout on processes in the pid_list */
2d21ac55 2834
cb323159
A
2835 const pidlist_entry_t *pe;
2836 SLIST_FOREACH(pe, &(pl->pl_head), pe_link) {
2837 for (u_int i = 0; i < pe->pe_nused; i++) {
2838 const pid_t pid = pe->pe_pid[i];
2839 proc_t p = proc_find(pid);
2840 if (p) {
2841 if ((flags & PROC_NOWAITTRANS) == 0) {
2842 proc_transwait(p, 0);
2843 }
2844 const int callout_ret = callout(p, arg);
2845
2846 switch (callout_ret) {
2847 case PROC_RETURNED_DONE:
2848 proc_rele(p);
f427ee49 2849 OS_FALLTHROUGH;
cb323159
A
2850 case PROC_CLAIMED_DONE:
2851 goto out;
2852
2853 case PROC_RETURNED:
2854 proc_rele(p);
f427ee49 2855 OS_FALLTHROUGH;
cb323159
A
2856 case PROC_CLAIMED:
2857 break;
2858 default:
2859 panic("%s: callout =%d for pid %d",
2860 __func__, callout_ret, pid);
2861 break;
2862 }
2863 } else if (flags & PROC_ZOMBPROCLIST) {
2864 p = proc_find_zombref(pid);
2865 if (!p) {
2866 continue;
2867 }
2868 const int callout_ret = callout(p, arg);
2869
2870 switch (callout_ret) {
2871 case PROC_RETURNED_DONE:
2872 proc_drop_zombref(p);
f427ee49 2873 OS_FALLTHROUGH;
cb323159
A
2874 case PROC_CLAIMED_DONE:
2875 goto out;
2876
2877 case PROC_RETURNED:
2878 proc_drop_zombref(p);
f427ee49 2879 OS_FALLTHROUGH;
cb323159
A
2880 case PROC_CLAIMED:
2881 break;
2882 default:
2883 panic("%s: callout =%d for zombie %d",
2884 __func__, callout_ret, pid);
2885 break;
2886 }
39037602 2887 }
2d21ac55
A
2888 }
2889 }
39037602 2890out:
cb323159 2891 pidlist_free(pl);
2d21ac55 2892}
2d21ac55 2893
39037602
A
2894void
2895proc_rebootscan(
2896 proc_iterate_fn_t callout,
2897 void *arg,
2898 proc_iterate_fn_t filterfn,
2899 void *filterarg)
2d21ac55
A
2900{
2901 proc_t p;
39037602
A
2902
2903 assert(callout != NULL);
2d21ac55 2904
b0d623f7
A
2905 proc_shutdown_exitcount = 0;
2906
39037602 2907restart_foreach:
2d21ac55
A
2908
2909 proc_list_lock();
b0d623f7 2910
39037602
A
2911 ALLPROC_FOREACH(p) {
2912 if ((filterfn != NULL) && filterfn(p, filterarg) == 0) {
2913 continue;
2914 }
2915 p = proc_ref_locked(p);
2916 if (!p) {
0a7de745 2917 continue;
39037602 2918 }
2d21ac55 2919
39037602 2920 proc_list_unlock();
2d21ac55 2921
39037602
A
2922 proc_transwait(p, 0);
2923 (void)callout(p, arg);
2924 proc_rele(p);
2d21ac55 2925
39037602 2926 goto restart_foreach;
2d21ac55
A
2927 }
2928
39037602 2929 proc_list_unlock();
2d21ac55
A
2930}
2931
cb323159 2932void
39037602
A
2933proc_childrenwalk(
2934 proc_t parent,
2935 proc_iterate_fn_t callout,
2936 void *arg)
2d21ac55 2937{
cb323159
A
2938 pidlist_t pid_list, *pl = pidlist_init(&pid_list);
2939 u_int pid_count_available = 0;
2d21ac55 2940
39037602
A
2941 assert(parent != NULL);
2942 assert(callout != NULL);
2d21ac55 2943
39037602
A
2944 for (;;) {
2945 proc_list_lock();
39037602
A
2946 pid_count_available = parent->p_childrencnt;
2947 if (pid_count_available == 0) {
2948 proc_list_unlock();
cb323159 2949 goto out;
39037602 2950 }
c3c9b80d 2951 if (pidlist_nalloc(pl) >= pid_count_available) {
39037602
A
2952 break;
2953 }
2954 proc_list_unlock();
2d21ac55 2955
cb323159 2956 pidlist_alloc(pl, pid_count_available);
39037602 2957 }
cb323159 2958 pidlist_set_active(pl);
39037602 2959
cb323159 2960 u_int pid_count = 0;
39037602
A
2961 proc_t p;
2962 PCHILDREN_FOREACH(parent, p) {
2963 if (p->p_stat == SIDL) {
2d21ac55 2964 continue;
39037602 2965 }
cb323159
A
2966 pidlist_add_pid(pl, proc_pid(p));
2967 if (++pid_count >= pid_count_available) {
2d21ac55 2968 break;
39037602 2969 }
2d21ac55 2970 }
2d21ac55 2971
39037602 2972 proc_list_unlock();
2d21ac55 2973
cb323159
A
2974 const pidlist_entry_t *pe;
2975 SLIST_FOREACH(pe, &(pl->pl_head), pe_link) {
2976 for (u_int i = 0; i < pe->pe_nused; i++) {
2977 const pid_t pid = pe->pe_pid[i];
2978 p = proc_find(pid);
2979 if (!p) {
2980 continue;
2981 }
2982 const int callout_ret = callout(p, arg);
2d21ac55 2983
cb323159
A
2984 switch (callout_ret) {
2985 case PROC_RETURNED_DONE:
2986 proc_rele(p);
f427ee49 2987 OS_FALLTHROUGH;
cb323159
A
2988 case PROC_CLAIMED_DONE:
2989 goto out;
39037602 2990
cb323159
A
2991 case PROC_RETURNED:
2992 proc_rele(p);
f427ee49 2993 OS_FALLTHROUGH;
cb323159
A
2994 case PROC_CLAIMED:
2995 break;
2996 default:
2997 panic("%s: callout =%d for pid %d",
2998 __func__, callout_ret, pid);
2999 break;
3000 }
39037602
A
3001 }
3002 }
39037602 3003out:
cb323159 3004 pidlist_free(pl);
2d21ac55
A
3005}
3006
cb323159 3007void
39037602
A
3008pgrp_iterate(
3009 struct pgrp *pgrp,
3010 unsigned int flags,
3011 proc_iterate_fn_t callout,
3012 void * arg,
3013 proc_iterate_fn_t filterfn,
3014 void * filterarg)
3015{
cb323159
A
3016 pidlist_t pid_list, *pl = pidlist_init(&pid_list);
3017 u_int pid_count_available = 0;
2d21ac55 3018
39037602
A
3019 assert(pgrp != NULL);
3020 assert(callout != NULL);
3021
3022 for (;;) {
3023 pgrp_lock(pgrp);
39037602
A
3024 pid_count_available = pgrp->pg_membercnt;
3025 if (pid_count_available == 0) {
3026 pgrp_unlock(pgrp);
cb323159
A
3027 if (flags & PGRP_DROPREF) {
3028 pg_rele(pgrp);
3029 }
3030 goto out;
39037602 3031 }
c3c9b80d 3032 if (pidlist_nalloc(pl) >= pid_count_available) {
39037602
A
3033 break;
3034 }
3035 pgrp_unlock(pgrp);
3036
cb323159 3037 pidlist_alloc(pl, pid_count_available);
2d21ac55 3038 }
cb323159 3039 pidlist_set_active(pl);
2d21ac55 3040
cb323159
A
3041 const pid_t pgid = pgrp->pg_id;
3042 u_int pid_count = 0;
3043 proc_t p;
39037602
A
3044 PGMEMBERS_FOREACH(pgrp, p) {
3045 if ((filterfn != NULL) && (filterfn(p, filterarg) == 0)) {
3046 continue;;
3047 }
cb323159
A
3048 pidlist_add_pid(pl, proc_pid(p));
3049 if (++pid_count >= pid_count_available) {
39037602 3050 break;
2d21ac55
A
3051 }
3052 }
2d21ac55
A
3053
3054 pgrp_unlock(pgrp);
2d21ac55 3055
39037602
A
3056 if (flags & PGRP_DROPREF) {
3057 pg_rele(pgrp);
3058 }
2d21ac55 3059
cb323159
A
3060 const pidlist_entry_t *pe;
3061 SLIST_FOREACH(pe, &(pl->pl_head), pe_link) {
3062 for (u_int i = 0; i < pe->pe_nused; i++) {
3063 const pid_t pid = pe->pe_pid[i];
3064 if (0 == pid) {
3065 continue; /* skip kernproc */
3066 }
3067 p = proc_find(pid);
3068 if (!p) {
3069 continue;
3070 }
3071 if (p->p_pgrpid != pgid) {
3072 proc_rele(p);
3073 continue;
3074 }
3075 const int callout_ret = callout(p, arg);
39037602 3076
cb323159
A
3077 switch (callout_ret) {
3078 case PROC_RETURNED:
3079 proc_rele(p);
f427ee49 3080 OS_FALLTHROUGH;
cb323159
A
3081 case PROC_CLAIMED:
3082 break;
3083 case PROC_RETURNED_DONE:
3084 proc_rele(p);
f427ee49 3085 OS_FALLTHROUGH;
cb323159
A
3086 case PROC_CLAIMED_DONE:
3087 goto out;
39037602 3088
cb323159
A
3089 default:
3090 panic("%s: callout =%d for pid %d",
3091 __func__, callout_ret, pid);
3092 }
2d21ac55 3093 }
2d21ac55 3094 }
39037602
A
3095
3096out:
cb323159 3097 pidlist_free(pl);
2d21ac55
A
3098}
3099
3100static void
3101pgrp_add(struct pgrp * pgrp, struct proc * parent, struct proc * child)
3102{
3103 proc_list_lock();
3104 child->p_pgrp = pgrp;
3105 child->p_pgrpid = pgrp->pg_id;
f427ee49 3106 child->p_sessionid = pgrp->pg_session->s_sid;
2d21ac55
A
3107 child->p_listflag |= P_LIST_INPGRP;
3108 /*
0a7de745
A
3109 * When pgrp is being freed , a process can still
3110 * request addition using setpgid from bash when
3111 * login is terminated (login cycler) return ESRCH
3112 * Safe to hold lock due to refcount on pgrp
2d21ac55
A
3113 */
3114 if ((pgrp->pg_listflags & (PGRP_FLAG_TERMINATE | PGRP_FLAG_DEAD)) == PGRP_FLAG_TERMINATE) {
0a7de745 3115 pgrp->pg_listflags &= ~PGRP_FLAG_TERMINATE;
2d21ac55
A
3116 }
3117
0a7de745 3118 if ((pgrp->pg_listflags & PGRP_FLAG_DEAD) == PGRP_FLAG_DEAD) {
2d21ac55 3119 panic("pgrp_add : pgrp is dead adding process");
0a7de745 3120 }
2d21ac55
A
3121 proc_list_unlock();
3122
3123 pgrp_lock(pgrp);
3124 pgrp->pg_membercnt++;
0a7de745 3125 if (parent != PROC_NULL) {
2d21ac55 3126 LIST_INSERT_AFTER(parent, child, p_pglist);
0a7de745 3127 } else {
2d21ac55
A
3128 LIST_INSERT_HEAD(&pgrp->pg_members, child, p_pglist);
3129 }
3130 pgrp_unlock(pgrp);
3131
3132 proc_list_lock();
3133 if (((pgrp->pg_listflags & (PGRP_FLAG_TERMINATE | PGRP_FLAG_DEAD)) == PGRP_FLAG_TERMINATE) && (pgrp->pg_membercnt != 0)) {
0a7de745 3134 pgrp->pg_listflags &= ~PGRP_FLAG_TERMINATE;
2d21ac55
A
3135 }
3136 proc_list_unlock();
3137}
3138
3139static void
3140pgrp_remove(struct proc * p)
3141{
3142 struct pgrp * pg;
3143
3144 pg = proc_pgrp(p);
3145
3146 proc_list_lock();
3147#if __PROC_INTERNAL_DEBUG
0a7de745 3148 if ((p->p_listflag & P_LIST_INPGRP) == 0) {
2d21ac55 3149 panic("removing from pglist but no named ref\n");
0a7de745 3150 }
2d21ac55
A
3151#endif
3152 p->p_pgrpid = PGRPID_DEAD;
3153 p->p_listflag &= ~P_LIST_INPGRP;
3154 p->p_pgrp = NULL;
3155 proc_list_unlock();
3156
0a7de745 3157 if (pg == PGRP_NULL) {
2d21ac55 3158 panic("pgrp_remove: pg is NULL");
0a7de745 3159 }
2d21ac55
A
3160 pgrp_lock(pg);
3161 pg->pg_membercnt--;
3162
0a7de745
A
3163 if (pg->pg_membercnt < 0) {
3164 panic("pgprp: -ve membercnt pgprp:%p p:%p\n", pg, p);
3165 }
2d21ac55
A
3166
3167 LIST_REMOVE(p, p_pglist);
3168 if (pg->pg_members.lh_first == 0) {
3169 pgrp_unlock(pg);
3170 pgdelete_dropref(pg);
3171 } else {
3172 pgrp_unlock(pg);
3173 pg_rele(pg);
3174 }
3175}
3176
3177
3178/* cannot use proc_pgrp as it maybe stalled */
3179static void
3180pgrp_replace(struct proc * p, struct pgrp * newpg)
3181{
0a7de745 3182 struct pgrp * oldpg;
2d21ac55
A
3183
3184
3185
0a7de745 3186 proc_list_lock();
2d21ac55
A
3187
3188 while ((p->p_listflag & P_LIST_PGRPTRANS) == P_LIST_PGRPTRANS) {
3189 p->p_listflag |= P_LIST_PGRPTRWAIT;
c3c9b80d 3190 (void)msleep(&p->p_pgrpid, &proc_list_mlock, 0, "proc_pgrp", 0);
2d21ac55
A
3191 }
3192
3193 p->p_listflag |= P_LIST_PGRPTRANS;
3194
3195 oldpg = p->p_pgrp;
0a7de745 3196 if (oldpg == PGRP_NULL) {
2d21ac55 3197 panic("pgrp_replace: oldpg NULL");
0a7de745 3198 }
2d21ac55
A
3199 oldpg->pg_refcount++;
3200#if __PROC_INTERNAL_DEBUG
0a7de745
A
3201 if ((p->p_listflag & P_LIST_INPGRP) == 0) {
3202 panic("removing from pglist but no named ref\n");
3203 }
2d21ac55 3204#endif
0a7de745
A
3205 p->p_pgrpid = PGRPID_DEAD;
3206 p->p_listflag &= ~P_LIST_INPGRP;
3207 p->p_pgrp = NULL;
3208
3209 proc_list_unlock();
3210
3211 pgrp_lock(oldpg);
3212 oldpg->pg_membercnt--;
3213 if (oldpg->pg_membercnt < 0) {
3214 panic("pgprp: -ve membercnt pgprp:%p p:%p\n", oldpg, p);
3215 }
3216 LIST_REMOVE(p, p_pglist);
3217 if (oldpg->pg_members.lh_first == 0) {
3218 pgrp_unlock(oldpg);
3219 pgdelete_dropref(oldpg);
3220 } else {
3221 pgrp_unlock(oldpg);
3222 pg_rele(oldpg);
3223 }
3224
3225 proc_list_lock();
3226 p->p_pgrp = newpg;
3227 p->p_pgrpid = newpg->pg_id;
f427ee49 3228 p->p_sessionid = newpg->pg_session->s_sid;
0a7de745
A
3229 p->p_listflag |= P_LIST_INPGRP;
3230 /*
3231 * When pgrp is being freed , a process can still
3232 * request addition using setpgid from bash when
3233 * login is terminated (login cycler) return ESRCH
3234 * Safe to hold lock due to refcount on pgrp
3235 */
3236 if ((newpg->pg_listflags & (PGRP_FLAG_TERMINATE | PGRP_FLAG_DEAD)) == PGRP_FLAG_TERMINATE) {
3237 newpg->pg_listflags &= ~PGRP_FLAG_TERMINATE;
3238 }
3239
3240 if ((newpg->pg_listflags & PGRP_FLAG_DEAD) == PGRP_FLAG_DEAD) {
3241 panic("pgrp_add : pgrp is dead adding process");
3242 }
3243 proc_list_unlock();
3244
3245 pgrp_lock(newpg);
3246 newpg->pg_membercnt++;
2d21ac55 3247 LIST_INSERT_HEAD(&newpg->pg_members, p, p_pglist);
0a7de745 3248 pgrp_unlock(newpg);
2d21ac55 3249
0a7de745
A
3250 proc_list_lock();
3251 if (((newpg->pg_listflags & (PGRP_FLAG_TERMINATE | PGRP_FLAG_DEAD)) == PGRP_FLAG_TERMINATE) && (newpg->pg_membercnt != 0)) {
3252 newpg->pg_listflags &= ~PGRP_FLAG_TERMINATE;
3253 }
2d21ac55
A
3254
3255 p->p_listflag &= ~P_LIST_PGRPTRANS;
3256 if ((p->p_listflag & P_LIST_PGRPTRWAIT) == P_LIST_PGRPTRWAIT) {
3257 p->p_listflag &= ~P_LIST_PGRPTRWAIT;
3258 wakeup(&p->p_pgrpid);
2d21ac55 3259 }
0a7de745 3260 proc_list_unlock();
2d21ac55
A
3261}
3262
3263void
3264pgrp_lock(struct pgrp * pgrp)
3265{
3266 lck_mtx_lock(&pgrp->pg_mlock);
3267}
3268
3269void
3270pgrp_unlock(struct pgrp * pgrp)
3271{
3272 lck_mtx_unlock(&pgrp->pg_mlock);
3273}
3274
3275void
3276session_lock(struct session * sess)
3277{
3278 lck_mtx_lock(&sess->s_mlock);
3279}
3280
3281
3282void
3283session_unlock(struct session * sess)
3284{
3285 lck_mtx_unlock(&sess->s_mlock);
3286}
3287
3288struct pgrp *
3289proc_pgrp(proc_t p)
3290{
3291 struct pgrp * pgrp;
3292
0a7de745
A
3293 if (p == PROC_NULL) {
3294 return PGRP_NULL;
3295 }
2d21ac55
A
3296 proc_list_lock();
3297
3298 while ((p->p_listflag & P_LIST_PGRPTRANS) == P_LIST_PGRPTRANS) {
3299 p->p_listflag |= P_LIST_PGRPTRWAIT;
c3c9b80d 3300 (void)msleep(&p->p_pgrpid, &proc_list_mlock, 0, "proc_pgrp", 0);
2d21ac55 3301 }
0a7de745 3302
2d21ac55
A
3303 pgrp = p->p_pgrp;
3304
3305 assert(pgrp != NULL);
3306
b0d623f7 3307 if (pgrp != PGRP_NULL) {
2d21ac55 3308 pgrp->pg_refcount++;
0a7de745 3309 if ((pgrp->pg_listflags & (PGRP_FLAG_TERMINATE | PGRP_FLAG_DEAD)) != 0) {
b0d623f7 3310 panic("proc_pgrp: ref being povided for dead pgrp");
0a7de745 3311 }
b0d623f7 3312 }
0a7de745 3313
2d21ac55 3314 proc_list_unlock();
0a7de745
A
3315
3316 return pgrp;
2d21ac55
A
3317}
3318
3319struct pgrp *
3320tty_pgrp(struct tty * tp)
3321{
3322 struct pgrp * pg = PGRP_NULL;
3323
3324 proc_list_lock();
3325 pg = tp->t_pgrp;
3326
3327 if (pg != PGRP_NULL) {
0a7de745 3328 if ((pg->pg_listflags & PGRP_FLAG_DEAD) != 0) {
2d21ac55 3329 panic("tty_pgrp: ref being povided for dead pgrp");
0a7de745 3330 }
2d21ac55
A
3331 pg->pg_refcount++;
3332 }
3333 proc_list_unlock();
3334
0a7de745 3335 return pg;
2d21ac55
A
3336}
3337
3338struct session *
3339proc_session(proc_t p)
3340{
3341 struct session * sess = SESSION_NULL;
0a7de745
A
3342
3343 if (p == PROC_NULL) {
3344 return SESSION_NULL;
3345 }
2d21ac55
A
3346
3347 proc_list_lock();
3348
3349 /* wait during transitions */
3350 while ((p->p_listflag & P_LIST_PGRPTRANS) == P_LIST_PGRPTRANS) {
3351 p->p_listflag |= P_LIST_PGRPTRWAIT;
c3c9b80d 3352 (void)msleep(&p->p_pgrpid, &proc_list_mlock, 0, "proc_pgrp", 0);
2d21ac55
A
3353 }
3354
3355 if ((p->p_pgrp != PGRP_NULL) && ((sess = p->p_pgrp->pg_session) != SESSION_NULL)) {
0a7de745 3356 if ((sess->s_listflags & (S_LIST_TERM | S_LIST_DEAD)) != 0) {
2d21ac55 3357 panic("proc_session:returning sesssion ref on terminating session");
0a7de745 3358 }
2d21ac55
A
3359 sess->s_count++;
3360 }
3361 proc_list_unlock();
0a7de745 3362 return sess;
2d21ac55
A
3363}
3364
3365void
3366session_rele(struct session *sess)
3367{
3368 proc_list_lock();
3369 if (--sess->s_count == 0) {
0a7de745 3370 if ((sess->s_listflags & (S_LIST_TERM | S_LIST_DEAD)) != 0) {
2d21ac55 3371 panic("session_rele: terminating already terminated session");
0a7de745 3372 }
2d21ac55
A
3373 sess->s_listflags |= S_LIST_TERM;
3374 LIST_REMOVE(sess, s_hash);
3375 sess->s_listflags |= S_LIST_DEAD;
0a7de745
A
3376 if (sess->s_count != 0) {
3377 panic("session_rele: freeing session in use");
3378 }
2d21ac55 3379 proc_list_unlock();
c3c9b80d 3380 lck_mtx_destroy(&sess->s_mlock, &proc_mlock_grp);
f427ee49 3381 zfree(session_zone, sess);
0a7de745 3382 } else {
2d21ac55 3383 proc_list_unlock();
0a7de745 3384 }
2d21ac55
A
3385}
3386
b0d623f7 3387int
fe8ab488 3388proc_transstart(proc_t p, int locked, int non_blocking)
2d21ac55 3389{
0a7de745 3390 if (locked == 0) {
2d21ac55 3391 proc_lock(p);
0a7de745 3392 }
2d21ac55 3393 while ((p->p_lflag & P_LINTRANSIT) == P_LINTRANSIT) {
fe8ab488 3394 if (((p->p_lflag & P_LTRANSCOMMIT) == P_LTRANSCOMMIT) || non_blocking) {
0a7de745 3395 if (locked == 0) {
b0d623f7 3396 proc_unlock(p);
0a7de745 3397 }
b0d623f7
A
3398 return EDEADLK;
3399 }
2d21ac55
A
3400 p->p_lflag |= P_LTRANSWAIT;
3401 msleep(&p->p_lflag, &p->p_mlock, 0, "proc_signstart", NULL);
3402 }
3403 p->p_lflag |= P_LINTRANSIT;
3404 p->p_transholder = current_thread();
0a7de745 3405 if (locked == 0) {
2d21ac55 3406 proc_unlock(p);
0a7de745 3407 }
b0d623f7 3408 return 0;
2d21ac55
A
3409}
3410
b0d623f7
A
3411void
3412proc_transcommit(proc_t p, int locked)
3413{
0a7de745 3414 if (locked == 0) {
b0d623f7 3415 proc_lock(p);
0a7de745 3416 }
b0d623f7 3417
0a7de745
A
3418 assert((p->p_lflag & P_LINTRANSIT) == P_LINTRANSIT);
3419 assert(p->p_transholder == current_thread());
b0d623f7
A
3420 p->p_lflag |= P_LTRANSCOMMIT;
3421
3422 if ((p->p_lflag & P_LTRANSWAIT) == P_LTRANSWAIT) {
3423 p->p_lflag &= ~P_LTRANSWAIT;
3424 wakeup(&p->p_lflag);
3425 }
0a7de745 3426 if (locked == 0) {
b0d623f7 3427 proc_unlock(p);
0a7de745 3428 }
b0d623f7 3429}
2d21ac55
A
3430
3431void
3432proc_transend(proc_t p, int locked)
3433{
0a7de745 3434 if (locked == 0) {
2d21ac55 3435 proc_lock(p);
0a7de745 3436 }
b0d623f7 3437
0a7de745 3438 p->p_lflag &= ~(P_LINTRANSIT | P_LTRANSCOMMIT);
b0d623f7 3439 p->p_transholder = NULL;
2d21ac55
A
3440
3441 if ((p->p_lflag & P_LTRANSWAIT) == P_LTRANSWAIT) {
3442 p->p_lflag &= ~P_LTRANSWAIT;
3443 wakeup(&p->p_lflag);
3444 }
0a7de745 3445 if (locked == 0) {
2d21ac55 3446 proc_unlock(p);
0a7de745 3447 }
2d21ac55
A
3448}
3449
b0d623f7 3450int
2d21ac55
A
3451proc_transwait(proc_t p, int locked)
3452{
0a7de745 3453 if (locked == 0) {
2d21ac55 3454 proc_lock(p);
0a7de745 3455 }
2d21ac55 3456 while ((p->p_lflag & P_LINTRANSIT) == P_LINTRANSIT) {
b0d623f7 3457 if ((p->p_lflag & P_LTRANSCOMMIT) == P_LTRANSCOMMIT && current_proc() == p) {
0a7de745 3458 if (locked == 0) {
b0d623f7 3459 proc_unlock(p);
0a7de745 3460 }
b0d623f7
A
3461 return EDEADLK;
3462 }
2d21ac55
A
3463 p->p_lflag |= P_LTRANSWAIT;
3464 msleep(&p->p_lflag, &p->p_mlock, 0, "proc_signstart", NULL);
3465 }
0a7de745 3466 if (locked == 0) {
2d21ac55 3467 proc_unlock(p);
0a7de745 3468 }
b0d623f7 3469 return 0;
2d21ac55
A
3470}
3471
3472void
3473proc_klist_lock(void)
3474{
c3c9b80d 3475 lck_mtx_lock(&proc_klist_mlock);
2d21ac55
A
3476}
3477
3478void
3479proc_klist_unlock(void)
3480{
c3c9b80d 3481 lck_mtx_unlock(&proc_klist_mlock);
2d21ac55
A
3482}
3483
3484void
3485proc_knote(struct proc * p, long hint)
3486{
3487 proc_klist_lock();
3488 KNOTE(&p->p_klist, hint);
3489 proc_klist_unlock();
3490}
3491
b0d623f7
A
3492void
3493proc_knote_drain(struct proc *p)
3494{
3495 struct knote *kn = NULL;
3496
3497 /*
3498 * Clear the proc's klist to avoid references after the proc is reaped.
3499 */
3500 proc_klist_lock();
3501 while ((kn = SLIST_FIRST(&p->p_klist))) {
cb323159 3502 kn->kn_proc = PROC_NULL;
b0d623f7
A
3503 KNOTE_DETACH(&p->p_klist, kn);
3504 }
3505 proc_klist_unlock();
3506}
2d21ac55 3507
0a7de745 3508void
b0d623f7
A
3509proc_setregister(proc_t p)
3510{
3511 proc_lock(p);
3512 p->p_lflag |= P_LREGISTER;
3513 proc_unlock(p);
3514}
3515
0a7de745 3516void
b0d623f7
A
3517proc_resetregister(proc_t p)
3518{
3519 proc_lock(p);
3520 p->p_lflag &= ~P_LREGISTER;
3521 proc_unlock(p);
3522}
3523
3524pid_t
3525proc_pgrpid(proc_t p)
3526{
3527 return p->p_pgrpid;
3528}
3529
cb323159
A
3530pid_t
3531proc_sessionid(proc_t p)
3532{
f427ee49 3533 return p->p_sessionid;
cb323159
A
3534}
3535
b0d623f7
A
3536pid_t
3537proc_selfpgrpid()
3538{
3539 return current_proc()->p_pgrpid;
3540}
3541
3542
3543/* return control and action states */
3544int
3545proc_getpcontrol(int pid, int * pcontrolp)
3546{
3547 proc_t p;
3548
3549 p = proc_find(pid);
0a7de745
A
3550 if (p == PROC_NULL) {
3551 return ESRCH;
3552 }
3553 if (pcontrolp != NULL) {
b0d623f7 3554 *pcontrolp = p->p_pcaction;
0a7de745 3555 }
b0d623f7
A
3556
3557 proc_rele(p);
0a7de745 3558 return 0;
b0d623f7
A
3559}
3560
3561int
fe8ab488 3562proc_dopcontrol(proc_t p)
b0d623f7
A
3563{
3564 int pcontrol;
cb323159 3565 os_reason_t kill_reason;
b0d623f7
A
3566
3567 proc_lock(p);
3568
3569 pcontrol = PROC_CONTROL_STATE(p);
3570
fe8ab488 3571 if (PROC_ACTION_STATE(p) == 0) {
0a7de745
A
3572 switch (pcontrol) {
3573 case P_PCTHROTTLE:
3574 PROC_SETACTION_STATE(p);
3575 proc_unlock(p);
3576 printf("low swap: throttling pid %d (%s)\n", p->p_pid, p->p_comm);
3577 break;
b0d623f7 3578
0a7de745
A
3579 case P_PCSUSP:
3580 PROC_SETACTION_STATE(p);
3581 proc_unlock(p);
3582 printf("low swap: suspending pid %d (%s)\n", p->p_pid, p->p_comm);
3583 task_suspend(p->task);
3584 break;
b0d623f7 3585
0a7de745
A
3586 case P_PCKILL:
3587 PROC_SETACTION_STATE(p);
3588 proc_unlock(p);
3589 printf("low swap: killing pid %d (%s)\n", p->p_pid, p->p_comm);
cb323159
A
3590 kill_reason = os_reason_create(OS_REASON_JETSAM, JETSAM_REASON_LOWSWAP);
3591 psignal_with_reason(p, SIGKILL, kill_reason);
0a7de745 3592 break;
b0d623f7 3593
0a7de745
A
3594 default:
3595 proc_unlock(p);
b0d623f7 3596 }
0a7de745 3597 } else {
b0d623f7 3598 proc_unlock(p);
0a7de745 3599 }
b0d623f7 3600
0a7de745 3601 return PROC_RETURNED;
b0d623f7
A
3602}
3603
3604
3605/*
3606 * Resume a throttled or suspended process. This is an internal interface that's only
0a7de745 3607 * used by the user level code that presents the GUI when we run out of swap space and
b0d623f7
A
3608 * hence is restricted to processes with superuser privileges.
3609 */
3610
3611int
3612proc_resetpcontrol(int pid)
3613{
3614 proc_t p;
3615 int pcontrol;
3616 int error;
6d2010ae 3617 proc_t self = current_proc();
b0d623f7 3618
6d2010ae 3619 /* if the process has been validated to handle resource control or root is valid one */
0a7de745 3620 if (((self->p_lflag & P_LVMRSRCOWNER) == 0) && (error = suser(kauth_cred_get(), 0))) {
b0d623f7 3621 return error;
0a7de745 3622 }
6d2010ae 3623
b0d623f7 3624 p = proc_find(pid);
0a7de745
A
3625 if (p == PROC_NULL) {
3626 return ESRCH;
3627 }
3628
b0d623f7
A
3629 proc_lock(p);
3630
3631 pcontrol = PROC_CONTROL_STATE(p);
3632
0a7de745
A
3633 if (PROC_ACTION_STATE(p) != 0) {
3634 switch (pcontrol) {
3635 case P_PCTHROTTLE:
3636 PROC_RESETACTION_STATE(p);
3637 proc_unlock(p);
3638 printf("low swap: unthrottling pid %d (%s)\n", p->p_pid, p->p_comm);
3639 break;
b0d623f7 3640
0a7de745
A
3641 case P_PCSUSP:
3642 PROC_RESETACTION_STATE(p);
3643 proc_unlock(p);
3644 printf("low swap: resuming pid %d (%s)\n", p->p_pid, p->p_comm);
3645 task_resume(p->task);
3646 break;
b0d623f7 3647
0a7de745
A
3648 case P_PCKILL:
3649 /* Huh? */
3650 PROC_SETACTION_STATE(p);
3651 proc_unlock(p);
3652 printf("low swap: attempt to unkill pid %d (%s) ignored\n", p->p_pid, p->p_comm);
3653 break;
b0d623f7 3654
0a7de745
A
3655 default:
3656 proc_unlock(p);
b0d623f7 3657 }
0a7de745 3658 } else {
b0d623f7 3659 proc_unlock(p);
0a7de745 3660 }
b0d623f7
A
3661
3662 proc_rele(p);
0a7de745 3663 return 0;
b0d623f7
A
3664}
3665
3666
fe8ab488 3667
0a7de745
A
3668struct no_paging_space {
3669 uint64_t pcs_max_size;
3670 uint64_t pcs_uniqueid;
3671 int pcs_pid;
3672 int pcs_proc_count;
3673 uint64_t pcs_total_size;
fe8ab488 3674
0a7de745
A
3675 uint64_t npcs_max_size;
3676 uint64_t npcs_uniqueid;
3677 int npcs_pid;
3678 int npcs_proc_count;
3679 uint64_t npcs_total_size;
fe8ab488 3680
0a7de745
A
3681 int apcs_proc_count;
3682 uint64_t apcs_total_size;
fe8ab488
A
3683};
3684
b0d623f7
A
3685
3686static int
fe8ab488 3687proc_pcontrol_filter(proc_t p, void *arg)
b0d623f7 3688{
fe8ab488 3689 struct no_paging_space *nps;
0a7de745 3690 uint64_t compressed;
fe8ab488
A
3691
3692 nps = (struct no_paging_space *)arg;
3693
3694 compressed = get_task_compressed(p->task);
3695
3696 if (PROC_CONTROL_STATE(p)) {
3697 if (PROC_ACTION_STATE(p) == 0) {
3698 if (compressed > nps->pcs_max_size) {
3699 nps->pcs_pid = p->p_pid;
3700 nps->pcs_uniqueid = p->p_uniqueid;
3701 nps->pcs_max_size = compressed;
3702 }
3703 nps->pcs_total_size += compressed;
3704 nps->pcs_proc_count++;
3705 } else {
3706 nps->apcs_total_size += compressed;
3707 nps->apcs_proc_count++;
3708 }
3709 } else {
3710 if (compressed > nps->npcs_max_size) {
3711 nps->npcs_pid = p->p_pid;
3712 nps->npcs_uniqueid = p->p_uniqueid;
3713 nps->npcs_max_size = compressed;
3714 }
3715 nps->npcs_total_size += compressed;
3716 nps->npcs_proc_count++;
fe8ab488 3717 }
0a7de745 3718 return 0;
b0d623f7
A
3719}
3720
3721
fe8ab488
A
3722static int
3723proc_pcontrol_null(__unused proc_t p, __unused void *arg)
3724{
0a7de745 3725 return PROC_RETURNED;
fe8ab488
A
3726}
3727
b0d623f7
A
3728
3729/*
fe8ab488
A
3730 * Deal with the low on compressor pool space condition... this function
3731 * gets called when we are approaching the limits of the compressor pool or
3732 * we are unable to create a new swap file.
3733 * Since this eventually creates a memory deadlock situtation, we need to take action to free up
3734 * memory resources (both compressed and uncompressed) in order to prevent the system from hanging completely.
3735 * There are 2 categories of processes to deal with. Those that have an action
0a7de745 3736 * associated with them by the task itself and those that do not. Actionable
fe8ab488
A
3737 * tasks can have one of three categories specified: ones that
3738 * can be killed immediately, ones that should be suspended, and ones that should
3739 * be throttled. Processes that do not have an action associated with them are normally
3740 * ignored unless they are utilizing such a large percentage of the compressor pool (currently 50%)
3741 * that only by killing them can we hope to put the system back into a usable state.
b0d623f7
A
3742 */
3743
0a7de745 3744#define NO_PAGING_SPACE_DEBUG 0
fe8ab488 3745
0a7de745 3746extern uint64_t vm_compressor_pages_compressed(void);
b0d623f7 3747
cb323159 3748struct timeval last_no_space_action = {.tv_sec = 0, .tv_usec = 0};
b0d623f7 3749
0a7de745
A
3750#define MB_SIZE (1024 * 1024ULL)
3751boolean_t memorystatus_kill_on_VM_compressor_space_shortage(boolean_t);
5ba3f43e 3752
0a7de745
A
3753extern int32_t max_kill_priority;
3754extern int memorystatus_get_proccnt_upto_priority(int32_t max_bucket_index);
813fb2f6 3755
fe8ab488
A
3756int
3757no_paging_space_action()
b0d623f7 3758{
0a7de745 3759 proc_t p;
fe8ab488 3760 struct no_paging_space nps;
0a7de745 3761 struct timeval now;
cb323159 3762 os_reason_t kill_reason;
b0d623f7
A
3763
3764 /*
fe8ab488 3765 * Throttle how often we come through here. Once every 5 seconds should be plenty.
b0d623f7 3766 */
b0d623f7
A
3767 microtime(&now);
3768
0a7de745
A
3769 if (now.tv_sec <= last_no_space_action.tv_sec + 5) {
3770 return 0;
3771 }
b0d623f7
A
3772
3773 /*
0a7de745 3774 * Examine all processes and find the biggest (biggest is based on the number of pages this
fe8ab488
A
3775 * task has in the compressor pool) that has been marked to have some action
3776 * taken when swap space runs out... we also find the biggest that hasn't been marked for
3777 * action.
b0d623f7 3778 *
fe8ab488
A
3779 * If the biggest non-actionable task is over the "dangerously big" threashold (currently 50% of
3780 * the total number of pages held by the compressor, we go ahead and kill it since no other task
3781 * can have any real effect on the situation. Otherwise, we go after the actionable process.
b0d623f7 3782 */
fe8ab488 3783 bzero(&nps, sizeof(nps));
b0d623f7 3784
fe8ab488 3785 proc_iterate(PROC_ALLPROCLIST, proc_pcontrol_null, (void *)NULL, proc_pcontrol_filter, (void *)&nps);
b0d623f7 3786
fe8ab488
A
3787#if NO_PAGING_SPACE_DEBUG
3788 printf("low swap: npcs_proc_count = %d, npcs_total_size = %qd, npcs_max_size = %qd\n",
0a7de745 3789 nps.npcs_proc_count, nps.npcs_total_size, nps.npcs_max_size);
fe8ab488 3790 printf("low swap: pcs_proc_count = %d, pcs_total_size = %qd, pcs_max_size = %qd\n",
0a7de745 3791 nps.pcs_proc_count, nps.pcs_total_size, nps.pcs_max_size);
fe8ab488 3792 printf("low swap: apcs_proc_count = %d, apcs_total_size = %qd\n",
0a7de745 3793 nps.apcs_proc_count, nps.apcs_total_size);
fe8ab488
A
3794#endif
3795 if (nps.npcs_max_size > (vm_compressor_pages_compressed() * 50) / 100) {
b0d623f7 3796 /*
fe8ab488
A
3797 * for now we'll knock out any task that has more then 50% of the pages
3798 * held by the compressor
b0d623f7 3799 */
fe8ab488 3800 if ((p = proc_find(nps.npcs_pid)) != PROC_NULL) {
fe8ab488
A
3801 if (nps.npcs_uniqueid == p->p_uniqueid) {
3802 /*
3803 * verify this is still the same process
3804 * in case the proc exited and the pid got reused while
3805 * we were finishing the proc_iterate and getting to this point
3806 */
3807 last_no_space_action = now;
3808
0a7de745 3809 printf("low swap: killing largest compressed process with pid %d (%s) and size %llu MB\n", p->p_pid, p->p_comm, (nps.pcs_max_size / MB_SIZE));
cb323159
A
3810 kill_reason = os_reason_create(OS_REASON_JETSAM, JETSAM_REASON_LOWSWAP);
3811 psignal_with_reason(p, SIGKILL, kill_reason);
0a7de745 3812
fe8ab488 3813 proc_rele(p);
b0d623f7 3814
0a7de745 3815 return 0;
fe8ab488 3816 }
0a7de745 3817
fe8ab488
A
3818 proc_rele(p);
3819 }
3820 }
b0d623f7 3821
5ba3f43e
A
3822 /*
3823 * We have some processes within our jetsam bands of consideration and hence can be killed.
3824 * So we will invoke the memorystatus thread to go ahead and kill something.
3825 */
3826 if (memorystatus_get_proccnt_upto_priority(max_kill_priority) > 0) {
5ba3f43e 3827 last_no_space_action = now;
d9a64523 3828 memorystatus_kill_on_VM_compressor_space_shortage(TRUE /* async */);
0a7de745 3829 return 1;
5ba3f43e
A
3830 }
3831
3832 /*
3833 * No eligible processes to kill. So let's suspend/kill the largest
3834 * process depending on its policy control specifications.
3835 */
3836
fe8ab488
A
3837 if (nps.pcs_max_size > 0) {
3838 if ((p = proc_find(nps.pcs_pid)) != PROC_NULL) {
fe8ab488
A
3839 if (nps.pcs_uniqueid == p->p_uniqueid) {
3840 /*
3841 * verify this is still the same process
3842 * in case the proc exited and the pid got reused while
3843 * we were finishing the proc_iterate and getting to this point
3844 */
3845 last_no_space_action = now;
0a7de745 3846
fe8ab488 3847 proc_dopcontrol(p);
0a7de745 3848
fe8ab488 3849 proc_rele(p);
0a7de745
A
3850
3851 return 1;
fe8ab488 3852 }
0a7de745 3853
fe8ab488 3854 proc_rele(p);
b0d623f7
A
3855 }
3856 }
fe8ab488
A
3857 last_no_space_action = now;
3858
3859 printf("low swap: unable to find any eligible processes to take action on\n");
3860
0a7de745 3861 return 0;
fe8ab488
A
3862}
3863
0a7de745
A
3864int
3865proc_trace_log(__unused proc_t p, struct proc_trace_log_args *uap, __unused int *retval)
fe8ab488
A
3866{
3867 int ret = 0;
3868 proc_t target_proc = PROC_NULL;
3869 pid_t target_pid = uap->pid;
3870 uint64_t target_uniqueid = uap->uniqueid;
3871 task_t target_task = NULL;
3872
3873 if (priv_check_cred(kauth_cred_get(), PRIV_PROC_TRACE_INSPECT, 0)) {
3874 ret = EPERM;
3875 goto out;
3876 }
3877 target_proc = proc_find(target_pid);
3878 if (target_proc != PROC_NULL) {
3879 if (target_uniqueid != proc_uniqueid(target_proc)) {
3880 ret = ENOENT;
3881 goto out;
3882 }
3883
3884 target_task = proc_task(target_proc);
3885 if (task_send_trace_memory(target_task, target_pid, target_uniqueid)) {
3886 ret = EINVAL;
3887 goto out;
3888 }
0a7de745 3889 } else {
fe8ab488 3890 ret = ENOENT;
0a7de745 3891 }
fe8ab488
A
3892
3893out:
0a7de745 3894 if (target_proc != PROC_NULL) {
fe8ab488 3895 proc_rele(target_proc);
0a7de745
A
3896 }
3897 return ret;
fe8ab488
A
3898}
3899
3900#if VM_SCAN_FOR_SHADOW_CHAIN
3901extern int vm_map_shadow_max(vm_map_t map);
3902int proc_shadow_max(void);
0a7de745
A
3903int
3904proc_shadow_max(void)
fe8ab488 3905{
0a7de745
A
3906 int retval, max;
3907 proc_t p;
3908 task_t task;
3909 vm_map_t map;
fe8ab488
A
3910
3911 max = 0;
3912 proc_list_lock();
3913 for (p = allproc.lh_first; (p != 0); p = p->p_list.le_next) {
0a7de745 3914 if (p->p_stat == SIDL) {
fe8ab488 3915 continue;
0a7de745 3916 }
fe8ab488
A
3917 task = p->task;
3918 if (task == NULL) {
3919 continue;
3920 }
3921 map = get_task_map(task);
3922 if (map == NULL) {
3923 continue;
3924 }
3925 retval = vm_map_shadow_max(map);
3926 if (retval > max) {
3927 max = retval;
3928 }
3929 }
3930 proc_list_unlock();
3931 return max;
b0d623f7 3932}
fe8ab488 3933#endif /* VM_SCAN_FOR_SHADOW_CHAIN */
3e170ce0
A
3934
3935void proc_set_responsible_pid(proc_t target_proc, pid_t responsible_pid);
0a7de745
A
3936void
3937proc_set_responsible_pid(proc_t target_proc, pid_t responsible_pid)
3e170ce0
A
3938{
3939 if (target_proc != NULL) {
3940 target_proc->p_responsible_pid = responsible_pid;
3941 }
3942 return;
3943}
3944
3945int
3946proc_chrooted(proc_t p)
3947{
3948 int retval = 0;
3949
3950 if (p) {
3951 proc_fdlock(p);
3952 retval = (p->p_fd->fd_rdir != NULL) ? 1 : 0;
3953 proc_fdunlock(p);
3954 }
3955
3956 return retval;
3957}
39037602 3958
d9a64523
A
3959boolean_t
3960proc_send_synchronous_EXC_RESOURCE(proc_t p)
39037602 3961{
0a7de745 3962 if (p == PROC_NULL) {
d9a64523 3963 return FALSE;
0a7de745 3964 }
d9a64523
A
3965
3966 /* Send sync EXC_RESOURCE if the process is traced */
3967 if (ISSET(p->p_lflag, P_LTRACED)) {
3968 return TRUE;
3969 }
3970 return FALSE;
39037602 3971}
527f9951 3972
f427ee49 3973#if CONFIG_MACF
cb323159
A
3974size_t
3975proc_get_syscall_filter_mask_size(int which)
3976{
f427ee49
A
3977 switch (which) {
3978 case SYSCALL_MASK_UNIX:
cb323159 3979 return nsysent;
f427ee49
A
3980 case SYSCALL_MASK_MACH:
3981 return mach_trap_count;
3982 case SYSCALL_MASK_KOBJ:
3983 return mach_kobj_count;
3984 default:
3985 return 0;
cb323159 3986 }
cb323159
A
3987}
3988
3989int
3990proc_set_syscall_filter_mask(proc_t p, int which, unsigned char *maskptr, size_t masklen)
3991{
3992#if DEVELOPMENT || DEBUG
3993 if (syscallfilter_disable) {
3994 printf("proc_set_syscall_filter_mask: attempt to set policy for pid %d, but disabled by boot-arg\n", proc_pid(p));
f427ee49 3995 return 0;
cb323159
A
3996 }
3997#endif // DEVELOPMENT || DEBUG
3998
f427ee49
A
3999 switch (which) {
4000 case SYSCALL_MASK_UNIX:
4001 if (maskptr != NULL && masklen != nsysent) {
4002 return EINVAL;
4003 }
4004 p->syscall_filter_mask = maskptr;
4005 break;
4006 case SYSCALL_MASK_MACH:
4007 if (maskptr != NULL && masklen != (size_t)mach_trap_count) {
4008 return EINVAL;
4009 }
4010 mac_task_set_mach_filter_mask(p->task, maskptr);
4011 break;
4012 case SYSCALL_MASK_KOBJ:
4013 if (maskptr != NULL && masklen != (size_t)mach_kobj_count) {
4014 return EINVAL;
4015 }
4016 mac_task_set_kobj_filter_mask(p->task, maskptr);
4017 break;
4018 default:
4019 return EINVAL;
4020 }
4021
4022 return 0;
4023}
4024
4025int
4026proc_set_syscall_filter_callbacks(syscall_filter_cbs_t cbs)
4027{
4028 if (cbs->version != SYSCALL_FILTER_CALLBACK_VERSION) {
4029 return EINVAL;
4030 }
4031
4032 /* XXX register unix filter callback instead of using MACF hook. */
4033
4034 if (cbs->mach_filter_cbfunc || cbs->kobj_filter_cbfunc) {
4035 if (mac_task_register_filter_callbacks(cbs->mach_filter_cbfunc,
4036 cbs->kobj_filter_cbfunc) != 0) {
4037 return EPERM;
4038 }
4039 }
4040
4041 return 0;
4042}
4043
4044int
4045proc_set_syscall_filter_index(int which, int num, int index)
4046{
4047 switch (which) {
4048 case SYSCALL_MASK_KOBJ:
4049 if (ipc_kobject_set_kobjidx(num, index) != 0) {
4050 return ENOENT;
4051 }
4052 break;
4053 default:
4054 return EINVAL;
4055 }
4056
4057 return 0;
4058}
4059#endif /* CONFIG_MACF */
4060
4061int
4062proc_set_filter_message_flag(proc_t p, boolean_t flag)
4063{
4064 if (p == PROC_NULL) {
cb323159
A
4065 return EINVAL;
4066 }
4067
f427ee49 4068 task_set_filter_msg_flag(proc_task(p), flag);
cb323159 4069
f427ee49
A
4070 return 0;
4071}
4072
4073int
4074proc_get_filter_message_flag(proc_t p, boolean_t *flag)
4075{
4076 if (p == PROC_NULL || flag == NULL) {
4077 return EINVAL;
4078 }
4079
4080 *flag = task_get_filter_msg_flag(proc_task(p));
4081
4082 return 0;
cb323159
A
4083}
4084
eb6b6ca3
A
4085bool
4086proc_is_traced(proc_t p)
4087{
4088 bool ret = FALSE;
4089 assert(p != PROC_NULL);
4090 proc_lock(p);
4091 if (p->p_lflag & P_LTRACED) {
4092 ret = TRUE;
4093 }
4094 proc_unlock(p);
4095 return ret;
4096}
4097
527f9951
A
4098#ifdef CONFIG_32BIT_TELEMETRY
4099void
4100proc_log_32bit_telemetry(proc_t p)
4101{
4102 /* Gather info */
4103 char signature_buf[MAX_32BIT_EXEC_SIG_SIZE] = { 0 };
4104 char * signature_cur_end = &signature_buf[0];
4105 char * signature_buf_end = &signature_buf[MAX_32BIT_EXEC_SIG_SIZE - 1];
4106 int bytes_printed = 0;
4107
4108 const char * teamid = NULL;
4109 const char * identity = NULL;
4110 struct cs_blob * csblob = NULL;
4111
4112 proc_list_lock();
4113
4114 /*
4115 * Get proc name and parent proc name; if the parent execs, we'll get a
4116 * garbled name.
4117 */
4ba76501 4118 bytes_printed = scnprintf(signature_cur_end,
0a7de745
A
4119 signature_buf_end - signature_cur_end,
4120 "%s,%s,", p->p_name,
4121 (p->p_pptr ? p->p_pptr->p_name : ""));
527f9951
A
4122
4123 if (bytes_printed > 0) {
4124 signature_cur_end += bytes_printed;
4125 }
4126
4127 proc_list_unlock();
4128
4129 /* Get developer info. */
4130 vnode_t v = proc_getexecutablevnode(p);
4131
4132 if (v) {
4133 csblob = csvnode_get_blob(v, 0);
4134
4135 if (csblob) {
4136 teamid = csblob_get_teamid(csblob);
4137 identity = csblob_get_identity(csblob);
4138 }
4139 }
4140
4141 if (teamid == NULL) {
4142 teamid = "";
4143 }
4144
4145 if (identity == NULL) {
4146 identity = "";
4147 }
4148
4ba76501 4149 bytes_printed = scnprintf(signature_cur_end,
0a7de745
A
4150 signature_buf_end - signature_cur_end,
4151 "%s,%s", teamid, identity);
527f9951
A
4152
4153 if (bytes_printed > 0) {
4154 signature_cur_end += bytes_printed;
4155 }
4156
4157 if (v) {
4158 vnode_put(v);
4159 }
4160
4161 /*
4162 * We may want to rate limit here, although the SUMMARIZE key should
4163 * help us aggregate events in userspace.
4164 */
4165
4166 /* Emit log */
4167 kern_asl_msg(LOG_DEBUG, "messagetracer", 3,
0a7de745
A
4168 /* 0 */ "com.apple.message.domain", "com.apple.kernel.32bit_exec",
4169 /* 1 */ "com.apple.message.signature", signature_buf,
4170 /* 2 */ "com.apple.message.summarize", "YES",
4171 NULL);
527f9951
A
4172}
4173#endif /* CONFIG_32BIT_TELEMETRY */