]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_proc.c
xnu-3789.60.24.tar.gz
[apple/xnu.git] / bsd / kern / kern_proc.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* 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
72 * lodable modules.
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>
b0d623f7 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>
2d21ac55 114
39236c6e
A
115#if CONFIG_MEMORYSTATUS
116#include <sys/kern_memorystatus.h>
117#endif
118
2d21ac55
A
119#if CONFIG_MACF
120#include <security/mac_framework.h>
121#endif
122
123#include <libkern/crypto/sha1.h>
1c79356b
A
124
125/*
126 * Structure associated with user cacheing.
127 */
128struct uidinfo {
129 LIST_ENTRY(uidinfo) ui_hash;
130 uid_t ui_uid;
131 long ui_proccnt;
132};
133#define UIHASH(uid) (&uihashtbl[(uid) & uihash])
134LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
135u_long uihash; /* size of hash table - 1 */
136
137/*
138 * Other process lists
139 */
140struct pidhashhead *pidhashtbl;
141u_long pidhash;
142struct pgrphashhead *pgrphashtbl;
143u_long pgrphash;
2d21ac55
A
144struct sesshashhead *sesshashtbl;
145u_long sesshash;
146
1c79356b
A
147struct proclist allproc;
148struct proclist zombproc;
91447636 149extern struct tty cons;
1c79356b 150
39236c6e 151extern int cs_debug;
c331a0be 152
593a1d5f 153#if DEBUG
2d21ac55 154#define __PROC_INTERNAL_DEBUG 1
593a1d5f 155#endif
39037602 156#if CONFIG_COREDUMP
e5568f75 157/* Name to give to core files */
39236c6e 158__XNU_PRIVATE_EXTERN char corefilename[MAXPATHLEN+1] = {"/cores/core.%P"};
39037602 159#endif
e5568f75 160
3e170ce0 161#if PROC_REF_DEBUG
39037602 162#include <kern/backtrace.h>
3e170ce0
A
163#endif
164
39037602
A
165static void orphanpg(struct pgrp * pg);
166void proc_name_kdp(task_t t, char * buf, int size);
167void * proc_get_uthread_uu_threadlist(void * uthread_v);
168int proc_threadname_kdp(void * uth, char * buf, size_t size);
169void proc_starttime_kdp(void * p, uint64_t * tv_sec, uint64_t * tv_usec, uint64_t * abstime);
170char * proc_name_address(void * p);
171
172/* TODO: make a header that's exported and usable in osfmk */
173char* proc_best_name(proc_t p);
2d21ac55 174
2d21ac55
A
175static void pgrp_add(struct pgrp * pgrp, proc_t parent, proc_t child);
176static void pgrp_remove(proc_t p);
177static void pgrp_replace(proc_t p, struct pgrp *pgrp);
178static void pgdelete_dropref(struct pgrp *pgrp);
2d21ac55 179extern void pg_rele_dropref(struct pgrp * pgrp);
316670eb 180static int csops_internal(pid_t pid, int ops, user_addr_t uaddr, user_size_t usersize, user_addr_t uaddittoken);
39236c6e 181static boolean_t proc_parent_is_currentproc(proc_t p);
2d21ac55
A
182
183struct fixjob_iterargs {
184 struct pgrp * pg;
185 struct session * mysession;
186 int entering;
187};
188
189int fixjob_callback(proc_t, void *);
e5568f75 190
39037602
A
191uint64_t get_current_unique_pid(void);
192
193
194uint64_t
195get_current_unique_pid(void)
196{
197 proc_t p = current_proc();
198
199 if (p)
200 return p->p_uniqueid;
201 else
202 return 0;
203}
204
1c79356b
A
205/*
206 * Initialize global process hashing structures.
207 */
208void
2d21ac55 209procinit(void)
1c79356b 210{
1c79356b
A
211 LIST_INIT(&allproc);
212 LIST_INIT(&zombproc);
213 pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
214 pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
2d21ac55 215 sesshashtbl = hashinit(maxproc / 4, M_PROC, &sesshash);
1c79356b 216 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
490019cf
A
217#if CONFIG_PERSONAS
218 personas_bootstrap();
219#endif
1c79356b
A
220}
221
222/*
223 * Change the count associated with number of processes
2d21ac55
A
224 * a given user is using. This routine protects the uihash
225 * with the list lock
1c79356b
A
226 */
227int
2d21ac55 228chgproccnt(uid_t uid, int diff)
1c79356b 229{
2d21ac55
A
230 struct uidinfo *uip;
231 struct uidinfo *newuip = NULL;
232 struct uihashhead *uipp;
233 int retval;
1c79356b 234
2d21ac55
A
235again:
236 proc_list_lock();
1c79356b
A
237 uipp = UIHASH(uid);
238 for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next)
239 if (uip->ui_uid == uid)
240 break;
241 if (uip) {
242 uip->ui_proccnt += diff;
2d21ac55
A
243 if (uip->ui_proccnt > 0) {
244 retval = uip->ui_proccnt;
245 proc_list_unlock();
246 goto out;
247 }
1c79356b
A
248 if (uip->ui_proccnt < 0)
249 panic("chgproccnt: procs < 0");
250 LIST_REMOVE(uip, ui_hash);
2d21ac55
A
251 retval = 0;
252 proc_list_unlock();
253 FREE_ZONE(uip, sizeof(*uip), M_PROC);
254 goto out;
1c79356b
A
255 }
256 if (diff <= 0) {
2d21ac55
A
257 if (diff == 0) {
258 retval = 0;
259 proc_list_unlock();
260 goto out;
261 }
1c79356b
A
262 panic("chgproccnt: lost user");
263 }
2d21ac55
A
264 if (newuip != NULL) {
265 uip = newuip;
266 newuip = NULL;
267 LIST_INSERT_HEAD(uipp, uip, ui_hash);
268 uip->ui_uid = uid;
269 uip->ui_proccnt = diff;
270 retval = diff;
271 proc_list_unlock();
272 goto out;
273 }
274 proc_list_unlock();
275 MALLOC_ZONE(newuip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
276 if (newuip == NULL)
91447636 277 panic("chgproccnt: M_PROC zone depleted");
2d21ac55
A
278 goto again;
279out:
280 if (newuip != NULL)
281 FREE_ZONE(newuip, sizeof(*uip), M_PROC);
282 return(retval);
1c79356b
A
283}
284
285/*
286 * Is p an inferior of the current process?
287 */
288int
2d21ac55 289inferior(proc_t p)
1c79356b 290{
2d21ac55 291 int retval = 0;
1c79356b 292
2d21ac55 293 proc_list_lock();
1c79356b 294 for (; p != current_proc(); p = p->p_pptr)
2d21ac55
A
295 if (p->p_pid == 0)
296 goto out;
297 retval = 1;
298out:
299 proc_list_unlock();
300 return(retval);
1c79356b 301}
2d21ac55 302
9bccf70c
A
303/*
304 * Is p an inferior of t ?
305 */
306int
2d21ac55 307isinferior(proc_t p, proc_t t)
9bccf70c 308{
593a1d5f
A
309 int retval = 0;
310 int nchecked = 0;
311 proc_t start = p;
9bccf70c
A
312
313 /* if p==t they are not inferior */
314 if (p == t)
315 return(0);
2d21ac55
A
316
317 proc_list_lock();
593a1d5f
A
318 for (; p != t; p = p->p_pptr) {
319 nchecked++;
320
321 /* Detect here if we're in a cycle */
322 if ((p->p_pid == 0) || (p->p_pptr == start) || (nchecked >= nprocs))
2d21ac55 323 goto out;
593a1d5f 324 }
2d21ac55
A
325 retval = 1;
326out:
327 proc_list_unlock();
328 return(retval);
9bccf70c 329}
1c79356b 330
91447636
A
331int
332proc_isinferior(int pid1, int pid2)
333{
2d21ac55
A
334 proc_t p = PROC_NULL;
335 proc_t t = PROC_NULL;
336 int retval = 0;
337
338 if (((p = proc_find(pid1)) != (proc_t)0 ) && ((t = proc_find(pid2)) != (proc_t)0))
339 retval = isinferior(p, t);
91447636 340
2d21ac55
A
341 if (p != PROC_NULL)
342 proc_rele(p);
343 if (t != PROC_NULL)
344 proc_rele(t);
345
346 return(retval);
91447636
A
347}
348
349proc_t
350proc_find(int pid)
351{
2d21ac55 352 return(proc_findinternal(pid, 0));
91447636
A
353}
354
2d21ac55
A
355proc_t
356proc_findinternal(int pid, int locked)
91447636 357{
2d21ac55
A
358 proc_t p = PROC_NULL;
359
360 if (locked == 0) {
361 proc_list_lock();
362 }
363
364 p = pfind_locked(pid);
6d2010ae 365 if ((p == PROC_NULL) || (p != proc_ref_locked(p)))
2d21ac55
A
366 p = PROC_NULL;
367
368 if (locked == 0) {
369 proc_list_unlock();
370 }
371
372 return(p);
91447636
A
373}
374
316670eb
A
375proc_t
376proc_findthread(thread_t thread)
377{
378 proc_t p = PROC_NULL;
379 struct uthread *uth;
380
381 proc_list_lock();
382 uth = get_bsdthread_info(thread);
383 if (uth && (uth->uu_flag & UT_VFORK))
384 p = uth->uu_proc;
385 else
386 p = (proc_t)(get_bsdthreadtask_info(thread));
387 p = proc_ref_locked(p);
388 proc_list_unlock();
389 return(p);
390}
391
3e170ce0
A
392void
393uthread_reset_proc_refcount(void *uthread) {
394 uthread_t uth;
395
813fb2f6
A
396 uth = (uthread_t) uthread;
397 uth->uu_proc_refcount = 0;
398
399#if PROC_REF_DEBUG
3e170ce0
A
400 if (proc_ref_tracking_disabled) {
401 return;
402 }
403
3e170ce0 404 uth->uu_pindex = 0;
813fb2f6 405#endif
3e170ce0
A
406}
407
813fb2f6 408#if PROC_REF_DEBUG
3e170ce0
A
409int
410uthread_get_proc_refcount(void *uthread) {
411 uthread_t uth;
412
413 if (proc_ref_tracking_disabled) {
414 return 0;
415 }
416
417 uth = (uthread_t) uthread;
418
419 return uth->uu_proc_refcount;
420}
813fb2f6 421#endif
3e170ce0
A
422
423static void
813fb2f6 424record_procref(proc_t p __unused, int count) {
3e170ce0
A
425 uthread_t uth;
426
813fb2f6
A
427 uth = current_uthread();
428 uth->uu_proc_refcount += count;
429
430#if PROC_REF_DEBUG
3e170ce0
A
431 if (proc_ref_tracking_disabled) {
432 return;
433 }
434
3e170ce0
A
435 if (count == 1) {
436 if (uth->uu_pindex < NUM_PROC_REFS_TO_TRACK) {
39037602 437 backtrace((uintptr_t *) &uth->uu_proc_pcs[uth->uu_pindex], PROC_REF_STACK_DEPTH);
3e170ce0
A
438
439 uth->uu_proc_ps[uth->uu_pindex] = p;
440 uth->uu_pindex++;
441 }
442 }
3e170ce0 443#endif
813fb2f6
A
444}
445
446static boolean_t
447uthread_needs_to_wait_in_proc_refwait(void) {
448 uthread_t uth = current_uthread();
449
450 /*
451 * Allow threads holding no proc refs to wait
452 * in proc_refwait, allowing threads holding
453 * proc refs to wait in proc_refwait causes
454 * deadlocks and makes proc_find non-reentrant.
455 */
456 if (uth->uu_proc_refcount == 0)
457 return TRUE;
458
459 return FALSE;
460}
3e170ce0 461
2d21ac55
A
462int
463proc_rele(proc_t p)
91447636 464{
2d21ac55
A
465 proc_list_lock();
466 proc_rele_locked(p);
467 proc_list_unlock();
468
469 return(0);
91447636
A
470}
471
ff6e181a 472proc_t
2d21ac55 473proc_self(void)
ff6e181a 474{
2d21ac55 475 struct proc * p;
ff6e181a 476
2d21ac55
A
477 p = current_proc();
478
479 proc_list_lock();
6d2010ae 480 if (p != proc_ref_locked(p))
ff6e181a 481 p = PROC_NULL;
2d21ac55 482 proc_list_unlock();
ff6e181a
A
483 return(p);
484}
485
2d21ac55 486
6d2010ae
A
487proc_t
488proc_ref_locked(proc_t p)
ff6e181a 489{
2d21ac55
A
490 proc_t p1 = p;
491
492 /* if process still in creation return failure */
493 if ((p == PROC_NULL) || ((p->p_listflag & P_LIST_INCREATE) != 0))
494 return (PROC_NULL);
743345f9
A
495retry:
496 /*
497 * Do not return process marked for termination
498 * or proc_refdrain called without ref wait.
499 * Wait for proc_refdrain_with_refwait to complete if
813fb2f6
A
500 * process in refdrain and refwait flag is set, unless
501 * the current thread is holding to a proc_ref
502 * for any proc.
743345f9
A
503 */
504 if ((p->p_stat != SZOMB) &&
505 ((p->p_listflag & P_LIST_EXITED) == 0) &&
506 ((p->p_listflag & P_LIST_DEAD) == 0) &&
507 (((p->p_listflag & (P_LIST_DRAIN | P_LIST_DRAINWAIT)) == 0) ||
508 ((p->p_listflag & P_LIST_REFWAIT) != 0))) {
813fb2f6 509 if ((p->p_listflag & P_LIST_REFWAIT) != 0 && uthread_needs_to_wait_in_proc_refwait()) {
743345f9
A
510 msleep(&p->p_listflag, proc_list_mlock, 0, "proc_refwait", 0) ;
511 goto retry;
512 }
2d21ac55 513 p->p_refcount++;
3e170ce0 514 record_procref(p, 1);
3e170ce0 515 }
2d21ac55
A
516 else
517 p1 = PROC_NULL;
ff6e181a 518
2d21ac55 519 return(p1);
ff6e181a
A
520}
521
2d21ac55
A
522void
523proc_rele_locked(proc_t p)
524{
ff6e181a 525
2d21ac55
A
526 if (p->p_refcount > 0) {
527 p->p_refcount--;
3e170ce0 528 record_procref(p, -1);
2d21ac55
A
529 if ((p->p_refcount == 0) && ((p->p_listflag & P_LIST_DRAINWAIT) == P_LIST_DRAINWAIT)) {
530 p->p_listflag &= ~P_LIST_DRAINWAIT;
531 wakeup(&p->p_refcount);
532 }
533 } else
534 panic("proc_rele_locked -ve ref\n");
535
536}
537
6d2010ae 538proc_t
2d21ac55 539proc_find_zombref(int pid)
ff6e181a 540{
39236c6e 541 proc_t p;
ff6e181a 542
2d21ac55 543 proc_list_lock();
ff6e181a 544
39236c6e 545 again:
2d21ac55
A
546 p = pfind_locked(pid);
547
39236c6e
A
548 /* should we bail? */
549 if ((p == PROC_NULL) /* not found */
550 || ((p->p_listflag & P_LIST_INCREATE) != 0) /* not created yet */
551 || ((p->p_listflag & P_LIST_EXITED) == 0)) { /* not started exit */
552
2d21ac55 553 proc_list_unlock();
39236c6e 554 return (PROC_NULL);
2d21ac55
A
555 }
556
39236c6e
A
557 /* If someone else is controlling the (unreaped) zombie - wait */
558 if ((p->p_listflag & P_LIST_WAITING) != 0) {
559 (void)msleep(&p->p_stat, proc_list_mlock, PWAIT, "waitcoll", 0);
560 goto again;
561 }
562 p->p_listflag |= P_LIST_WAITING;
ff6e181a 563
2d21ac55
A
564 proc_list_unlock();
565
39236c6e 566 return(p);
ff6e181a
A
567}
568
6d2010ae 569void
2d21ac55
A
570proc_drop_zombref(proc_t p)
571{
572 proc_list_lock();
573 if ((p->p_listflag & P_LIST_WAITING) == P_LIST_WAITING) {
574 p->p_listflag &= ~P_LIST_WAITING;
575 wakeup(&p->p_stat);
576 }
577 proc_list_unlock();
578}
579
580
ff6e181a 581void
2d21ac55
A
582proc_refdrain(proc_t p)
583{
743345f9
A
584 proc_refdrain_with_refwait(p, FALSE);
585}
2d21ac55 586
743345f9
A
587proc_t
588proc_refdrain_with_refwait(proc_t p, boolean_t get_ref_and_allow_wait)
589{
590 boolean_t initexec = FALSE;
2d21ac55
A
591 proc_list_lock();
592
593 p->p_listflag |= P_LIST_DRAIN;
743345f9
A
594 if (get_ref_and_allow_wait) {
595 /*
596 * All the calls to proc_ref_locked will wait
813fb2f6
A
597 * for the flag to get cleared before returning a ref,
598 * unless the current thread is holding to a proc ref
599 * for any proc.
743345f9
A
600 */
601 p->p_listflag |= P_LIST_REFWAIT;
602 if (p == initproc) {
603 initexec = TRUE;
604 }
605 }
606
607 /* Do not wait in ref drain for launchd exec */
608 while (p->p_refcount && !initexec) {
2d21ac55
A
609 p->p_listflag |= P_LIST_DRAINWAIT;
610 msleep(&p->p_refcount, proc_list_mlock, 0, "proc_refdrain", 0) ;
611 }
743345f9 612
2d21ac55 613 p->p_listflag &= ~P_LIST_DRAIN;
743345f9
A
614 if (!get_ref_and_allow_wait) {
615 p->p_listflag |= P_LIST_DEAD;
616 } else {
617 /* Return a ref to the caller */
618 p->p_refcount++;
743345f9 619 record_procref(p, 1);
743345f9 620 }
2d21ac55
A
621
622 proc_list_unlock();
623
743345f9
A
624 if (get_ref_and_allow_wait) {
625 return (p);
626 }
627 return NULL;
628}
2d21ac55 629
743345f9
A
630void
631proc_refwake(proc_t p)
632{
633 proc_list_lock();
634 p->p_listflag &= ~P_LIST_REFWAIT;
635 wakeup(&p->p_listflag);
636 proc_list_unlock();
2d21ac55
A
637}
638
639proc_t
640proc_parentholdref(proc_t p)
ff6e181a 641{
2d21ac55
A
642 proc_t parent = PROC_NULL;
643 proc_t pp;
644 int loopcnt = 0;
645
ff6e181a 646
2d21ac55
A
647 proc_list_lock();
648loop:
649 pp = p->p_pptr;
650 if ((pp == PROC_NULL) || (pp->p_stat == SZOMB) || ((pp->p_listflag & (P_LIST_CHILDDRSTART | P_LIST_CHILDDRAINED)) == (P_LIST_CHILDDRSTART | P_LIST_CHILDDRAINED))) {
651 parent = PROC_NULL;
652 goto out;
653 }
654
655 if ((pp->p_listflag & (P_LIST_CHILDDRSTART | P_LIST_CHILDDRAINED)) == P_LIST_CHILDDRSTART) {
656 pp->p_listflag |= P_LIST_CHILDDRWAIT;
657 msleep(&pp->p_childrencnt, proc_list_mlock, 0, "proc_parent", 0);
658 loopcnt++;
659 if (loopcnt == 5) {
660 parent = PROC_NULL;
661 goto out;
662 }
663 goto loop;
664 }
ff6e181a 665
2d21ac55
A
666 if ((pp->p_listflag & (P_LIST_CHILDDRSTART | P_LIST_CHILDDRAINED)) == 0) {
667 pp->p_parentref++;
668 parent = pp;
669 goto out;
670 }
671
672out:
673 proc_list_unlock();
674 return(parent);
675}
676int
677proc_parentdropref(proc_t p, int listlocked)
678{
679 if (listlocked == 0)
680 proc_list_lock();
681
682 if (p->p_parentref > 0) {
683 p->p_parentref--;
684 if ((p->p_parentref == 0) && ((p->p_listflag & P_LIST_PARENTREFWAIT) == P_LIST_PARENTREFWAIT)) {
685 p->p_listflag &= ~P_LIST_PARENTREFWAIT;
686 wakeup(&p->p_parentref);
ff6e181a
A
687 }
688 } else
2d21ac55
A
689 panic("proc_parentdropref -ve ref\n");
690 if (listlocked == 0)
691 proc_list_unlock();
692
693 return(0);
694}
ff6e181a 695
2d21ac55
A
696void
697proc_childdrainstart(proc_t p)
698{
699#if __PROC_INTERNAL_DEBUG
700 if ((p->p_listflag & P_LIST_CHILDDRSTART) == P_LIST_CHILDDRSTART)
701 panic("proc_childdrainstart: childdrain already started\n");
702#endif
703 p->p_listflag |= P_LIST_CHILDDRSTART;
704 /* wait for all that hold parentrefs to drop */
705 while (p->p_parentref > 0) {
706 p->p_listflag |= P_LIST_PARENTREFWAIT;
707 msleep(&p->p_parentref, proc_list_mlock, 0, "proc_childdrainstart", 0) ;
708 }
709}
710
711
712void
713proc_childdrainend(proc_t p)
714{
715#if __PROC_INTERNAL_DEBUG
716 if (p->p_childrencnt > 0)
717 panic("exiting: children stil hanging around\n");
718#endif
719 p->p_listflag |= P_LIST_CHILDDRAINED;
720 if ((p->p_listflag & (P_LIST_CHILDLKWAIT |P_LIST_CHILDDRWAIT)) != 0) {
721 p->p_listflag &= ~(P_LIST_CHILDLKWAIT |P_LIST_CHILDDRWAIT);
722 wakeup(&p->p_childrencnt);
723 }
ff6e181a
A
724}
725
2d21ac55 726void
593a1d5f 727proc_checkdeadrefs(__unused proc_t p)
2d21ac55 728{
593a1d5f 729#if __PROC_INTERNAL_DEBUG
2d21ac55 730 if ((p->p_listflag & P_LIST_INHASH) != 0)
b0d623f7 731 panic("proc being freed and still in hash %p: %u\n", p, p->p_listflag);
2d21ac55 732 if (p->p_childrencnt != 0)
b0d623f7 733 panic("proc being freed and pending children cnt %p:%d\n", p, p->p_childrencnt);
2d21ac55 734 if (p->p_refcount != 0)
b0d623f7 735 panic("proc being freed and pending refcount %p:%d\n", p, p->p_refcount);
2d21ac55 736 if (p->p_parentref != 0)
b0d623f7 737 panic("proc being freed and pending parentrefs %p:%d\n", p, p->p_parentref);
593a1d5f 738#endif
2d21ac55 739}
91447636
A
740
741int
742proc_pid(proc_t p)
743{
3e170ce0
A
744 if (p != NULL)
745 return (p->p_pid);
746 return -1;
91447636
A
747}
748
3e170ce0 749int
91447636
A
750proc_ppid(proc_t p)
751{
3e170ce0
A
752 if (p != NULL)
753 return (p->p_ppid);
754 return -1;
91447636
A
755}
756
39236c6e 757int
91447636
A
758proc_selfpid(void)
759{
39236c6e 760 return (current_proc()->p_pid);
91447636
A
761}
762
39236c6e 763int
91447636
A
764proc_selfppid(void)
765{
39236c6e
A
766 return (current_proc()->p_ppid);
767}
768
490019cf
A
769int
770proc_selfcsflags(void)
771{
772 return (current_proc()->p_csflags);
773}
774
39236c6e
A
775#if CONFIG_DTRACE
776static proc_t
777dtrace_current_proc_vforking(void)
778{
779 thread_t th = current_thread();
780 struct uthread *ut = get_bsdthread_info(th);
781
782 if (ut &&
783 ((ut->uu_flag & (UT_VFORK|UT_VFORKING)) == (UT_VFORK|UT_VFORKING))) {
784 /*
785 * Handle the narrow window where we're in the vfork syscall,
786 * but we're not quite ready to claim (in particular, to DTrace)
787 * that we're running as the child.
788 */
789 return (get_bsdtask_info(get_threadtask(th)));
790 }
791 return (current_proc());
792}
793
794int
795dtrace_proc_selfpid(void)
796{
797 return (dtrace_current_proc_vforking()->p_pid);
2d21ac55
A
798}
799
39236c6e
A
800int
801dtrace_proc_selfppid(void)
802{
803 return (dtrace_current_proc_vforking()->p_ppid);
804}
805
806uid_t
807dtrace_proc_selfruid(void)
808{
809 return (dtrace_current_proc_vforking()->p_ruid);
810}
811#endif /* CONFIG_DTRACE */
812
2d21ac55
A
813proc_t
814proc_parent(proc_t p)
815{
816 proc_t parent;
817 proc_t pp;
818
819 proc_list_lock();
820loop:
821 pp = p->p_pptr;
6d2010ae 822 parent = proc_ref_locked(pp);
2d21ac55
A
823 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)){
824 pp->p_listflag |= P_LIST_CHILDLKWAIT;
825 msleep(&pp->p_childrencnt, proc_list_mlock, 0, "proc_parent", 0);
826 goto loop;
827 }
828 proc_list_unlock();
829 return(parent);
91447636
A
830}
831
39236c6e
A
832static boolean_t
833proc_parent_is_currentproc(proc_t p)
834{
835 boolean_t ret = FALSE;
836
837 proc_list_lock();
838 if (p->p_pptr == current_proc())
839 ret = TRUE;
840
841 proc_list_unlock();
842 return ret;
843}
2d21ac55 844
91447636
A
845void
846proc_name(int pid, char * buf, int size)
847{
2d21ac55 848 proc_t p;
91447636 849
2d21ac55
A
850 if ((p = proc_find(pid)) != PROC_NULL) {
851 strlcpy(buf, &p->p_comm[0], size);
852 proc_rele(p);
91447636
A
853 }
854}
855
2d21ac55
A
856void
857proc_name_kdp(task_t t, char * buf, int size)
858{
859 proc_t p = get_bsdtask_info(t);
3e170ce0
A
860 if (p == PROC_NULL)
861 return;
2d21ac55 862
3e170ce0
A
863 if ((size_t)size > sizeof(p->p_comm))
864 strlcpy(buf, &p->p_name[0], MIN((int)sizeof(p->p_name), size));
865 else
866 strlcpy(buf, &p->p_comm[0], MIN((int)sizeof(p->p_comm), size));
2d21ac55
A
867}
868
fe8ab488 869int
39037602 870proc_threadname_kdp(void * uth, char * buf, size_t size)
fe8ab488
A
871{
872 if (size < MAXTHREADNAMESIZE) {
873 /* this is really just a protective measure for the future in
874 * case the thread name size in stackshot gets out of sync with
875 * the BSD max thread name size. Note that bsd_getthreadname
876 * doesn't take input buffer size into account. */
877 return -1;
878 }
879
880 if (uth != NULL) {
881 bsd_getthreadname(uth, buf);
882 }
883 return 0;
884}
885
886/* note that this function is generally going to be called from stackshot,
887 * and the arguments will be coming from a struct which is declared packed
888 * thus the input arguments will in general be unaligned. We have to handle
889 * that here. */
890void
39037602 891proc_starttime_kdp(void *p, uint64_t *tv_sec, uint64_t *tv_usec, uint64_t *abstime)
fe8ab488
A
892{
893 proc_t pp = (proc_t)p;
894 struct uint64p {
895 uint64_t val;
896 } __attribute__((packed));
897
898 if (pp != PROC_NULL) {
899 if (tv_sec != NULL)
900 ((struct uint64p *)tv_sec)->val = pp->p_start.tv_sec;
901 if (tv_usec != NULL)
902 ((struct uint64p *)tv_usec)->val = pp->p_start.tv_usec;
39037602
A
903 if (abstime != NULL) {
904 if (pp->p_stats != NULL)
905 *abstime = pp->p_stats->ps_start;
906 else
907 *abstime = 0;
908 }
fe8ab488
A
909 }
910}
911
2d21ac55
A
912char *
913proc_name_address(void *p)
914{
915 return &((proc_t)p)->p_comm[0];
916}
917
39037602
A
918char *
919proc_best_name(proc_t p)
920{
921 if (p->p_name[0] != 0)
922 return (&p->p_name[0]);
923 return (&p->p_comm[0]);
924}
925
91447636
A
926void
927proc_selfname(char * buf, int size)
928{
2d21ac55 929 proc_t p;
91447636 930
2d21ac55
A
931 if ((p = current_proc())!= (proc_t)0) {
932 strlcpy(buf, &p->p_comm[0], size);
91447636
A
933 }
934}
935
936void
937proc_signal(int pid, int signum)
938{
939 proc_t p;
940
2d21ac55 941 if ((p = proc_find(pid)) != PROC_NULL) {
91447636 942 psignal(p, signum);
2d21ac55 943 proc_rele(p);
91447636
A
944 }
945}
946
947int
948proc_issignal(int pid, sigset_t mask)
949{
950 proc_t p;
2d21ac55 951 int error=0;
91447636 952
2d21ac55
A
953 if ((p = proc_find(pid)) != PROC_NULL) {
954 error = proc_pendingsignals(p, mask);
955 proc_rele(p);
91447636 956 }
2d21ac55
A
957
958 return(error);
91447636
A
959}
960
961int
962proc_noremotehang(proc_t p)
963{
964 int retval = 0;
965
966 if (p)
967 retval = p->p_flag & P_NOREMOTEHANG;
968 return(retval? 1: 0);
969
970}
971
972int
973proc_exiting(proc_t p)
974{
975 int retval = 0;
976
977 if (p)
2d21ac55 978 retval = p->p_lflag & P_LEXIT;
91447636
A
979 return(retval? 1: 0);
980}
981
91447636
A
982int
983proc_forcequota(proc_t p)
984{
985 int retval = 0;
986
987 if (p)
988 retval = p->p_flag & P_FORCEQUOTA;
989 return(retval? 1: 0);
990
991}
992
91447636
A
993int
994proc_suser(proc_t p)
995{
2d21ac55
A
996 kauth_cred_t my_cred;
997 int error;
998
999 my_cred = kauth_cred_proc_ref(p);
1000 error = suser(my_cred, &p->p_acflag);
1001 kauth_cred_unref(&my_cred);
1002 return(error);
91447636
A
1003}
1004
316670eb
A
1005task_t
1006proc_task(proc_t proc)
1007{
1008 return (task_t)proc->task;
1009}
1010
2d21ac55
A
1011/*
1012 * Obtain the first thread in a process
1013 *
1014 * XXX This is a bad thing to do; it exists predominantly to support the
1015 * XXX use of proc_t's in places that should really be using
1016 * XXX thread_t's instead. This maintains historical behaviour, but really
1017 * XXX needs an audit of the context (proxy vs. not) to clean up.
1018 */
1019thread_t
1020proc_thread(proc_t proc)
1021{
1022 uthread_t uth = TAILQ_FIRST(&proc->p_uthlist);
1023
1024 if (uth != NULL)
1025 return(uth->uu_context.vc_thread);
1026
1027 return(NULL);
1028}
1029
91447636
A
1030kauth_cred_t
1031proc_ucred(proc_t p)
1032{
1033 return(p->p_ucred);
1034}
1035
b0d623f7
A
1036struct uthread *
1037current_uthread()
1038{
1039 thread_t th = current_thread();
1040
1041 return((struct uthread *)get_bsdthread_info(th));
1042}
1043
1044
91447636
A
1045int
1046proc_is64bit(proc_t p)
1047{
1048 return(IS_64BIT_PROCESS(p));
1049}
1050
593a1d5f
A
1051int
1052proc_pidversion(proc_t p)
1053{
1054 return(p->p_idversion);
1055}
1056
490019cf
A
1057uint32_t
1058proc_persona_id(proc_t p)
1059{
1060 return (uint32_t)persona_id_from_proc(p);
1061}
1062
1063uint32_t
1064proc_getuid(proc_t p)
1065{
1066 return(p->p_uid);
1067}
1068
1069uint32_t
1070proc_getgid(proc_t p)
1071{
1072 return(p->p_gid);
1073}
1074
6d2010ae
A
1075uint64_t
1076proc_uniqueid(proc_t p)
1077{
1078 return(p->p_uniqueid);
1079}
1080
1081uint64_t
39236c6e 1082proc_puniqueid(proc_t p)
6d2010ae 1083{
39236c6e
A
1084 return(p->p_puniqueid);
1085}
1086
3e170ce0
A
1087void
1088proc_coalitionids(__unused proc_t p, __unused uint64_t ids[COALITION_NUM_TYPES])
fe8ab488
A
1089{
1090#if CONFIG_COALITIONS
3e170ce0 1091 task_coalition_ids(p->task, ids);
fe8ab488 1092#else
3e170ce0 1093 memset(ids, 0, sizeof(uint64_t [COALITION_NUM_TYPES]));
fe8ab488 1094#endif
3e170ce0 1095 return;
fe8ab488
A
1096}
1097
39236c6e
A
1098uint64_t
1099proc_was_throttled(proc_t p)
1100{
1101 return (p->was_throttled);
1102}
1103
1104uint64_t
1105proc_did_throttle(proc_t p)
1106{
1107 return (p->did_throttle);
6d2010ae
A
1108}
1109
593a1d5f
A
1110int
1111proc_getcdhash(proc_t p, unsigned char *cdhash)
1112{
1113 return vn_getcdhash(p->p_textvp, p->p_textoff, cdhash);
1114}
1115
6d2010ae
A
1116void
1117proc_getexecutableuuid(proc_t p, unsigned char *uuidbuf, unsigned long size)
1118{
1119 if (size >= sizeof(p->p_uuid)) {
1120 memcpy(uuidbuf, p->p_uuid, sizeof(p->p_uuid));
1121 }
1122}
1123
fe8ab488
A
1124/* Return vnode for executable with an iocount. Must be released with vnode_put() */
1125vnode_t
1126proc_getexecutablevnode(proc_t p)
1127{
1128 vnode_t tvp = p->p_textvp;
1129
1130 if ( tvp != NULLVP) {
1131 if (vnode_getwithref(tvp) == 0) {
1132 return tvp;
1133 }
1134 }
1135
1136 return NULLVP;
1137}
1138
6d2010ae 1139
2d21ac55
A
1140void
1141bsd_set_dependency_capable(task_t task)
1142{
1143 proc_t p = get_bsdtask_info(task);
1144
1145 if (p) {
b0d623f7 1146 OSBitOrAtomic(P_DEPENDENCY_CAPABLE, &p->p_flag);
2d21ac55
A
1147 }
1148}
1149
1150
91447636
A
1151int
1152IS_64BIT_PROCESS(proc_t p)
1153{
1154 if (p && (p->p_flag & P_LP64))
1155 return(1);
1156 else
1157 return(0);
1158}
1159
1c79356b
A
1160/*
1161 * Locate a process by number
1162 */
2d21ac55
A
1163proc_t
1164pfind_locked(pid_t pid)
1c79356b 1165{
2d21ac55 1166 proc_t p;
b0d623f7 1167#if DEBUG
2d21ac55
A
1168 proc_t q;
1169#endif
1c79356b
A
1170
1171 if (!pid)
1172 return (kernproc);
1173
2d21ac55
A
1174 for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next) {
1175 if (p->p_pid == pid) {
b0d623f7 1176#if DEBUG
2d21ac55
A
1177 for (q = p->p_hash.le_next; q != 0; q = q->p_hash.le_next) {
1178 if ((p !=q) && (q->p_pid == pid))
b0d623f7 1179 panic("two procs with same pid %p:%p:%d:%d\n", p, q, p->p_pid, q->p_pid);
2d21ac55
A
1180 }
1181#endif
1c79356b 1182 return (p);
2d21ac55
A
1183 }
1184 }
1c79356b
A
1185 return (NULL);
1186}
1187
55e303ae
A
1188/*
1189 * Locate a zombie by PID
1190 */
2d21ac55
A
1191__private_extern__ proc_t
1192pzfind(pid_t pid)
55e303ae 1193{
2d21ac55
A
1194 proc_t p;
1195
1196
1197 proc_list_lock();
55e303ae
A
1198
1199 for (p = zombproc.lh_first; p != 0; p = p->p_list.le_next)
1200 if (p->p_pid == pid)
2d21ac55
A
1201 break;
1202
1203 proc_list_unlock();
1204
1205 return (p);
55e303ae
A
1206}
1207
1c79356b
A
1208/*
1209 * Locate a process group by number
1210 */
2d21ac55 1211
1c79356b 1212struct pgrp *
2d21ac55 1213pgfind(pid_t pgid)
1c79356b 1214{
2d21ac55
A
1215 struct pgrp * pgrp;
1216
1217 proc_list_lock();
1218 pgrp = pgfind_internal(pgid);
1219 if ((pgrp == NULL) || ((pgrp->pg_listflags & PGRP_FLAG_TERMINATE) != 0))
1220 pgrp = PGRP_NULL;
1221 else
1222 pgrp->pg_refcount++;
1223 proc_list_unlock();
1224 return(pgrp);
1225}
1226
1227
1228
1229struct pgrp *
1230pgfind_internal(pid_t pgid)
1231{
1232 struct pgrp *pgrp;
1c79356b
A
1233
1234 for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next)
1235 if (pgrp->pg_id == pgid)
1236 return (pgrp);
1237 return (NULL);
1238}
1239
2d21ac55
A
1240void
1241pg_rele(struct pgrp * pgrp)
1242{
1243 if(pgrp == PGRP_NULL)
1244 return;
1245 pg_rele_dropref(pgrp);
1246}
1247
1248void
1249pg_rele_dropref(struct pgrp * pgrp)
1250{
1251 proc_list_lock();
1252 if ((pgrp->pg_refcount == 1) && ((pgrp->pg_listflags & PGRP_FLAG_TERMINATE) == PGRP_FLAG_TERMINATE)) {
1253 proc_list_unlock();
1254 pgdelete_dropref(pgrp);
1255 return;
1256 }
1257
1258 pgrp->pg_refcount--;
1259 proc_list_unlock();
1260}
1261
1262struct session *
1263session_find_internal(pid_t sessid)
1264{
1265 struct session *sess;
1266
1267 for (sess = SESSHASH(sessid)->lh_first; sess != 0; sess = sess->s_hash.le_next)
1268 if (sess->s_sid == sessid)
1269 return (sess);
1270 return (NULL);
1271}
1272
1273
1274/*
1275 * Make a new process ready to become a useful member of society by making it
1276 * visible in all the right places and initialize its own lists to empty.
1277 *
1278 * Parameters: parent The parent of the process to insert
1279 * child The child process to insert
1280 *
1281 * Returns: (void)
1282 *
1283 * Notes: Insert a child process into the parents process group, assign
1284 * the child the parent process pointer and PPID of the parent,
1285 * place it on the parents p_children list as a sibling,
1286 * initialize its own child list, place it in the allproc list,
1287 * insert it in the proper hash bucket, and initialize its
1288 * event list.
1289 */
1290void
1291pinsertchild(proc_t parent, proc_t child)
1292{
1293 struct pgrp * pg;
1294
1295 LIST_INIT(&child->p_children);
1296 TAILQ_INIT(&child->p_evlist);
1297 child->p_pptr = parent;
1298 child->p_ppid = parent->p_pid;
39236c6e 1299 child->p_puniqueid = parent->p_uniqueid;
2d21ac55
A
1300
1301 pg = proc_pgrp(parent);
1302 pgrp_add(pg, parent, child);
1303 pg_rele(pg);
1304
1305 proc_list_lock();
39236c6e
A
1306
1307#if CONFIG_MEMORYSTATUS
1308 memorystatus_add(child, TRUE);
1309#endif
1310
2d21ac55
A
1311 parent->p_childrencnt++;
1312 LIST_INSERT_HEAD(&parent->p_children, child, p_sibling);
1313
1314 LIST_INSERT_HEAD(&allproc, child, p_list);
1315 /* mark the completion of proc creation */
1316 child->p_listflag &= ~P_LIST_INCREATE;
1317
1318 proc_list_unlock();
2d21ac55 1319}
1c79356b
A
1320
1321/*
1322 * Move p to a new or existing process group (and session)
2d21ac55
A
1323 *
1324 * Returns: 0 Success
1325 * ESRCH No such process
1c79356b
A
1326 */
1327int
2d21ac55 1328enterpgrp(proc_t p, pid_t pgid, int mksess)
1c79356b 1329{
2d21ac55
A
1330 struct pgrp *pgrp;
1331 struct pgrp *mypgrp;
1332 struct session * procsp;
1333
1334 pgrp = pgfind(pgid);
1335 mypgrp = proc_pgrp(p);
1336 procsp = proc_session(p);
1c79356b
A
1337
1338#if DIAGNOSTIC
1339 if (pgrp != NULL && mksess) /* firewalls */
1340 panic("enterpgrp: setsid into non-empty pgrp");
2d21ac55 1341 if (SESS_LEADER(p, procsp))
1c79356b
A
1342 panic("enterpgrp: session leader attempted setpgrp");
1343#endif
2d21ac55 1344 if (pgrp == PGRP_NULL) {
1c79356b 1345 pid_t savepid = p->p_pid;
2d21ac55 1346 proc_t np = PROC_NULL;
1c79356b
A
1347 /*
1348 * new process group
1349 */
1350#if DIAGNOSTIC
1351 if (p->p_pid != pgid)
1352 panic("enterpgrp: new pgrp and pid != pgid");
1353#endif
1354 MALLOC_ZONE(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
1355 M_WAITOK);
91447636
A
1356 if (pgrp == NULL)
1357 panic("enterpgrp: M_PGRP zone depleted");
2d21ac55
A
1358 if ((np = proc_find(savepid)) == NULL || np != p) {
1359 if (np != PROC_NULL)
1360 proc_rele(np);
1361 if (mypgrp != PGRP_NULL)
1362 pg_rele(mypgrp);
1363 if (procsp != SESSION_NULL)
1364 session_rele(procsp);
9bccf70c 1365 FREE_ZONE(pgrp, sizeof(struct pgrp), M_PGRP);
1c79356b 1366 return (ESRCH);
9bccf70c 1367 }
2d21ac55 1368 proc_rele(np);
1c79356b 1369 if (mksess) {
2d21ac55 1370 struct session *sess;
1c79356b
A
1371
1372 /*
1373 * new session
1374 */
1375 MALLOC_ZONE(sess, struct session *,
1376 sizeof(struct session), M_SESSION, M_WAITOK);
91447636
A
1377 if (sess == NULL)
1378 panic("enterpgrp: M_SESSION zone depleted");
1c79356b 1379 sess->s_leader = p;
9bccf70c 1380 sess->s_sid = p->p_pid;
1c79356b
A
1381 sess->s_count = 1;
1382 sess->s_ttyvp = NULL;
b0d623f7 1383 sess->s_ttyp = TTY_NULL;
2d21ac55
A
1384 sess->s_flags = 0;
1385 sess->s_listflags = 0;
1386 sess->s_ttypgrpid = NO_PID;
6d2010ae 1387#if CONFIG_FINE_LOCK_GROUPS
b0d623f7 1388 lck_mtx_init(&sess->s_mlock, proc_mlock_grp, proc_lck_attr);
6d2010ae
A
1389#else
1390 lck_mtx_init(&sess->s_mlock, proc_lck_grp, proc_lck_attr);
b0d623f7 1391#endif
2d21ac55 1392 bcopy(procsp->s_login, sess->s_login,
1c79356b 1393 sizeof(sess->s_login));
b0d623f7 1394 OSBitAndAtomic(~((uint32_t)P_CONTROLT), &p->p_flag);
2d21ac55
A
1395 proc_list_lock();
1396 LIST_INSERT_HEAD(SESSHASH(sess->s_sid), sess, s_hash);
1397 proc_list_unlock();
1c79356b
A
1398 pgrp->pg_session = sess;
1399#if DIAGNOSTIC
1400 if (p != current_proc())
1401 panic("enterpgrp: mksession and p != curproc");
1402#endif
1403 } else {
2d21ac55
A
1404 proc_list_lock();
1405 pgrp->pg_session = procsp;
1406
1407 if ((pgrp->pg_session->s_listflags & (S_LIST_TERM | S_LIST_DEAD)) != 0)
1408 panic("enterpgrp: providing ref to terminating session ");
1c79356b 1409 pgrp->pg_session->s_count++;
2d21ac55 1410 proc_list_unlock();
1c79356b
A
1411 }
1412 pgrp->pg_id = pgid;
6d2010ae 1413#if CONFIG_FINE_LOCK_GROUPS
b0d623f7 1414 lck_mtx_init(&pgrp->pg_mlock, proc_mlock_grp, proc_lck_attr);
6d2010ae
A
1415#else
1416 lck_mtx_init(&pgrp->pg_mlock, proc_lck_grp, proc_lck_attr);
b0d623f7 1417#endif
1c79356b 1418 LIST_INIT(&pgrp->pg_members);
2d21ac55 1419 pgrp->pg_membercnt = 0;
1c79356b 1420 pgrp->pg_jobc = 0;
2d21ac55
A
1421 proc_list_lock();
1422 pgrp->pg_refcount = 1;
1423 pgrp->pg_listflags = 0;
1424 LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
1425 proc_list_unlock();
1426 } else if (pgrp == mypgrp) {
1427 pg_rele(pgrp);
1428 if (mypgrp != NULL)
1429 pg_rele(mypgrp);
1430 if (procsp != SESSION_NULL)
1431 session_rele(procsp);
1c79356b 1432 return (0);
2d21ac55 1433 }
1c79356b 1434
2d21ac55
A
1435 if (procsp != SESSION_NULL)
1436 session_rele(procsp);
1c79356b
A
1437 /*
1438 * Adjust eligibility of affected pgrps to participate in job control.
1439 * Increment eligibility counts before decrementing, otherwise we
1440 * could reach 0 spuriously during the first call.
1441 */
1442 fixjobc(p, pgrp, 1);
2d21ac55 1443 fixjobc(p, mypgrp, 0);
1c79356b 1444
2d21ac55
A
1445 if(mypgrp != PGRP_NULL)
1446 pg_rele(mypgrp);
1447 pgrp_replace(p, pgrp);
1448 pg_rele(pgrp);
1449
1450 return(0);
1c79356b
A
1451}
1452
1453/*
1454 * remove process from process group
1455 */
1456int
2d21ac55 1457leavepgrp(proc_t p)
1c79356b
A
1458{
1459
2d21ac55 1460 pgrp_remove(p);
1c79356b
A
1461 return (0);
1462}
1463
1464/*
1465 * delete a process group
1466 */
2d21ac55
A
1467static void
1468pgdelete_dropref(struct pgrp *pgrp)
1c79356b 1469{
b0d623f7 1470 struct tty *ttyp;
2d21ac55
A
1471 int emptypgrp = 1;
1472 struct session *sessp;
1c79356b 1473
2d21ac55
A
1474
1475 pgrp_lock(pgrp);
1476 if (pgrp->pg_membercnt != 0) {
1477 emptypgrp = 0;
1478 }
1479 pgrp_unlock(pgrp);
1480
1481 proc_list_lock();
1482 pgrp->pg_refcount--;
1483 if ((emptypgrp == 0) || (pgrp->pg_membercnt != 0)) {
1484 proc_list_unlock();
1485 return;
1486 }
1487
1488 pgrp->pg_listflags |= PGRP_FLAG_TERMINATE;
1489
1490 if (pgrp->pg_refcount > 0) {
1491 proc_list_unlock();
1492 return;
91447636 1493 }
2d21ac55
A
1494
1495 pgrp->pg_listflags |= PGRP_FLAG_DEAD;
1c79356b 1496 LIST_REMOVE(pgrp, pg_hash);
2d21ac55
A
1497
1498 proc_list_unlock();
1499
b0d623f7
A
1500 ttyp = SESSION_TP(pgrp->pg_session);
1501 if (ttyp != TTY_NULL) {
1502 if (ttyp->t_pgrp == pgrp) {
1503 tty_lock(ttyp);
1504 /* Re-check after acquiring the lock */
1505 if (ttyp->t_pgrp == pgrp) {
1506 ttyp->t_pgrp = NULL;
1507 pgrp->pg_session->s_ttypgrpid = NO_PID;
1508 }
1509 tty_unlock(ttyp);
1510 }
91447636 1511 }
2d21ac55
A
1512
1513 proc_list_lock();
1514
1515 sessp = pgrp->pg_session;
1516 if ((sessp->s_listflags & (S_LIST_TERM | S_LIST_DEAD)) != 0)
1517 panic("pg_deleteref: manipulating refs of already terminating session");
1518 if (--sessp->s_count == 0) {
1519 if ((sessp->s_listflags & (S_LIST_TERM | S_LIST_DEAD)) != 0)
1520 panic("pg_deleteref: terminating already terminated session");
1521 sessp->s_listflags |= S_LIST_TERM;
b0d623f7 1522 ttyp = SESSION_TP(sessp);
2d21ac55
A
1523 LIST_REMOVE(sessp, s_hash);
1524 proc_list_unlock();
b0d623f7
A
1525 if (ttyp != TTY_NULL) {
1526 tty_lock(ttyp);
1527 if (ttyp->t_session == sessp)
1528 ttyp->t_session = NULL;
1529 tty_unlock(ttyp);
1530 }
2d21ac55
A
1531 proc_list_lock();
1532 sessp->s_listflags |= S_LIST_DEAD;
1533 if (sessp->s_count != 0)
1534 panic("pg_deleteref: freeing session in use");
1535 proc_list_unlock();
6d2010ae 1536#if CONFIG_FINE_LOCK_GROUPS
b0d623f7 1537 lck_mtx_destroy(&sessp->s_mlock, proc_mlock_grp);
6d2010ae
A
1538#else
1539 lck_mtx_destroy(&sessp->s_mlock, proc_lck_grp);
b0d623f7 1540#endif
2d21ac55
A
1541 FREE_ZONE(sessp, sizeof(struct session), M_SESSION);
1542 } else
1543 proc_list_unlock();
6d2010ae 1544#if CONFIG_FINE_LOCK_GROUPS
b0d623f7 1545 lck_mtx_destroy(&pgrp->pg_mlock, proc_mlock_grp);
6d2010ae
A
1546#else
1547 lck_mtx_destroy(&pgrp->pg_mlock, proc_lck_grp);
b0d623f7 1548#endif
2d21ac55 1549 FREE_ZONE(pgrp, sizeof(*pgrp), M_PGRP);
1c79356b
A
1550}
1551
1c79356b 1552
1c79356b
A
1553/*
1554 * Adjust pgrp jobc counters when specified process changes process group.
1555 * We count the number of processes in each process group that "qualify"
1556 * the group for terminal job control (those with a parent in a different
1557 * process group of the same session). If that count reaches zero, the
1558 * process group becomes orphaned. Check both the specified process'
1559 * process group and that of its children.
1560 * entering == 0 => p is leaving specified group.
1561 * entering == 1 => p is entering specified group.
1562 */
2d21ac55
A
1563int
1564fixjob_callback(proc_t p, void * arg)
1c79356b 1565{
2d21ac55
A
1566 struct fixjob_iterargs *fp;
1567 struct pgrp * pg, *hispg;
1568 struct session * mysession, *hissess;
1569 int entering;
1570
1571 fp = (struct fixjob_iterargs *)arg;
1572 pg = fp->pg;
1573 mysession = fp->mysession;
1574 entering = fp->entering;
1575
1576 hispg = proc_pgrp(p);
1577 hissess = proc_session(p);
1578
1579 if ((hispg != pg) &&
1580 (hissess == mysession)) {
1581 pgrp_lock(hispg);
1582 if (entering) {
1583 hispg->pg_jobc++;
1584 pgrp_unlock(hispg);
1585 } else if (--hispg->pg_jobc == 0) {
1586 pgrp_unlock(hispg);
1587 orphanpg(hispg);
1588 } else
1589 pgrp_unlock(hispg);
1590 }
1591 if (hissess != SESSION_NULL)
1592 session_rele(hissess);
1593 if (hispg != PGRP_NULL)
1594 pg_rele(hispg);
1c79356b 1595
2d21ac55
A
1596 return(PROC_RETURNED);
1597}
1598
1599void
1600fixjobc(proc_t p, struct pgrp *pgrp, int entering)
1601{
1602 struct pgrp *hispgrp = PGRP_NULL;
1603 struct session *hissess = SESSION_NULL;
1604 struct session *mysession = pgrp->pg_session;
1605 proc_t parent;
1606 struct fixjob_iterargs fjarg;
39236c6e
A
1607 boolean_t proc_parent_self;
1608
1609 /*
1610 * Check if p's parent is current proc, if yes then no need to take
1611 * a ref; calling proc_parent with current proc as parent may
1612 * deadlock if current proc is exiting.
1613 */
1614 proc_parent_self = proc_parent_is_currentproc(p);
1615 if (proc_parent_self)
1616 parent = current_proc();
1617 else
1618 parent = proc_parent(p);
2d21ac55 1619
2d21ac55
A
1620 if (parent != PROC_NULL) {
1621 hispgrp = proc_pgrp(parent);
1622 hissess = proc_session(parent);
39236c6e
A
1623 if (!proc_parent_self)
1624 proc_rele(parent);
2d21ac55
A
1625 }
1626
1627
1628 /*
1629 * Check p's parent to see whether p qualifies its own process
1c79356b
A
1630 * group; if so, adjust count for p's process group.
1631 */
2d21ac55
A
1632 if ((hispgrp != pgrp) &&
1633 (hissess == mysession)) {
1634 pgrp_lock(pgrp);
1635 if (entering) {
1c79356b 1636 pgrp->pg_jobc++;
2d21ac55
A
1637 pgrp_unlock(pgrp);
1638 }else if (--pgrp->pg_jobc == 0) {
1639 pgrp_unlock(pgrp);
1c79356b 1640 orphanpg(pgrp);
2d21ac55
A
1641 } else
1642 pgrp_unlock(pgrp);
e5568f75 1643 }
1c79356b 1644
2d21ac55
A
1645 if (hissess != SESSION_NULL)
1646 session_rele(hissess);
1647 if (hispgrp != PGRP_NULL)
1648 pg_rele(hispgrp);
1649
1c79356b
A
1650 /*
1651 * Check this process' children to see whether they qualify
1652 * their process groups; if so, adjust counts for children's
1653 * process groups.
1654 */
2d21ac55
A
1655 fjarg.pg = pgrp;
1656 fjarg.mysession = mysession;
1657 fjarg.entering = entering;
1658 proc_childrenwalk(p, fixjob_callback, &fjarg);
e5568f75 1659}
1c79356b 1660
39037602
A
1661/*
1662 * A process group has become orphaned; if there are any stopped processes in
1663 * the group, hang-up all process in that group.
1c79356b
A
1664 */
1665static void
39037602 1666orphanpg(struct pgrp *pgrp)
1c79356b 1667{
39037602 1668 pid_t *pid_list;
2d21ac55 1669 proc_t p;
39037602
A
1670 vm_size_t pid_list_size = 0;
1671 vm_size_t pid_list_size_needed = 0;
1672 int pid_count = 0;
1673 int pid_count_available = 0;
2d21ac55 1674
39037602
A
1675 assert(pgrp != NULL);
1676
1677 /* allocate outside of the pgrp_lock */
1678 for (;;) {
1679 pgrp_lock(pgrp);
1680
1681 boolean_t should_iterate = FALSE;
1682 pid_count_available = 0;
1683
1684 PGMEMBERS_FOREACH(pgrp, p) {
1685 pid_count_available++;
1686
1687 if (p->p_stat == SSTOP) {
1688 should_iterate = TRUE;
1689 }
1690 }
1691
1692 if (pid_count_available == 0 || !should_iterate) {
1693 pgrp_unlock(pgrp);
1694 return;
1695 }
1696
1697 pid_list_size_needed = pid_count_available * sizeof(pid_t);
1698 if (pid_list_size >= pid_list_size_needed) {
1699 break;
1700 }
1701 pgrp_unlock(pgrp);
1702
1703 if (pid_list_size != 0) {
1704 kfree(pid_list, pid_list_size);
1705 }
1706 pid_list = kalloc(pid_list_size_needed);
1707 if (!pid_list) {
1708 return;
1c79356b 1709 }
39037602 1710 pid_list_size = pid_list_size_needed;
1c79356b 1711 }
2d21ac55 1712
39037602
A
1713 /* no orphaned processes */
1714 if (pid_list_size == 0) {
1715 pgrp_unlock(pgrp);
1716 return;
1717 }
1718
1719 PGMEMBERS_FOREACH(pgrp, p) {
1720 pid_list[pid_count++] = proc_pid(p);
1721 if (pid_count >= pid_count_available) {
1722 break;
1c79356b
A
1723 }
1724 }
2d21ac55 1725 pgrp_unlock(pgrp);
2d21ac55 1726
39037602
A
1727 if (pid_count == 0) {
1728 goto out;
1729 }
2d21ac55 1730
39037602
A
1731 for (int i = 0; i < pid_count; i++) {
1732 /* do not handle kernproc */
1733 if (pid_list[i] == 0) {
2d21ac55 1734 continue;
39037602 1735 }
2d21ac55 1736 p = proc_find(pid_list[i]);
39037602
A
1737 if (!p) {
1738 continue;
2d21ac55 1739 }
39037602
A
1740
1741 proc_transwait(p, 0);
1742 pt_setrunnable(p);
1743 psignal(p, SIGHUP);
1744 psignal(p, SIGCONT);
1745 proc_rele(p);
2d21ac55 1746 }
39037602 1747
2d21ac55 1748out:
39037602 1749 kfree(pid_list, pid_list_size);
2d21ac55 1750 return;
1c79356b 1751}
2d21ac55 1752
55e303ae 1753int
3e170ce0 1754proc_is_classic(proc_t p __unused)
55e303ae 1755{
3e170ce0 1756 return (0);
55e303ae
A
1757}
1758
e5568f75 1759/* XXX Why does this function exist? Need to kill it off... */
2d21ac55 1760proc_t
e5568f75 1761current_proc_EXTERNAL(void)
1c79356b
A
1762{
1763 return (current_proc());
1764}
e5568f75 1765
39236c6e
A
1766int
1767proc_is_forcing_hfs_case_sensitivity(proc_t p)
1768{
1769 return (p->p_vfs_iopolicy & P_VFS_IOPOLICY_FORCE_HFS_CASE_SENSITIVITY) ? 1 : 0;
1770}
1771
39037602 1772#if CONFIG_COREDUMP
e5568f75
A
1773/*
1774 * proc_core_name(name, uid, pid)
1775 * Expand the name described in corefilename, using name, uid, and pid.
1776 * corefilename is a printf-like string, with three format specifiers:
1777 * %N name of process ("name")
1778 * %P process id (pid)
1779 * %U user id (uid)
1780 * For example, "%N.core" is the default; they can be disabled completely
1781 * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
1782 * This is controlled by the sysctl variable kern.corefile (see above).
1783 */
2d21ac55
A
1784__private_extern__ int
1785proc_core_name(const char *name, uid_t uid, pid_t pid, char *cf_name,
1786 size_t cf_name_len)
e5568f75
A
1787{
1788 const char *format, *appendstr;
e5568f75
A
1789 char id_buf[11]; /* Buffer for pid/uid -- max 4B */
1790 size_t i, l, n;
1791
2d21ac55
A
1792 if (cf_name == NULL)
1793 goto toolong;
1794
e5568f75 1795 format = corefilename;
2d21ac55 1796 for (i = 0, n = 0; n < cf_name_len && format[i]; i++) {
e5568f75
A
1797 switch (format[i]) {
1798 case '%': /* Format character */
1799 i++;
1800 switch (format[i]) {
1801 case '%':
1802 appendstr = "%";
1803 break;
1804 case 'N': /* process name */
1805 appendstr = name;
1806 break;
1807 case 'P': /* process id */
2d21ac55 1808 snprintf(id_buf, sizeof(id_buf), "%u", pid);
e5568f75
A
1809 appendstr = id_buf;
1810 break;
1811 case 'U': /* user id */
2d21ac55 1812 snprintf(id_buf, sizeof(id_buf), "%u", uid);
e5568f75
A
1813 appendstr = id_buf;
1814 break;
39037602
A
1815 case '\0': /* format string ended in % symbol */
1816 goto endofstring;
e5568f75
A
1817 default:
1818 appendstr = "";
1819 log(LOG_ERR,
1820 "Unknown format character %c in `%s'\n",
1821 format[i], format);
1822 }
1823 l = strlen(appendstr);
2d21ac55 1824 if ((n + l) >= cf_name_len)
e5568f75 1825 goto toolong;
2d21ac55 1826 bcopy(appendstr, cf_name + n, l);
e5568f75
A
1827 n += l;
1828 break;
1829 default:
2d21ac55 1830 cf_name[n++] = format[i];
e5568f75
A
1831 }
1832 }
1833 if (format[i] != '\0')
1834 goto toolong;
2d21ac55 1835 return (0);
e5568f75 1836toolong:
b0d623f7
A
1837 log(LOG_ERR, "pid %ld (%s), uid (%u): corename is too long\n",
1838 (long)pid, name, (uint32_t)uid);
2d21ac55 1839 return (1);
39037602
A
1840endofstring:
1841 log(LOG_ERR, "pid %ld (%s), uid (%u): unexpected end of string after %% token\n",
1842 (long)pid, name, (uint32_t)uid);
1843 return (1);
2d21ac55 1844}
39037602 1845#endif /* CONFIG_COREDUMP */
2d21ac55 1846
2d21ac55
A
1847/* Code Signing related routines */
1848
1849int
b0d623f7 1850csops(__unused proc_t p, struct csops_args *uap, __unused int32_t *retval)
2d21ac55 1851{
316670eb
A
1852 return(csops_internal(uap->pid, uap->ops, uap->useraddr,
1853 uap->usersize, USER_ADDR_NULL));
1854}
1855
1856int
1857csops_audittoken(__unused proc_t p, struct csops_audittoken_args *uap, __unused int32_t *retval)
1858{
1859 if (uap->uaudittoken == USER_ADDR_NULL)
1860 return(EINVAL);
316670eb
A
1861 return(csops_internal(uap->pid, uap->ops, uap->useraddr,
1862 uap->usersize, uap->uaudittoken));
1863}
1864
39236c6e
A
1865static int
1866csops_copy_token(void *start, size_t length, user_size_t usize, user_addr_t uaddr)
1867{
1868 char fakeheader[8] = { 0 };
1869 int error;
1870
1871 if (usize < sizeof(fakeheader))
1872 return ERANGE;
1873
1874 /* if no blob, fill in zero header */
1875 if (NULL == start) {
1876 start = fakeheader;
1877 length = sizeof(fakeheader);
1878 } else if (usize < length) {
1879 /* ... if input too short, copy out length of entitlement */
1880 uint32_t length32 = htonl((uint32_t)length);
1881 memcpy(&fakeheader[4], &length32, sizeof(length32));
1882
1883 error = copyout(fakeheader, uaddr, sizeof(fakeheader));
1884 if (error == 0)
1885 return ERANGE; /* input buffer to short, ERANGE signals that */
1886 return error;
1887 }
1888 return copyout(start, uaddr, length);
1889}
1890
316670eb
A
1891static int
1892csops_internal(pid_t pid, int ops, user_addr_t uaddr, user_size_t usersize, user_addr_t uaudittoken)
1893{
1894 size_t usize = (size_t)CAST_DOWN(size_t, usersize);
2d21ac55 1895 proc_t pt;
39236c6e 1896 int forself;
2d21ac55
A
1897 int error;
1898 vnode_t tvp;
1899 off_t toff;
2d21ac55 1900 unsigned char cdhash[SHA1_RESULTLEN];
316670eb
A
1901 audit_token_t token;
1902 unsigned int upid=0, uidversion = 0;
2d21ac55
A
1903
1904 forself = error = 0;
1905
1906 if (pid == 0)
1907 pid = proc_selfpid();
1908 if (pid == proc_selfpid())
1909 forself = 1;
1910
1911
39236c6e 1912 switch (ops) {
316670eb
A
1913 case CS_OPS_STATUS:
1914 case CS_OPS_CDHASH:
1915 case CS_OPS_PIDOFFSET:
1916 case CS_OPS_ENTITLEMENTS_BLOB:
fe8ab488 1917 case CS_OPS_IDENTITY:
39236c6e 1918 case CS_OPS_BLOB:
7e41aa88 1919 break; /* not restricted to root */
316670eb
A
1920 default:
1921 if (forself == 0 && kauth_cred_issuser(kauth_cred_get()) != TRUE)
1922 return(EPERM);
1923 break;
2d21ac55
A
1924 }
1925
1926 pt = proc_find(pid);
1927 if (pt == PROC_NULL)
1928 return(ESRCH);
1929
316670eb
A
1930 upid = pt->p_pid;
1931 uidversion = pt->p_idversion;
1932 if (uaudittoken != USER_ADDR_NULL) {
1933
1934 error = copyin(uaudittoken, &token, sizeof(audit_token_t));
1935 if (error != 0)
1936 goto out;
1937 /* verify the audit token pid/idversion matches with proc */
1938 if ((token.val[5] != upid) || (token.val[7] != uidversion)) {
1939 error = ESRCH;
1940 goto out;
1941 }
1942 }
2d21ac55 1943
7e41aa88
A
1944#if CONFIG_MACF
1945 switch (ops) {
1946 case CS_OPS_MARKINVALID:
1947 case CS_OPS_MARKHARD:
1948 case CS_OPS_MARKKILL:
1949 case CS_OPS_MARKRESTRICT:
1950 case CS_OPS_SET_STATUS:
39037602 1951 case CS_OPS_CLEARINSTALLER:
7e41aa88
A
1952 if ((error = mac_proc_check_set_cs_info(current_proc(), pt, ops)))
1953 goto out;
1954 break;
1955 default:
1956 if ((error = mac_proc_check_get_cs_info(current_proc(), pt, ops)))
1957 goto out;
1958 }
1959#endif
1960
2d21ac55
A
1961 switch (ops) {
1962
39236c6e
A
1963 case CS_OPS_STATUS: {
1964 uint32_t retflags;
1965
1966 proc_lock(pt);
2d21ac55 1967 retflags = pt->p_csflags;
39236c6e
A
1968 if (cs_enforcement(pt))
1969 retflags |= CS_ENFORCEMENT;
3e170ce0
A
1970 if (csproc_get_platform_binary(pt))
1971 retflags |= CS_PLATFORM_BINARY;
39037602
A
1972 if (csproc_get_platform_path(pt))
1973 retflags |= CS_PLATFORM_PATH;
39236c6e
A
1974 proc_unlock(pt);
1975
2d21ac55
A
1976 if (uaddr != USER_ADDR_NULL)
1977 error = copyout(&retflags, uaddr, sizeof(uint32_t));
1978 break;
39236c6e 1979 }
2d21ac55
A
1980 case CS_OPS_MARKINVALID:
1981 proc_lock(pt);
1982 if ((pt->p_csflags & CS_VALID) == CS_VALID) { /* is currently valid */
1983 pt->p_csflags &= ~CS_VALID; /* set invalid */
1984 if ((pt->p_csflags & CS_KILL) == CS_KILL) {
c331a0be 1985 pt->p_csflags |= CS_KILLED;
2d21ac55 1986 proc_unlock(pt);
c331a0be
A
1987 if (cs_debug) {
1988 printf("CODE SIGNING: marked invalid by pid %d: "
1989 "p=%d[%s] honoring CS_KILL, final status 0x%x\n",
1990 proc_selfpid(), pt->p_pid, pt->p_comm, pt->p_csflags);
1991 }
2d21ac55
A
1992 psignal(pt, SIGKILL);
1993 } else
1994 proc_unlock(pt);
1995 } else
1996 proc_unlock(pt);
1997
1998 break;
1999
2000 case CS_OPS_MARKHARD:
2001 proc_lock(pt);
2002 pt->p_csflags |= CS_HARD;
2003 if ((pt->p_csflags & CS_VALID) == 0) {
2004 /* @@@ allow? reject? kill? @@@ */
2005 proc_unlock(pt);
2006 error = EINVAL;
2007 goto out;
2008 } else
2009 proc_unlock(pt);
2010 break;
2011
2012 case CS_OPS_MARKKILL:
2013 proc_lock(pt);
2014 pt->p_csflags |= CS_KILL;
2015 if ((pt->p_csflags & CS_VALID) == 0) {
2016 proc_unlock(pt);
2017 psignal(pt, SIGKILL);
2018 } else
2019 proc_unlock(pt);
2020 break;
2021
b0d623f7
A
2022 case CS_OPS_PIDOFFSET:
2023 toff = pt->p_textoff;
2024 proc_rele(pt);
2025 error = copyout(&toff, uaddr, sizeof(toff));
2d21ac55
A
2026 return(error);
2027
2028 case CS_OPS_CDHASH:
2d21ac55
A
2029
2030 /* pt already holds a reference on its p_textvp */
2031 tvp = pt->p_textvp;
2032 toff = pt->p_textoff;
2033
b0d623f7
A
2034 if (tvp == NULLVP || usize != SHA1_RESULTLEN) {
2035 proc_rele(pt);
2036 return EINVAL;
2037 }
2038
2d21ac55
A
2039 error = vn_getcdhash(tvp, toff, cdhash);
2040 proc_rele(pt);
2041
2042 if (error == 0) {
2043 error = copyout(cdhash, uaddr, sizeof (cdhash));
2044 }
2045
2046 return error;
6d2010ae
A
2047
2048 case CS_OPS_ENTITLEMENTS_BLOB: {
6d2010ae
A
2049 void *start;
2050 size_t length;
2051
39236c6e
A
2052 proc_lock(pt);
2053
490019cf 2054 if ((pt->p_csflags & (CS_VALID | CS_DEBUGGED)) == 0) {
39236c6e 2055 proc_unlock(pt);
316670eb 2056 error = EINVAL;
6d2010ae 2057 break;
316670eb 2058 }
39236c6e
A
2059
2060 error = cs_entitlements_blob_get(pt, &start, &length);
2061 proc_unlock(pt);
2062 if (error)
2063 break;
2064
2065 error = csops_copy_token(start, length, usize, uaddr);
2066 break;
2067 }
2068 case CS_OPS_MARKRESTRICT:
2069 proc_lock(pt);
2070 pt->p_csflags |= CS_RESTRICT;
2071 proc_unlock(pt);
2072 break;
2073
2074 case CS_OPS_SET_STATUS: {
2075 uint32_t flags;
2076
2077 if (usize < sizeof(flags)) {
6d2010ae
A
2078 error = ERANGE;
2079 break;
2080 }
39236c6e
A
2081
2082 error = copyin(uaddr, &flags, sizeof(flags));
2083 if (error)
316670eb 2084 break;
39236c6e
A
2085
2086 /* only allow setting a subset of all code sign flags */
2087 flags &=
2088 CS_HARD | CS_EXEC_SET_HARD |
2089 CS_KILL | CS_EXEC_SET_KILL |
2090 CS_RESTRICT |
fe8ab488 2091 CS_REQUIRE_LV |
39037602 2092 CS_ENFORCEMENT | CS_EXEC_SET_ENFORCEMENT;
39236c6e
A
2093
2094 proc_lock(pt);
2095 if (pt->p_csflags & CS_VALID)
2096 pt->p_csflags |= flags;
2097 else
2098 error = EINVAL;
2099 proc_unlock(pt);
2100
2101 break;
2102 }
2103 case CS_OPS_BLOB: {
2104 void *start;
2105 size_t length;
2106
2107 proc_lock(pt);
490019cf 2108 if ((pt->p_csflags & (CS_VALID | CS_DEBUGGED)) == 0) {
39236c6e
A
2109 proc_unlock(pt);
2110 error = EINVAL;
316670eb 2111 break;
6d2010ae 2112 }
39236c6e
A
2113
2114 error = cs_blob_get(pt, &start, &length);
2115 proc_unlock(pt);
2116 if (error)
2117 break;
2118
2119 error = csops_copy_token(start, length, usize, uaddr);
6d2010ae
A
2120 break;
2121 }
39236c6e
A
2122 case CS_OPS_IDENTITY: {
2123 const char *identity;
2124 uint8_t fakeheader[8];
2125 uint32_t idlen;
2126 size_t length;
2127
2128 /*
2129 * Make identity have a blob header to make it
2130 * easier on userland to guess the identity
2131 * length.
2132 */
2133 if (usize < sizeof(fakeheader)) {
2134 error = ERANGE;
2135 break;
2136 }
2137 memset(fakeheader, 0, sizeof(fakeheader));
6d2010ae 2138
6d2010ae 2139 proc_lock(pt);
490019cf 2140 if ((pt->p_csflags & (CS_VALID | CS_DEBUGGED)) == 0) {
39236c6e
A
2141 proc_unlock(pt);
2142 error = EINVAL;
2143 break;
2144 }
2145
2146 identity = cs_identity_get(pt);
6d2010ae 2147 proc_unlock(pt);
39236c6e
A
2148 if (identity == NULL) {
2149 error = ENOENT;
2150 break;
2151 }
2152
2153 length = strlen(identity) + 1; /* include NUL */
2154 idlen = htonl(length + sizeof(fakeheader));
2155 memcpy(&fakeheader[4], &idlen, sizeof(idlen));
2156
2157 error = copyout(fakeheader, uaddr, sizeof(fakeheader));
2158 if (error)
2159 break;
2160
2161 if (usize < sizeof(fakeheader) + length)
2162 error = ERANGE;
2163 else if (usize > sizeof(fakeheader))
2164 error = copyout(identity, uaddr + sizeof(fakeheader), length);
2165
2166 break;
2167 }
2168
39037602
A
2169 case CS_OPS_CLEARINSTALLER:
2170 proc_lock(pt);
2171 pt->p_csflags &= ~(CS_INSTALLER | CS_EXEC_SET_INSTALLER);
2172 proc_unlock(pt);
2173 break;
2174
2d21ac55
A
2175 default:
2176 error = EINVAL;
2177 break;
2178 }
2179out:
2180 proc_rele(pt);
2181 return(error);
e5568f75 2182}
2d21ac55 2183
2d21ac55 2184int
39037602
A
2185proc_iterate(
2186 unsigned int flags,
2187 proc_iterate_fn_t callout,
2188 void *arg,
2189 proc_iterate_fn_t filterfn,
2190 void *filterarg)
2191{
2192 pid_t *pid_list;
2193 vm_size_t pid_list_size = 0;
2194 vm_size_t pid_list_size_needed = 0;
2195 int pid_count = 0;
2196 int pid_count_available = 0;
2197
2198 assert(callout != NULL);
2199
2200 /* allocate outside of the proc_list_lock */
2201 for (;;) {
2202 proc_list_lock();
2d21ac55 2203
39037602
A
2204 pid_count_available = nprocs;
2205 assert(pid_count_available > 0);
2d21ac55 2206
39037602
A
2207 pid_list_size_needed = pid_count_available * sizeof(pid_t);
2208 if (pid_list_size >= pid_list_size_needed) {
2209 break;
2210 }
2211 proc_list_unlock();
2d21ac55 2212
39037602
A
2213 if (pid_list_size != 0) {
2214 kfree(pid_list, pid_list_size);
2215 }
2216 pid_list = kalloc(pid_list_size_needed);
2217 if (!pid_list) {
2218 return 1;
2219 }
2220 pid_list_size = pid_list_size_needed;
2221 }
2d21ac55 2222
39037602 2223 /* filter pids into pid_list */
2d21ac55 2224
2d21ac55 2225 if (flags & PROC_ALLPROCLIST) {
39037602
A
2226 proc_t p;
2227 ALLPROC_FOREACH(p) {
2228 /* ignore processes that are being forked */
2229 if (p->p_stat == SIDL) {
2230 continue;
2231 }
2232 if ((filterfn != NULL) && (filterfn(p, filterarg) == 0)) {
2d21ac55 2233 continue;
39037602
A
2234 }
2235
2236 pid_list[pid_count++] = proc_pid(p);
2237 if (pid_count >= pid_count_available) {
2238 break;
2d21ac55
A
2239 }
2240 }
2241 }
39037602
A
2242
2243 if ((pid_count < pid_count_available) &&
2244 (flags & PROC_ZOMBPROCLIST))
2245 {
2246 proc_t p;
2247 ZOMBPROC_FOREACH(p) {
2248 if ((filterfn != NULL) && (filterfn(p, filterarg) == 0)) {
2249 continue;
2250 }
2251
2252 pid_list[pid_count++] = proc_pid(p);
2253 if (pid_count >= pid_count_available) {
2254 break;
2d21ac55
A
2255 }
2256 }
2257 }
2d21ac55
A
2258
2259 proc_list_unlock();
2260
39037602 2261 /* call callout on processes in the pid_list */
2d21ac55 2262
39037602
A
2263 for (int i = 0; i < pid_count; i++) {
2264 proc_t p = proc_find(pid_list[i]);
2d21ac55 2265 if (p) {
39037602 2266 if ((flags & PROC_NOWAITTRANS) == 0) {
2d21ac55 2267 proc_transwait(p, 0);
2d21ac55 2268 }
39037602 2269 int callout_ret = callout(p, arg);
2d21ac55 2270
39037602
A
2271 switch (callout_ret) {
2272 case PROC_RETURNED_DONE:
2273 proc_rele(p);
2274 /* FALLTHROUGH */
2275 case PROC_CLAIMED_DONE:
2276 goto out;
2d21ac55 2277
39037602
A
2278 case PROC_RETURNED:
2279 proc_rele(p);
2280 /* FALLTHROUGH */
2281 case PROC_CLAIMED:
2282 break;
2d21ac55 2283
39037602
A
2284 default:
2285 panic("proc_iterate: callout returned %d for pid %d",
2286 callout_ret, pid_list[i]);
2287 break;
2288 }
2289 } else if (flags & PROC_ZOMBPROCLIST) {
2290 p = proc_find_zombref(pid_list[i]);
2291 if (!p) {
2292 continue;
2293 }
2294 int callout_ret = callout(p, arg);
2d21ac55 2295
39037602
A
2296 switch (callout_ret) {
2297 case PROC_RETURNED_DONE:
2298 proc_drop_zombref(p);
2299 /* FALLTHROUGH */
2300 case PROC_CLAIMED_DONE:
2301 goto out;
2d21ac55 2302
39037602
A
2303 case PROC_RETURNED:
2304 proc_drop_zombref(p);
2305 /* FALLTHROUGH */
2306 case PROC_CLAIMED:
2307 break;
2d21ac55 2308
39037602
A
2309 default:
2310 panic("proc_iterate: callout returned %d for zombie pid %d",
2311 callout_ret, pid_list[i]);
2312 break;
2313 }
2d21ac55
A
2314 }
2315 }
2d21ac55 2316
39037602
A
2317out:
2318 kfree(pid_list, pid_list_size);
2319 return 0;
2d21ac55 2320
2d21ac55 2321}
2d21ac55 2322
39037602
A
2323void
2324proc_rebootscan(
2325 proc_iterate_fn_t callout,
2326 void *arg,
2327 proc_iterate_fn_t filterfn,
2328 void *filterarg)
2d21ac55
A
2329{
2330 proc_t p;
39037602
A
2331
2332 assert(callout != NULL);
2d21ac55 2333
b0d623f7
A
2334 proc_shutdown_exitcount = 0;
2335
39037602 2336restart_foreach:
2d21ac55
A
2337
2338 proc_list_lock();
b0d623f7 2339
39037602
A
2340 ALLPROC_FOREACH(p) {
2341 if ((filterfn != NULL) && filterfn(p, filterarg) == 0) {
2342 continue;
2343 }
2344 p = proc_ref_locked(p);
2345 if (!p) {
2346 continue;
2347 }
2d21ac55 2348
39037602 2349 proc_list_unlock();
2d21ac55 2350
39037602
A
2351 proc_transwait(p, 0);
2352 (void)callout(p, arg);
2353 proc_rele(p);
2d21ac55 2354
39037602 2355 goto restart_foreach;
2d21ac55
A
2356 }
2357
39037602 2358 proc_list_unlock();
2d21ac55
A
2359}
2360
2d21ac55 2361int
39037602
A
2362proc_childrenwalk(
2363 proc_t parent,
2364 proc_iterate_fn_t callout,
2365 void *arg)
2d21ac55 2366{
39037602
A
2367 pid_t *pid_list;
2368 vm_size_t pid_list_size = 0;
2369 vm_size_t pid_list_size_needed = 0;
2370 int pid_count = 0;
2371 int pid_count_available = 0;
2d21ac55 2372
39037602
A
2373 assert(parent != NULL);
2374 assert(callout != NULL);
2d21ac55 2375
39037602
A
2376 for (;;) {
2377 proc_list_lock();
2d21ac55 2378
39037602
A
2379 pid_count_available = parent->p_childrencnt;
2380 if (pid_count_available == 0) {
2381 proc_list_unlock();
2382 return 0;
2383 }
2d21ac55 2384
39037602
A
2385 pid_list_size_needed = pid_count_available * sizeof(pid_t);
2386 if (pid_list_size >= pid_list_size_needed) {
2387 break;
2388 }
2389 proc_list_unlock();
2d21ac55 2390
39037602
A
2391 if (pid_list_size != 0) {
2392 kfree(pid_list, pid_list_size);
2393 }
2394 pid_list = kalloc(pid_list_size_needed);
2395 if (!pid_list) {
2396 return 1;
2397 }
2398 pid_list_size = pid_list_size_needed;
2399 }
2400
2401 proc_t p;
2402 PCHILDREN_FOREACH(parent, p) {
2403 if (p->p_stat == SIDL) {
2d21ac55 2404 continue;
39037602
A
2405 }
2406
2407 pid_list[pid_count++] = proc_pid(p);
2408 if (pid_count >= pid_count_available) {
2d21ac55 2409 break;
39037602 2410 }
2d21ac55 2411 }
2d21ac55 2412
39037602 2413 proc_list_unlock();
2d21ac55 2414
39037602 2415 for (int i = 0; i < pid_count; i++) {
2d21ac55 2416 p = proc_find(pid_list[i]);
39037602
A
2417 if (!p) {
2418 continue;
2d21ac55 2419 }
2d21ac55 2420
39037602 2421 int callout_ret = callout(p, arg);
2d21ac55 2422
39037602
A
2423 switch (callout_ret) {
2424 case PROC_RETURNED_DONE:
2425 proc_rele(p);
2426 /* FALLTHROUGH */
2427 case PROC_CLAIMED_DONE:
2428 goto out;
2429
2430 case PROC_RETURNED:
2431 proc_rele(p);
2432 /* FALLTHROUGH */
2433 case PROC_CLAIMED:
2434 break;
2435 default:
2436 panic("proc_childrenwalk: callout returned %d for pid %d",
2437 callout_ret, pid_list[i]);
2438 break;
2439 }
2440 }
2441
2442out:
2443 kfree(pid_list, pid_list_size);
2444 return 0;
2d21ac55
A
2445}
2446
2d21ac55 2447int
39037602
A
2448pgrp_iterate(
2449 struct pgrp *pgrp,
2450 unsigned int flags,
2451 proc_iterate_fn_t callout,
2452 void * arg,
2453 proc_iterate_fn_t filterfn,
2454 void * filterarg)
2455{
2456 pid_t *pid_list;
2d21ac55 2457 proc_t p;
39037602
A
2458 vm_size_t pid_list_size = 0;
2459 vm_size_t pid_list_size_needed = 0;
2460 int pid_count = 0;
2461 int pid_count_available = 0;
2462
2d21ac55 2463 pid_t pgid;
2d21ac55 2464
39037602
A
2465 assert(pgrp != NULL);
2466 assert(callout != NULL);
2467
2468 for (;;) {
2469 pgrp_lock(pgrp);
2470
2471 pid_count_available = pgrp->pg_membercnt;
2472 if (pid_count_available == 0) {
2473 pgrp_unlock(pgrp);
2474 return 0;
2475 }
2476
2477 pid_list_size_needed = pid_count_available * sizeof(pid_t);
2478 if (pid_list_size >= pid_list_size_needed) {
2479 break;
2480 }
2481 pgrp_unlock(pgrp);
2482
2483 if (pid_list_size != 0) {
2484 kfree(pid_list, pid_list_size);
2485 }
2486 pid_list = kalloc(pid_list_size_needed);
2487 if (!pid_list) {
2488 return 1;
2d21ac55 2489 }
39037602 2490 pid_list_size = pid_list_size_needed;
2d21ac55
A
2491 }
2492
2493 pgid = pgrp->pg_id;
2494
39037602
A
2495 PGMEMBERS_FOREACH(pgrp, p) {
2496 if ((filterfn != NULL) && (filterfn(p, filterarg) == 0)) {
2497 continue;;
2498 }
2499 pid_list[pid_count++] = proc_pid(p);
2500 if (pid_count >= pid_count_available) {
2501 break;
2d21ac55
A
2502 }
2503 }
2d21ac55
A
2504
2505 pgrp_unlock(pgrp);
2d21ac55 2506
39037602
A
2507 if (flags & PGRP_DROPREF) {
2508 pg_rele(pgrp);
2509 }
2d21ac55 2510
39037602
A
2511 for (int i = 0; i< pid_count; i++) {
2512 /* do not handle kernproc */
2513 if (pid_list[i] == 0) {
2d21ac55 2514 continue;
39037602 2515 }
2d21ac55 2516 p = proc_find(pid_list[i]);
39037602
A
2517 if (!p) {
2518 continue;
2d21ac55 2519 }
39037602
A
2520 if (p->p_pgrpid != pgid) {
2521 proc_rele(p);
2522 continue;
2523 }
2524
2525 int callout_ret = callout(p, arg);
2526
2527 switch (callout_ret) {
2528 case PROC_RETURNED:
2529 proc_rele(p);
2530 /* FALLTHROUGH */
2531 case PROC_CLAIMED:
2532 break;
2533
2534 case PROC_RETURNED_DONE:
2535 proc_rele(p);
2536 /* FALLTHROUGH */
2537 case PROC_CLAIMED_DONE:
2538 goto out;
2539
2540 default:
2541 panic("pgrp_iterate: callout returned %d for pid %d",
2542 callout_ret, pid_list[i]);
2d21ac55 2543 }
2d21ac55 2544 }
39037602
A
2545
2546out:
2547 kfree(pid_list, pid_list_size);
2548 return 0;
2d21ac55
A
2549}
2550
2551static void
2552pgrp_add(struct pgrp * pgrp, struct proc * parent, struct proc * child)
2553{
2554 proc_list_lock();
2555 child->p_pgrp = pgrp;
2556 child->p_pgrpid = pgrp->pg_id;
2557 child->p_listflag |= P_LIST_INPGRP;
2558 /*
2559 * When pgrp is being freed , a process can still
2560 * request addition using setpgid from bash when
2561 * login is terminated (login cycler) return ESRCH
2562 * Safe to hold lock due to refcount on pgrp
2563 */
2564 if ((pgrp->pg_listflags & (PGRP_FLAG_TERMINATE | PGRP_FLAG_DEAD)) == PGRP_FLAG_TERMINATE) {
2565 pgrp->pg_listflags &= ~PGRP_FLAG_TERMINATE;
2566 }
2567
2568 if ((pgrp->pg_listflags & PGRP_FLAG_DEAD) == PGRP_FLAG_DEAD)
2569 panic("pgrp_add : pgrp is dead adding process");
2570 proc_list_unlock();
2571
2572 pgrp_lock(pgrp);
2573 pgrp->pg_membercnt++;
2574 if ( parent != PROC_NULL) {
2575 LIST_INSERT_AFTER(parent, child, p_pglist);
2576 }else {
2577 LIST_INSERT_HEAD(&pgrp->pg_members, child, p_pglist);
2578 }
2579 pgrp_unlock(pgrp);
2580
2581 proc_list_lock();
2582 if (((pgrp->pg_listflags & (PGRP_FLAG_TERMINATE | PGRP_FLAG_DEAD)) == PGRP_FLAG_TERMINATE) && (pgrp->pg_membercnt != 0)) {
2583 pgrp->pg_listflags &= ~PGRP_FLAG_TERMINATE;
2584 }
2585 proc_list_unlock();
2586}
2587
2588static void
2589pgrp_remove(struct proc * p)
2590{
2591 struct pgrp * pg;
2592
2593 pg = proc_pgrp(p);
2594
2595 proc_list_lock();
2596#if __PROC_INTERNAL_DEBUG
2597 if ((p->p_listflag & P_LIST_INPGRP) == 0)
2598 panic("removing from pglist but no named ref\n");
2599#endif
2600 p->p_pgrpid = PGRPID_DEAD;
2601 p->p_listflag &= ~P_LIST_INPGRP;
2602 p->p_pgrp = NULL;
2603 proc_list_unlock();
2604
2605 if (pg == PGRP_NULL)
2606 panic("pgrp_remove: pg is NULL");
2607 pgrp_lock(pg);
2608 pg->pg_membercnt--;
2609
2610 if (pg->pg_membercnt < 0)
b0d623f7 2611 panic("pgprp: -ve membercnt pgprp:%p p:%p\n",pg, p);
2d21ac55
A
2612
2613 LIST_REMOVE(p, p_pglist);
2614 if (pg->pg_members.lh_first == 0) {
2615 pgrp_unlock(pg);
2616 pgdelete_dropref(pg);
2617 } else {
2618 pgrp_unlock(pg);
2619 pg_rele(pg);
2620 }
2621}
2622
2623
2624/* cannot use proc_pgrp as it maybe stalled */
2625static void
2626pgrp_replace(struct proc * p, struct pgrp * newpg)
2627{
2628 struct pgrp * oldpg;
2629
2630
2631
2632 proc_list_lock();
2633
2634 while ((p->p_listflag & P_LIST_PGRPTRANS) == P_LIST_PGRPTRANS) {
2635 p->p_listflag |= P_LIST_PGRPTRWAIT;
2636 (void)msleep(&p->p_pgrpid, proc_list_mlock, 0, "proc_pgrp", 0);
2637 }
2638
2639 p->p_listflag |= P_LIST_PGRPTRANS;
2640
2641 oldpg = p->p_pgrp;
2642 if (oldpg == PGRP_NULL)
2643 panic("pgrp_replace: oldpg NULL");
2644 oldpg->pg_refcount++;
2645#if __PROC_INTERNAL_DEBUG
2646 if ((p->p_listflag & P_LIST_INPGRP) == 0)
2647 panic("removing from pglist but no named ref\n");
2648#endif
2649 p->p_pgrpid = PGRPID_DEAD;
2650 p->p_listflag &= ~P_LIST_INPGRP;
2651 p->p_pgrp = NULL;
2652
2653 proc_list_unlock();
2654
2655 pgrp_lock(oldpg);
2656 oldpg->pg_membercnt--;
2657 if (oldpg->pg_membercnt < 0)
b0d623f7 2658 panic("pgprp: -ve membercnt pgprp:%p p:%p\n",oldpg, p);
2d21ac55
A
2659 LIST_REMOVE(p, p_pglist);
2660 if (oldpg->pg_members.lh_first == 0) {
2661 pgrp_unlock(oldpg);
2662 pgdelete_dropref(oldpg);
2663 } else {
2664 pgrp_unlock(oldpg);
2665 pg_rele(oldpg);
2666 }
2667
2668 proc_list_lock();
2669 p->p_pgrp = newpg;
2670 p->p_pgrpid = newpg->pg_id;
2671 p->p_listflag |= P_LIST_INPGRP;
2672 /*
2673 * When pgrp is being freed , a process can still
2674 * request addition using setpgid from bash when
2675 * login is terminated (login cycler) return ESRCH
2676 * Safe to hold lock due to refcount on pgrp
2677 */
2678 if ((newpg->pg_listflags & (PGRP_FLAG_TERMINATE | PGRP_FLAG_DEAD)) == PGRP_FLAG_TERMINATE) {
2679 newpg->pg_listflags &= ~PGRP_FLAG_TERMINATE;
2680 }
2681
2682 if ((newpg->pg_listflags & PGRP_FLAG_DEAD) == PGRP_FLAG_DEAD)
2683 panic("pgrp_add : pgrp is dead adding process");
2684 proc_list_unlock();
2685
2686 pgrp_lock(newpg);
2687 newpg->pg_membercnt++;
2688 LIST_INSERT_HEAD(&newpg->pg_members, p, p_pglist);
2689 pgrp_unlock(newpg);
2690
2691 proc_list_lock();
2692 if (((newpg->pg_listflags & (PGRP_FLAG_TERMINATE | PGRP_FLAG_DEAD)) == PGRP_FLAG_TERMINATE) && (newpg->pg_membercnt != 0)) {
2693 newpg->pg_listflags &= ~PGRP_FLAG_TERMINATE;
2694 }
2695
2696 p->p_listflag &= ~P_LIST_PGRPTRANS;
2697 if ((p->p_listflag & P_LIST_PGRPTRWAIT) == P_LIST_PGRPTRWAIT) {
2698 p->p_listflag &= ~P_LIST_PGRPTRWAIT;
2699 wakeup(&p->p_pgrpid);
2700
2701 }
2702 proc_list_unlock();
2703}
2704
2705void
2706pgrp_lock(struct pgrp * pgrp)
2707{
2708 lck_mtx_lock(&pgrp->pg_mlock);
2709}
2710
2711void
2712pgrp_unlock(struct pgrp * pgrp)
2713{
2714 lck_mtx_unlock(&pgrp->pg_mlock);
2715}
2716
2717void
2718session_lock(struct session * sess)
2719{
2720 lck_mtx_lock(&sess->s_mlock);
2721}
2722
2723
2724void
2725session_unlock(struct session * sess)
2726{
2727 lck_mtx_unlock(&sess->s_mlock);
2728}
2729
2730struct pgrp *
2731proc_pgrp(proc_t p)
2732{
2733 struct pgrp * pgrp;
2734
2735 if (p == PROC_NULL)
2736 return(PGRP_NULL);
2737 proc_list_lock();
2738
2739 while ((p->p_listflag & P_LIST_PGRPTRANS) == P_LIST_PGRPTRANS) {
2740 p->p_listflag |= P_LIST_PGRPTRWAIT;
2741 (void)msleep(&p->p_pgrpid, proc_list_mlock, 0, "proc_pgrp", 0);
2742 }
2743
2744 pgrp = p->p_pgrp;
2745
2746 assert(pgrp != NULL);
2747
b0d623f7 2748 if (pgrp != PGRP_NULL) {
2d21ac55 2749 pgrp->pg_refcount++;
b0d623f7
A
2750 if ((pgrp->pg_listflags & (PGRP_FLAG_TERMINATE | PGRP_FLAG_DEAD)) != 0)
2751 panic("proc_pgrp: ref being povided for dead pgrp");
2752 }
2753
2d21ac55
A
2754 proc_list_unlock();
2755
2756 return(pgrp);
2757}
2758
2759struct pgrp *
2760tty_pgrp(struct tty * tp)
2761{
2762 struct pgrp * pg = PGRP_NULL;
2763
2764 proc_list_lock();
2765 pg = tp->t_pgrp;
2766
2767 if (pg != PGRP_NULL) {
2768 if ((pg->pg_listflags & PGRP_FLAG_DEAD) != 0)
2769 panic("tty_pgrp: ref being povided for dead pgrp");
2770 pg->pg_refcount++;
2771 }
2772 proc_list_unlock();
2773
2774 return(pg);
2775}
2776
2777struct session *
2778proc_session(proc_t p)
2779{
2780 struct session * sess = SESSION_NULL;
2781
2782 if (p == PROC_NULL)
2783 return(SESSION_NULL);
2784
2785 proc_list_lock();
2786
2787 /* wait during transitions */
2788 while ((p->p_listflag & P_LIST_PGRPTRANS) == P_LIST_PGRPTRANS) {
2789 p->p_listflag |= P_LIST_PGRPTRWAIT;
2790 (void)msleep(&p->p_pgrpid, proc_list_mlock, 0, "proc_pgrp", 0);
2791 }
2792
2793 if ((p->p_pgrp != PGRP_NULL) && ((sess = p->p_pgrp->pg_session) != SESSION_NULL)) {
2794 if ((sess->s_listflags & (S_LIST_TERM | S_LIST_DEAD)) != 0)
2795 panic("proc_session:returning sesssion ref on terminating session");
2796 sess->s_count++;
2797 }
2798 proc_list_unlock();
2799 return(sess);
2800}
2801
2802void
2803session_rele(struct session *sess)
2804{
2805 proc_list_lock();
2806 if (--sess->s_count == 0) {
2807 if ((sess->s_listflags & (S_LIST_TERM | S_LIST_DEAD)) != 0)
2808 panic("session_rele: terminating already terminated session");
2809 sess->s_listflags |= S_LIST_TERM;
2810 LIST_REMOVE(sess, s_hash);
2811 sess->s_listflags |= S_LIST_DEAD;
2812 if (sess->s_count != 0)
2813 panic("session_rele: freeing session in use");
2814 proc_list_unlock();
6d2010ae 2815#if CONFIG_FINE_LOCK_GROUPS
b0d623f7 2816 lck_mtx_destroy(&sess->s_mlock, proc_mlock_grp);
6d2010ae
A
2817#else
2818 lck_mtx_destroy(&sess->s_mlock, proc_lck_grp);
b0d623f7 2819#endif
2d21ac55
A
2820 FREE_ZONE(sess, sizeof(struct session), M_SESSION);
2821 } else
2822 proc_list_unlock();
2823}
2824
b0d623f7 2825int
fe8ab488 2826proc_transstart(proc_t p, int locked, int non_blocking)
2d21ac55
A
2827{
2828 if (locked == 0)
2829 proc_lock(p);
2830 while ((p->p_lflag & P_LINTRANSIT) == P_LINTRANSIT) {
fe8ab488 2831 if (((p->p_lflag & P_LTRANSCOMMIT) == P_LTRANSCOMMIT) || non_blocking) {
b0d623f7
A
2832 if (locked == 0)
2833 proc_unlock(p);
2834 return EDEADLK;
2835 }
2d21ac55
A
2836 p->p_lflag |= P_LTRANSWAIT;
2837 msleep(&p->p_lflag, &p->p_mlock, 0, "proc_signstart", NULL);
2838 }
2839 p->p_lflag |= P_LINTRANSIT;
2840 p->p_transholder = current_thread();
2841 if (locked == 0)
2842 proc_unlock(p);
b0d623f7 2843 return 0;
2d21ac55
A
2844}
2845
b0d623f7
A
2846void
2847proc_transcommit(proc_t p, int locked)
2848{
2849 if (locked == 0)
2850 proc_lock(p);
2851
2852 assert ((p->p_lflag & P_LINTRANSIT) == P_LINTRANSIT);
2853 assert (p->p_transholder == current_thread());
2854 p->p_lflag |= P_LTRANSCOMMIT;
2855
2856 if ((p->p_lflag & P_LTRANSWAIT) == P_LTRANSWAIT) {
2857 p->p_lflag &= ~P_LTRANSWAIT;
2858 wakeup(&p->p_lflag);
2859 }
2860 if (locked == 0)
2861 proc_unlock(p);
2862}
2d21ac55
A
2863
2864void
2865proc_transend(proc_t p, int locked)
2866{
2867 if (locked == 0)
2868 proc_lock(p);
b0d623f7
A
2869
2870 p->p_lflag &= ~( P_LINTRANSIT | P_LTRANSCOMMIT);
2871 p->p_transholder = NULL;
2d21ac55
A
2872
2873 if ((p->p_lflag & P_LTRANSWAIT) == P_LTRANSWAIT) {
2874 p->p_lflag &= ~P_LTRANSWAIT;
2875 wakeup(&p->p_lflag);
2876 }
2d21ac55
A
2877 if (locked == 0)
2878 proc_unlock(p);
2879}
2880
b0d623f7 2881int
2d21ac55
A
2882proc_transwait(proc_t p, int locked)
2883{
2884 if (locked == 0)
2885 proc_lock(p);
2886 while ((p->p_lflag & P_LINTRANSIT) == P_LINTRANSIT) {
b0d623f7
A
2887 if ((p->p_lflag & P_LTRANSCOMMIT) == P_LTRANSCOMMIT && current_proc() == p) {
2888 if (locked == 0)
2889 proc_unlock(p);
2890 return EDEADLK;
2891 }
2d21ac55
A
2892 p->p_lflag |= P_LTRANSWAIT;
2893 msleep(&p->p_lflag, &p->p_mlock, 0, "proc_signstart", NULL);
2894 }
2895 if (locked == 0)
2896 proc_unlock(p);
b0d623f7 2897 return 0;
2d21ac55
A
2898}
2899
2900void
2901proc_klist_lock(void)
2902{
2903 lck_mtx_lock(proc_klist_mlock);
2904}
2905
2906void
2907proc_klist_unlock(void)
2908{
2909 lck_mtx_unlock(proc_klist_mlock);
2910}
2911
2912void
2913proc_knote(struct proc * p, long hint)
2914{
2915 proc_klist_lock();
2916 KNOTE(&p->p_klist, hint);
2917 proc_klist_unlock();
2918}
2919
b0d623f7
A
2920void
2921proc_knote_drain(struct proc *p)
2922{
2923 struct knote *kn = NULL;
2924
2925 /*
2926 * Clear the proc's klist to avoid references after the proc is reaped.
2927 */
2928 proc_klist_lock();
2929 while ((kn = SLIST_FIRST(&p->p_klist))) {
2930 kn->kn_ptr.p_proc = PROC_NULL;
2931 KNOTE_DETACH(&p->p_klist, kn);
2932 }
2933 proc_klist_unlock();
2934}
2d21ac55 2935
b0d623f7
A
2936void
2937proc_setregister(proc_t p)
2938{
2939 proc_lock(p);
2940 p->p_lflag |= P_LREGISTER;
2941 proc_unlock(p);
2942}
2943
2944void
2945proc_resetregister(proc_t p)
2946{
2947 proc_lock(p);
2948 p->p_lflag &= ~P_LREGISTER;
2949 proc_unlock(p);
2950}
2951
2952pid_t
2953proc_pgrpid(proc_t p)
2954{
2955 return p->p_pgrpid;
2956}
2957
2958pid_t
2959proc_selfpgrpid()
2960{
2961 return current_proc()->p_pgrpid;
2962}
2963
2964
2965/* return control and action states */
2966int
2967proc_getpcontrol(int pid, int * pcontrolp)
2968{
2969 proc_t p;
2970
2971 p = proc_find(pid);
2972 if (p == PROC_NULL)
2973 return(ESRCH);
2974 if (pcontrolp != NULL)
2975 *pcontrolp = p->p_pcaction;
2976
2977 proc_rele(p);
2978 return(0);
2979}
2980
2981int
fe8ab488 2982proc_dopcontrol(proc_t p)
b0d623f7
A
2983{
2984 int pcontrol;
2985
2986 proc_lock(p);
2987
2988 pcontrol = PROC_CONTROL_STATE(p);
2989
fe8ab488 2990 if (PROC_ACTION_STATE(p) == 0) {
b0d623f7
A
2991 switch(pcontrol) {
2992 case P_PCTHROTTLE:
2993 PROC_SETACTION_STATE(p);
2994 proc_unlock(p);
2995 printf("low swap: throttling pid %d (%s)\n", p->p_pid, p->p_comm);
b0d623f7
A
2996 break;
2997
2998 case P_PCSUSP:
2999 PROC_SETACTION_STATE(p);
3000 proc_unlock(p);
3001 printf("low swap: suspending pid %d (%s)\n", p->p_pid, p->p_comm);
3002 task_suspend(p->task);
b0d623f7
A
3003 break;
3004
3005 case P_PCKILL:
3006 PROC_SETACTION_STATE(p);
3007 proc_unlock(p);
3008 printf("low swap: killing pid %d (%s)\n", p->p_pid, p->p_comm);
3009 psignal(p, SIGKILL);
b0d623f7
A
3010 break;
3011
3012 default:
3013 proc_unlock(p);
3014 }
3015
3016 } else
3017 proc_unlock(p);
3018
3019 return(PROC_RETURNED);
3020}
3021
3022
3023/*
3024 * Resume a throttled or suspended process. This is an internal interface that's only
3025 * used by the user level code that presents the GUI when we run out of swap space and
3026 * hence is restricted to processes with superuser privileges.
3027 */
3028
3029int
3030proc_resetpcontrol(int pid)
3031{
3032 proc_t p;
3033 int pcontrol;
3034 int error;
6d2010ae 3035 proc_t self = current_proc();
b0d623f7 3036
6d2010ae
A
3037 /* if the process has been validated to handle resource control or root is valid one */
3038 if (((self->p_lflag & P_LVMRSRCOWNER) == 0) && (error = suser(kauth_cred_get(), 0)))
b0d623f7 3039 return error;
6d2010ae 3040
b0d623f7
A
3041 p = proc_find(pid);
3042 if (p == PROC_NULL)
3043 return(ESRCH);
3044
3045 proc_lock(p);
3046
3047 pcontrol = PROC_CONTROL_STATE(p);
3048
3049 if(PROC_ACTION_STATE(p) !=0) {
3050 switch(pcontrol) {
3051 case P_PCTHROTTLE:
3052 PROC_RESETACTION_STATE(p);
3053 proc_unlock(p);
3054 printf("low swap: unthrottling pid %d (%s)\n", p->p_pid, p->p_comm);
3055 break;
3056
3057 case P_PCSUSP:
3058 PROC_RESETACTION_STATE(p);
3059 proc_unlock(p);
3060 printf("low swap: resuming pid %d (%s)\n", p->p_pid, p->p_comm);
3061 task_resume(p->task);
3062 break;
3063
3064 case P_PCKILL:
3065 /* Huh? */
3066 PROC_SETACTION_STATE(p);
3067 proc_unlock(p);
3068 printf("low swap: attempt to unkill pid %d (%s) ignored\n", p->p_pid, p->p_comm);
3069 break;
3070
3071 default:
3072 proc_unlock(p);
3073 }
3074
3075 } else
3076 proc_unlock(p);
3077
3078 proc_rele(p);
3079 return(0);
3080}
3081
3082
fe8ab488
A
3083
3084struct no_paging_space
3085{
3086 uint64_t pcs_max_size;
3087 uint64_t pcs_uniqueid;
3088 int pcs_pid;
3089 int pcs_proc_count;
3090 uint64_t pcs_total_size;
3091
3092 uint64_t npcs_max_size;
3093 uint64_t npcs_uniqueid;
3094 int npcs_pid;
3095 int npcs_proc_count;
3096 uint64_t npcs_total_size;
3097
3098 int apcs_proc_count;
3099 uint64_t apcs_total_size;
3100};
3101
b0d623f7
A
3102
3103static int
fe8ab488 3104proc_pcontrol_filter(proc_t p, void *arg)
b0d623f7 3105{
fe8ab488
A
3106 struct no_paging_space *nps;
3107 uint64_t compressed;
3108
3109 nps = (struct no_paging_space *)arg;
3110
3111 compressed = get_task_compressed(p->task);
3112
3113 if (PROC_CONTROL_STATE(p)) {
3114 if (PROC_ACTION_STATE(p) == 0) {
3115 if (compressed > nps->pcs_max_size) {
3116 nps->pcs_pid = p->p_pid;
3117 nps->pcs_uniqueid = p->p_uniqueid;
3118 nps->pcs_max_size = compressed;
3119 }
3120 nps->pcs_total_size += compressed;
3121 nps->pcs_proc_count++;
3122 } else {
3123 nps->apcs_total_size += compressed;
3124 nps->apcs_proc_count++;
3125 }
3126 } else {
3127 if (compressed > nps->npcs_max_size) {
3128 nps->npcs_pid = p->p_pid;
3129 nps->npcs_uniqueid = p->p_uniqueid;
3130 nps->npcs_max_size = compressed;
3131 }
3132 nps->npcs_total_size += compressed;
3133 nps->npcs_proc_count++;
3134
3135 }
3136 return (0);
b0d623f7
A
3137}
3138
3139
fe8ab488
A
3140static int
3141proc_pcontrol_null(__unused proc_t p, __unused void *arg)
3142{
3143 return(PROC_RETURNED);
3144}
3145
b0d623f7
A
3146
3147/*
fe8ab488
A
3148 * Deal with the low on compressor pool space condition... this function
3149 * gets called when we are approaching the limits of the compressor pool or
3150 * we are unable to create a new swap file.
3151 * Since this eventually creates a memory deadlock situtation, we need to take action to free up
3152 * memory resources (both compressed and uncompressed) in order to prevent the system from hanging completely.
3153 * There are 2 categories of processes to deal with. Those that have an action
3154 * associated with them by the task itself and those that do not. Actionable
3155 * tasks can have one of three categories specified: ones that
3156 * can be killed immediately, ones that should be suspended, and ones that should
3157 * be throttled. Processes that do not have an action associated with them are normally
3158 * ignored unless they are utilizing such a large percentage of the compressor pool (currently 50%)
3159 * that only by killing them can we hope to put the system back into a usable state.
b0d623f7
A
3160 */
3161
fe8ab488
A
3162#define NO_PAGING_SPACE_DEBUG 0
3163
3164extern uint64_t vm_compressor_pages_compressed(void);
b0d623f7
A
3165
3166struct timeval last_no_space_action = {0, 0};
3167
813fb2f6
A
3168#if DEVELOPMENT || DEBUG
3169extern boolean_t kill_on_no_paging_space;
3170#endif /* DEVELOPMENT || DEBUG */
3171
3172#define MB_SIZE (1024 * 1024ULL)
3173
fe8ab488
A
3174int
3175no_paging_space_action()
b0d623f7 3176{
fe8ab488
A
3177 proc_t p;
3178 struct no_paging_space nps;
b0d623f7
A
3179 struct timeval now;
3180
3181 /*
fe8ab488 3182 * Throttle how often we come through here. Once every 5 seconds should be plenty.
b0d623f7 3183 */
b0d623f7
A
3184 microtime(&now);
3185
fe8ab488
A
3186 if (now.tv_sec <= last_no_space_action.tv_sec + 5)
3187 return (0);
b0d623f7
A
3188
3189 /*
fe8ab488
A
3190 * Examine all processes and find the biggest (biggest is based on the number of pages this
3191 * task has in the compressor pool) that has been marked to have some action
3192 * taken when swap space runs out... we also find the biggest that hasn't been marked for
3193 * action.
b0d623f7 3194 *
fe8ab488
A
3195 * If the biggest non-actionable task is over the "dangerously big" threashold (currently 50% of
3196 * the total number of pages held by the compressor, we go ahead and kill it since no other task
3197 * can have any real effect on the situation. Otherwise, we go after the actionable process.
b0d623f7 3198 */
fe8ab488 3199 bzero(&nps, sizeof(nps));
b0d623f7 3200
fe8ab488 3201 proc_iterate(PROC_ALLPROCLIST, proc_pcontrol_null, (void *)NULL, proc_pcontrol_filter, (void *)&nps);
b0d623f7 3202
fe8ab488
A
3203#if NO_PAGING_SPACE_DEBUG
3204 printf("low swap: npcs_proc_count = %d, npcs_total_size = %qd, npcs_max_size = %qd\n",
3205 nps.npcs_proc_count, nps.npcs_total_size, nps.npcs_max_size);
3206 printf("low swap: pcs_proc_count = %d, pcs_total_size = %qd, pcs_max_size = %qd\n",
3207 nps.pcs_proc_count, nps.pcs_total_size, nps.pcs_max_size);
3208 printf("low swap: apcs_proc_count = %d, apcs_total_size = %qd\n",
3209 nps.apcs_proc_count, nps.apcs_total_size);
3210#endif
3211 if (nps.npcs_max_size > (vm_compressor_pages_compressed() * 50) / 100) {
b0d623f7 3212 /*
fe8ab488
A
3213 * for now we'll knock out any task that has more then 50% of the pages
3214 * held by the compressor
b0d623f7 3215 */
fe8ab488
A
3216 if ((p = proc_find(nps.npcs_pid)) != PROC_NULL) {
3217
3218 if (nps.npcs_uniqueid == p->p_uniqueid) {
3219 /*
3220 * verify this is still the same process
3221 * in case the proc exited and the pid got reused while
3222 * we were finishing the proc_iterate and getting to this point
3223 */
3224 last_no_space_action = now;
3225
813fb2f6 3226 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));
fe8ab488
A
3227 psignal(p, SIGKILL);
3228
3229 proc_rele(p);
b0d623f7 3230
fe8ab488
A
3231 return (0);
3232 }
3233
3234 proc_rele(p);
3235 }
3236 }
b0d623f7 3237
fe8ab488
A
3238 if (nps.pcs_max_size > 0) {
3239 if ((p = proc_find(nps.pcs_pid)) != PROC_NULL) {
3240
3241 if (nps.pcs_uniqueid == p->p_uniqueid) {
3242 /*
3243 * verify this is still the same process
3244 * in case the proc exited and the pid got reused while
3245 * we were finishing the proc_iterate and getting to this point
3246 */
3247 last_no_space_action = now;
3248
813fb2f6
A
3249#if DEVELOPMENT || DEBUG
3250 if (kill_on_no_paging_space == TRUE) {
3251 /*
3252 * We found the largest process that has a process policy i.e. one of
3253 * PC_KILL, PC_SUSP, PC_THROTTLE.
3254 * But we are in a mode where we will kill it regardless of its policy.
3255 */
3256 printf("low swap: killing largest process with pid %d (%s) and size %llu MB\n", p->p_pid, p->p_comm, (nps.pcs_max_size/MB_SIZE));
3257 psignal(p, SIGKILL);
3258
3259 proc_rele(p);
3260
3261 return 1;
3262 }
3263#endif /* DEVELOPMENT || DEBUG */
3264
fe8ab488
A
3265 proc_dopcontrol(p);
3266
3267 proc_rele(p);
3268
3269 return (1);
3270 }
3271
3272 proc_rele(p);
b0d623f7
A
3273 }
3274 }
fe8ab488
A
3275 last_no_space_action = now;
3276
3277 printf("low swap: unable to find any eligible processes to take action on\n");
3278
3279 return (0);
3280}
3281
3282int
3283proc_trace_log(__unused proc_t p, struct proc_trace_log_args *uap, __unused int *retval)
3284{
3285 int ret = 0;
3286 proc_t target_proc = PROC_NULL;
3287 pid_t target_pid = uap->pid;
3288 uint64_t target_uniqueid = uap->uniqueid;
3289 task_t target_task = NULL;
3290
3291 if (priv_check_cred(kauth_cred_get(), PRIV_PROC_TRACE_INSPECT, 0)) {
3292 ret = EPERM;
3293 goto out;
3294 }
3295 target_proc = proc_find(target_pid);
3296 if (target_proc != PROC_NULL) {
3297 if (target_uniqueid != proc_uniqueid(target_proc)) {
3298 ret = ENOENT;
3299 goto out;
3300 }
3301
3302 target_task = proc_task(target_proc);
3303 if (task_send_trace_memory(target_task, target_pid, target_uniqueid)) {
3304 ret = EINVAL;
3305 goto out;
3306 }
3307 } else
3308 ret = ENOENT;
3309
3310out:
3311 if (target_proc != PROC_NULL)
3312 proc_rele(target_proc);
3313 return (ret);
3314}
3315
3316#if VM_SCAN_FOR_SHADOW_CHAIN
3317extern int vm_map_shadow_max(vm_map_t map);
3318int proc_shadow_max(void);
3319int proc_shadow_max(void)
3320{
3321 int retval, max;
3322 proc_t p;
3323 task_t task;
3324 vm_map_t map;
3325
3326 max = 0;
3327 proc_list_lock();
3328 for (p = allproc.lh_first; (p != 0); p = p->p_list.le_next) {
3329 if (p->p_stat == SIDL)
3330 continue;
3331 task = p->task;
3332 if (task == NULL) {
3333 continue;
3334 }
3335 map = get_task_map(task);
3336 if (map == NULL) {
3337 continue;
3338 }
3339 retval = vm_map_shadow_max(map);
3340 if (retval > max) {
3341 max = retval;
3342 }
3343 }
3344 proc_list_unlock();
3345 return max;
b0d623f7 3346}
fe8ab488 3347#endif /* VM_SCAN_FOR_SHADOW_CHAIN */
3e170ce0
A
3348
3349void proc_set_responsible_pid(proc_t target_proc, pid_t responsible_pid);
3350void proc_set_responsible_pid(proc_t target_proc, pid_t responsible_pid)
3351{
3352 if (target_proc != NULL) {
3353 target_proc->p_responsible_pid = responsible_pid;
3354 }
3355 return;
3356}
3357
3358int
3359proc_chrooted(proc_t p)
3360{
3361 int retval = 0;
3362
3363 if (p) {
3364 proc_fdlock(p);
3365 retval = (p->p_fd->fd_rdir != NULL) ? 1 : 0;
3366 proc_fdunlock(p);
3367 }
3368
3369 return retval;
3370}
39037602
A
3371
3372void *
3373proc_get_uthread_uu_threadlist(void * uthread_v)
3374{
3375 uthread_t uth = (uthread_t)uthread_v;
3376 return (uth != NULL) ? uth->uu_threadlist : NULL;
3377}