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