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