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