]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/proc_info.c
xnu-3789.70.16.tar.gz
[apple/xnu.git] / bsd / kern / proc_info.c
1 /*
2 * Copyright (c) 2005-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * sysctl system call.
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/proc_internal.h>
38 #include <sys/kauth.h>
39 #include <sys/file_internal.h>
40 #include <sys/vnode_internal.h>
41 #include <sys/unistd.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <sys/namei.h>
45 #include <sys/tty.h>
46 #include <sys/disklabel.h>
47 #include <sys/vm.h>
48 #include <sys/reason.h>
49 #include <sys/sysctl.h>
50 #include <sys/user.h>
51 #include <sys/aio_kern.h>
52 #include <sys/kern_memorystatus.h>
53
54 #include <security/audit/audit.h>
55
56 #include <mach/machine.h>
57 #include <mach/mach_types.h>
58 #include <mach/vm_param.h>
59 #include <kern/task.h>
60 #include <kern/kalloc.h>
61 #include <kern/assert.h>
62 #include <kern/policy_internal.h>
63
64 #include <vm/vm_kern.h>
65 #include <vm/vm_map.h>
66 #include <mach/host_info.h>
67 #include <mach/task_info.h>
68 #include <mach/thread_info.h>
69 #include <mach/vm_region.h>
70
71 #include <sys/mount_internal.h>
72 #include <sys/proc_info.h>
73 #include <sys/bsdtask_info.h>
74 #include <sys/kdebug.h>
75 #include <sys/sysproto.h>
76 #include <sys/msgbuf.h>
77 #include <sys/priv.h>
78
79 #include <sys/guarded.h>
80
81 #include <machine/machine_routines.h>
82
83 #include <kern/ipc_misc.h>
84
85 #include <vm/vm_protos.h>
86
87 /* Needed by proc_pidnoteexit() */
88 #include <sys/event.h>
89 #include <sys/codesign.h>
90
91 /* Needed by proc_listcoalitions() */
92 #ifdef CONFIG_COALITIONS
93 #include <sys/coalition.h>
94 #endif
95
96 struct pshmnode;
97 struct psemnode;
98 struct pipe;
99 struct kqueue;
100 struct atalk;
101
102 uint64_t get_dispatchqueue_offset_from_proc(void *);
103 uint64_t get_dispatchqueue_serialno_offset_from_proc(void *);
104 int proc_info_internal(int callnum, int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
105
106 /*
107 * TODO: Replace the noinline attribute below. Currently, it serves
108 * to avoid stack bloat caused by inlining multiple functions that
109 * have large stack footprints; when the functions are independent
110 * of each other (will not both be called in any given call to the
111 * caller), this only serves to bloat the stack, as we allocate
112 * space for both functions, despite the fact that we only need a
113 * fraction of that space.
114 *
115 * Long term, these functions should not be allocating everything on
116 * the stack, and should move large allocations (the huge structs
117 * that proc info deals in) to the heap, or eliminate them if
118 * possible.
119 *
120 * The functions that most desperately need to improve stack usage
121 * (starting with the worst offenders):
122 * proc_pidvnodepathinfo
123 * proc_pidinfo
124 * proc_pidregionpathinfo
125 * pid_vnodeinfopath
126 * pid_pshminfo
127 * pid_pseminfo
128 * pid_socketinfo
129 * proc_pid_rusage
130 * proc_pidoriginatorinfo
131 */
132
133 /* protos for proc_info calls */
134 int __attribute__ ((noinline)) proc_listpids(uint32_t type, uint32_t tyoneinfo, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
135 int __attribute__ ((noinline)) proc_pidinfo(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
136 int __attribute__ ((noinline)) proc_pidfdinfo(int pid, int flavor,int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
137 int __attribute__ ((noinline)) proc_kernmsgbuf(user_addr_t buffer, uint32_t buffersize, int32_t * retval);
138 int __attribute__ ((noinline)) proc_setcontrol(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
139 int __attribute__ ((noinline)) proc_pidfileportinfo(int pid, int flavor, mach_port_name_t name, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
140 int __attribute__ ((noinline)) proc_dirtycontrol(int pid, int flavor, uint64_t arg, int32_t * retval);
141 int __attribute__ ((noinline)) proc_terminate(int pid, int32_t * retval);
142 int __attribute__ ((noinline)) proc_pid_rusage(int pid, int flavor, user_addr_t buffer, int32_t * retval);
143 int __attribute__ ((noinline)) proc_pidoriginatorinfo(int pid, int flavor, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
144 int __attribute__ ((noinline)) proc_listcoalitions(int flavor, int coaltype, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
145 int __attribute__ ((noinline)) proc_can_use_foreground_hw(int pid, user_addr_t reason, uint32_t resonsize, int32_t *retval);
146
147 /* protos for procpidinfo calls */
148 int __attribute__ ((noinline)) proc_pidfdlist(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
149 int __attribute__ ((noinline)) proc_pidbsdinfo(proc_t p, struct proc_bsdinfo *pbsd, int zombie);
150 int __attribute__ ((noinline)) proc_pidshortbsdinfo(proc_t p, struct proc_bsdshortinfo *pbsd_shortp, int zombie);
151 int __attribute__ ((noinline)) proc_pidtaskinfo(proc_t p, struct proc_taskinfo *ptinfo);
152 int __attribute__ ((noinline)) proc_pidthreadinfo(proc_t p, uint64_t arg, int thuniqueid, struct proc_threadinfo *pthinfo);
153 int __attribute__ ((noinline)) proc_pidthreadpathinfo(proc_t p, uint64_t arg, struct proc_threadwithpathinfo *pinfo);
154 int __attribute__ ((noinline)) proc_pidlistthreads(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
155 int __attribute__ ((noinline)) proc_pidregioninfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
156 int __attribute__ ((noinline)) proc_pidregionpathinfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
157 int __attribute__ ((noinline)) proc_pidregionpathinfo2(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
158 int __attribute__ ((noinline)) proc_pidregionpathinfo3(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
159 int __attribute__ ((noinline)) proc_pidvnodepathinfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
160 int __attribute__ ((noinline)) proc_pidpathinfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
161 int __attribute__ ((noinline)) proc_pidworkqueueinfo(proc_t p, struct proc_workqueueinfo *pwqinfo);
162 int __attribute__ ((noinline)) proc_pidfileportlist(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
163 void __attribute__ ((noinline)) proc_piduniqidentifierinfo(proc_t p, struct proc_uniqidentifierinfo *p_uniqidinfo);
164 void __attribute__ ((noinline)) proc_archinfo(proc_t p, struct proc_archinfo *pai);
165 void __attribute__ ((noinline)) proc_pidcoalitioninfo(proc_t p, struct proc_pidcoalitioninfo *pci);
166 int __attribute__ ((noinline)) proc_pidnoteexit(proc_t p, uint64_t arg, uint32_t *data);
167 int __attribute__ ((noinline)) proc_pidexitreasoninfo(proc_t p, struct proc_exitreasoninfo *peri, struct proc_exitreasonbasicinfo *pberi);
168 int __attribute__ ((noinline)) proc_pidoriginatorpid_uuid(uuid_t uuid, uint32_t buffersize, pid_t *pid);
169
170
171 /* protos for proc_pidfdinfo calls */
172 int __attribute__ ((noinline)) pid_vnodeinfo(vnode_t vp, uint32_t vid, struct fileproc * fp,proc_t proc, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
173 int __attribute__ ((noinline)) pid_vnodeinfopath(vnode_t vp, uint32_t vid, struct fileproc * fp,proc_t proc, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
174 int __attribute__ ((noinline)) pid_socketinfo(socket_t so, struct fileproc *fp,proc_t proc, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
175 int __attribute__ ((noinline)) pid_pseminfo(struct psemnode * psem, struct fileproc * fp, proc_t proc, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
176 int __attribute__ ((noinline)) pid_pshminfo(struct pshmnode * pshm, struct fileproc * fp, proc_t proc, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
177 int __attribute__ ((noinline)) pid_pipeinfo(struct pipe * p, struct fileproc * fp, proc_t proc, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
178 int __attribute__ ((noinline)) pid_kqueueinfo(struct kqueue * kq, struct fileproc * fp, proc_t proc, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
179 int __attribute__ ((noinline)) pid_atalkinfo(struct atalk * at, struct fileproc * fp, proc_t proc, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
180
181
182 /* protos for misc */
183
184 int fill_vnodeinfo(vnode_t vp, struct vnode_info *vinfo);
185 void fill_fileinfo(struct fileproc * fp, proc_t proc, int fd, struct proc_fileinfo * finfo);
186 int proc_security_policy(proc_t targetp, int callnum, int flavor, boolean_t check_same_user);
187 static void munge_vinfo_stat(struct stat64 *sbp, struct vinfo_stat *vsbp);
188 static int proc_piduuidinfo(pid_t pid, uuid_t uuid_buf, uint32_t buffersize);
189 int proc_pidpathinfo_internal(proc_t p, __unused uint64_t arg, char *buf, uint32_t buffersize, __unused int32_t *retval);
190 int proc_listfd_kqueue(proc_t p, int32_t *fdlist, int len);
191 int proc_kqueue_udata_info(proc_t p, int32_t fd, uint64_t *buffer, int bufsize);
192 int proc_list_uptrs(proc_t p, uint64_t *udata_buffer, int size);
193
194 extern int cansignal(struct proc *, kauth_cred_t, struct proc *, int, int);
195 extern int proc_get_rusage(proc_t proc, int flavor, user_addr_t buffer, int is_zombie);
196
197 #define CHECK_SAME_USER TRUE
198 #define NO_CHECK_SAME_USER FALSE
199
200 uint64_t get_dispatchqueue_offset_from_proc(void *p)
201 {
202 if(p != NULL) {
203 proc_t pself = (proc_t)p;
204 return (pself->p_dispatchqueue_offset);
205 } else {
206 return (uint64_t)0;
207 }
208 }
209
210 uint64_t get_dispatchqueue_serialno_offset_from_proc(void *p)
211 {
212 if(p != NULL) {
213 proc_t pself = (proc_t)p;
214 return (pself->p_dispatchqueue_serialno_offset);
215 } else {
216 return (uint64_t)0;
217 }
218 }
219
220 /***************************** proc_info ********************/
221
222 int
223 proc_info(__unused struct proc *p, struct proc_info_args * uap, int32_t *retval)
224 {
225 return(proc_info_internal(uap->callnum, uap->pid, uap->flavor, uap->arg, uap->buffer, uap->buffersize, retval));
226 }
227
228
229 int
230 proc_info_internal(int callnum, int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
231 {
232
233 switch(callnum) {
234 case PROC_INFO_CALL_LISTPIDS:
235 /* pid contains type and flavor contains typeinfo */
236 return(proc_listpids(pid, flavor, buffer, buffersize, retval));
237 case PROC_INFO_CALL_PIDINFO:
238 return(proc_pidinfo(pid, flavor, arg, buffer, buffersize, retval));
239 case PROC_INFO_CALL_PIDFDINFO:
240 return(proc_pidfdinfo(pid, flavor, (int)arg, buffer, buffersize, retval));
241 case PROC_INFO_CALL_KERNMSGBUF:
242 return(proc_kernmsgbuf(buffer, buffersize, retval));
243 case PROC_INFO_CALL_SETCONTROL:
244 return(proc_setcontrol(pid, flavor, arg, buffer, buffersize, retval));
245 case PROC_INFO_CALL_PIDFILEPORTINFO:
246 return(proc_pidfileportinfo(pid, flavor, (mach_port_name_t)arg, buffer, buffersize, retval));
247 case PROC_INFO_CALL_TERMINATE:
248 return(proc_terminate(pid, retval));
249 case PROC_INFO_CALL_DIRTYCONTROL:
250 return(proc_dirtycontrol(pid, flavor, arg, retval));
251 case PROC_INFO_CALL_PIDRUSAGE:
252 return (proc_pid_rusage(pid, flavor, buffer, retval));
253 case PROC_INFO_CALL_PIDORIGINATORINFO:
254 return (proc_pidoriginatorinfo(pid, flavor, buffer, buffersize, retval));
255 case PROC_INFO_CALL_LISTCOALITIONS:
256 return proc_listcoalitions(pid /* flavor */, flavor /* coaltype */, buffer,
257 buffersize, retval);
258 case PROC_INFO_CALL_CANUSEFGHW:
259 return proc_can_use_foreground_hw(pid, buffer, buffersize, retval);
260 default:
261 return(EINVAL);
262 }
263
264 return(EINVAL);
265 }
266
267 /******************* proc_listpids routine ****************/
268 int
269 proc_listpids(uint32_t type, uint32_t typeinfo, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
270 {
271 int numprocs, wantpids;
272 char * kbuf;
273 int * ptr;
274 int n, skip;
275 struct proc * p;
276 struct tty * tp;
277 int error = 0;
278 struct proclist *current_list;
279
280 /* Do we have permission to look into this? */
281 if ((error = proc_security_policy(PROC_NULL, PROC_INFO_CALL_LISTPIDS, type, NO_CHECK_SAME_USER)))
282 return (error);
283
284 /* if the buffer is null, return num of procs */
285 if (buffer == (user_addr_t)0) {
286 *retval = ((nprocs+20) * sizeof(int));
287 return(0);
288 }
289
290 if (buffersize < sizeof(int)) {
291 return(ENOMEM);
292 }
293 wantpids = buffersize/sizeof(int);
294 numprocs = nprocs+20;
295 if (numprocs > wantpids)
296 numprocs = wantpids;
297
298 kbuf = (char *)kalloc((vm_size_t)(numprocs * sizeof(int)));
299 if (kbuf == NULL)
300 return(ENOMEM);
301 bzero(kbuf, sizeof(int));
302
303 proc_list_lock();
304
305
306 n = 0;
307 ptr = (int *)kbuf;
308 current_list = &allproc;
309 proc_loop:
310 LIST_FOREACH(p, current_list, p_list) {
311 skip = 0;
312 switch (type) {
313 case PROC_PGRP_ONLY:
314 if (p->p_pgrpid != (pid_t)typeinfo)
315 skip = 1;
316 break;
317 case PROC_PPID_ONLY:
318 if ((p->p_ppid != (pid_t)typeinfo) && (((p->p_lflag & P_LTRACED) == 0) || (p->p_oppid != (pid_t)typeinfo)))
319 skip = 1;
320 break;
321
322 case PROC_ALL_PIDS:
323 skip = 0;
324 break;
325 case PROC_TTY_ONLY:
326 /* racy but list lock is held */
327 if ((p->p_flag & P_CONTROLT) == 0 ||
328 (p->p_pgrp == NULL) || (p->p_pgrp->pg_session == NULL) ||
329 (tp = SESSION_TP(p->p_pgrp->pg_session)) == TTY_NULL ||
330 tp->t_dev != (dev_t)typeinfo)
331 skip = 1;
332 break;
333 case PROC_UID_ONLY:
334 if (p->p_ucred == NULL)
335 skip = 1;
336 else {
337 kauth_cred_t my_cred;
338 uid_t uid;
339
340 my_cred = kauth_cred_proc_ref(p);
341 uid = kauth_cred_getuid(my_cred);
342 kauth_cred_unref(&my_cred);
343 if (uid != (uid_t)typeinfo)
344 skip = 1;
345 }
346 break;
347 case PROC_RUID_ONLY:
348 if (p->p_ucred == NULL)
349 skip = 1;
350 else {
351 kauth_cred_t my_cred;
352 uid_t uid;
353
354 my_cred = kauth_cred_proc_ref(p);
355 uid = kauth_cred_getruid(my_cred);
356 kauth_cred_unref(&my_cred);
357 if (uid != (uid_t)typeinfo)
358 skip = 1;
359 }
360 break;
361 default:
362 skip = 1;
363 break;
364 };
365
366 if(skip == 0) {
367 *ptr++ = p->p_pid;
368 n++;
369 }
370 if (n >= numprocs)
371 break;
372 }
373
374 if ((n < numprocs) && (current_list == &allproc)) {
375 current_list = &zombproc;
376 goto proc_loop;
377 }
378
379 proc_list_unlock();
380
381 ptr = (int *)kbuf;
382 error = copyout((caddr_t)ptr, buffer, n * sizeof(int));
383 if (error == 0)
384 *retval = (n * sizeof(int));
385 kfree((void *)kbuf, (vm_size_t)(numprocs * sizeof(int)));
386
387 return(error);
388 }
389
390
391 /********************************** proc_pidfdlist routines ********************************/
392
393 int
394 proc_pidfdlist(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval)
395 {
396 int numfds, needfds;
397 char * kbuf;
398 struct proc_fdinfo * pfd;
399 struct fileproc * fp;
400 int n;
401 int count = 0;
402 int error = 0;
403
404 numfds = p->p_fd->fd_nfiles;
405
406 if (buffer == (user_addr_t) 0) {
407 numfds += 20;
408 *retval = (numfds * sizeof(struct proc_fdinfo));
409 return(0);
410 }
411
412 /* buffersize is big enough atleast for one struct */
413 needfds = buffersize/sizeof(struct proc_fdinfo);
414
415 if (numfds > needfds)
416 numfds = needfds;
417
418 kbuf = (char *)kalloc((vm_size_t)(numfds * sizeof(struct proc_fdinfo)));
419 if (kbuf == NULL)
420 return(ENOMEM);
421 bzero(kbuf, numfds * sizeof(struct proc_fdinfo));
422
423 proc_fdlock(p);
424
425 pfd = (struct proc_fdinfo *)kbuf;
426
427 for (n = 0; ((n < numfds) && (n < p->p_fd->fd_nfiles)); n++) {
428 if (((fp = p->p_fd->fd_ofiles[n]) != 0)
429 && ((p->p_fd->fd_ofileflags[n] & UF_RESERVED) == 0)) {
430 file_type_t fdtype = FILEGLOB_DTYPE(fp->f_fglob);
431 pfd->proc_fd = n;
432 pfd->proc_fdtype = (fdtype != DTYPE_ATALK) ?
433 fdtype : PROX_FDTYPE_ATALK;
434 count++;
435 pfd++;
436 }
437 }
438 proc_fdunlock(p);
439
440 error = copyout(kbuf, buffer, count * sizeof(struct proc_fdinfo));
441 kfree((void *)kbuf, (vm_size_t)(numfds * sizeof(struct proc_fdinfo)));
442 if (error == 0)
443 *retval = (count * sizeof(struct proc_fdinfo));
444 return(error);
445 }
446
447 /*
448 * Helper functions for proc_pidfileportlist.
449 */
450 static int
451 proc_fileport_count(__unused mach_port_name_t name,
452 __unused struct fileglob *fg, void *arg)
453 {
454 uint32_t *counter = arg;
455
456 *counter += 1;
457 return (0);
458 }
459
460 struct fileport_fdtype_args {
461 struct proc_fileportinfo *ffa_pfi;
462 struct proc_fileportinfo *ffa_pfi_end;
463 };
464
465 static int
466 proc_fileport_fdtype(mach_port_name_t name, struct fileglob *fg, void *arg)
467 {
468 struct fileport_fdtype_args *ffa = arg;
469
470 if (ffa->ffa_pfi != ffa->ffa_pfi_end) {
471 file_type_t fdtype = FILEGLOB_DTYPE(fg);
472
473 ffa->ffa_pfi->proc_fdtype = (fdtype != DTYPE_ATALK) ?
474 fdtype : PROX_FDTYPE_ATALK;
475 ffa->ffa_pfi->proc_fileport = name;
476 ffa->ffa_pfi++;
477 return (0); /* keep walking */
478 } else
479 return (-1); /* stop the walk! */
480 }
481
482 int
483 proc_pidfileportlist(proc_t p,
484 user_addr_t buffer, uint32_t buffersize, int32_t *retval)
485 {
486 void *kbuf;
487 vm_size_t kbufsize;
488 struct proc_fileportinfo *pfi;
489 uint32_t needfileports, numfileports;
490 struct fileport_fdtype_args ffa;
491 int error;
492
493 needfileports = buffersize / sizeof (*pfi);
494 if ((user_addr_t)0 == buffer || needfileports > (uint32_t)maxfiles) {
495 /*
496 * Either (i) the user is asking for a fileport count,
497 * or (ii) the number of fileports they're asking for is
498 * larger than the maximum number of open files (!); count
499 * them to bound subsequent heap allocations.
500 */
501 numfileports = 0;
502 switch (fileport_walk(p->task,
503 proc_fileport_count, &numfileports)) {
504 case KERN_SUCCESS:
505 break;
506 case KERN_RESOURCE_SHORTAGE:
507 return (ENOMEM);
508 case KERN_INVALID_TASK:
509 return (ESRCH);
510 default:
511 return (EINVAL);
512 }
513
514 if (numfileports == 0) {
515 *retval = 0; /* none at all, bail */
516 return (0);
517 }
518 if ((user_addr_t)0 == buffer) {
519 numfileports += 20; /* accelerate convergence */
520 *retval = numfileports * sizeof (*pfi);
521 return (0);
522 }
523 if (needfileports > numfileports)
524 needfileports = numfileports;
525 }
526
527 assert(buffersize >= PROC_PIDLISTFILEPORTS_SIZE);
528
529 kbufsize = (vm_size_t)needfileports * sizeof (*pfi);
530 pfi = kbuf = kalloc(kbufsize);
531 if (kbuf == NULL)
532 return (ENOMEM);
533 bzero(kbuf, kbufsize);
534
535 ffa.ffa_pfi = pfi;
536 ffa.ffa_pfi_end = pfi + needfileports;
537
538 switch (fileport_walk(p->task, proc_fileport_fdtype, &ffa)) {
539 case KERN_SUCCESS:
540 error = 0;
541 pfi = ffa.ffa_pfi;
542 if ((numfileports = pfi - (typeof(pfi))kbuf) == 0)
543 break;
544 if (numfileports > needfileports)
545 panic("more fileports returned than requested");
546 error = copyout(kbuf, buffer, numfileports * sizeof (*pfi));
547 break;
548 case KERN_RESOURCE_SHORTAGE:
549 error = ENOMEM;
550 break;
551 case KERN_INVALID_TASK:
552 error = ESRCH;
553 break;
554 default:
555 error = EINVAL;
556 break;
557 }
558 kfree(kbuf, kbufsize);
559 if (error == 0)
560 *retval = numfileports * sizeof (*pfi);
561 return (error);
562 }
563
564 int
565 proc_pidbsdinfo(proc_t p, struct proc_bsdinfo * pbsd, int zombie)
566 {
567 struct tty *tp;
568 struct session *sessionp = NULL;
569 struct pgrp * pg;
570 kauth_cred_t my_cred;
571
572 pg = proc_pgrp(p);
573 sessionp = proc_session(p);
574
575 my_cred = kauth_cred_proc_ref(p);
576 bzero(pbsd, sizeof(struct proc_bsdinfo));
577 pbsd->pbi_status = p->p_stat;
578 pbsd->pbi_xstatus = p->p_xstat;
579 pbsd->pbi_pid = p->p_pid;
580 pbsd->pbi_ppid = p->p_ppid;
581 pbsd->pbi_uid = kauth_cred_getuid(my_cred);
582 pbsd->pbi_gid = kauth_cred_getgid(my_cred);
583 pbsd->pbi_ruid = kauth_cred_getruid(my_cred);
584 pbsd->pbi_rgid = kauth_cred_getrgid(my_cred);
585 pbsd->pbi_svuid = kauth_cred_getsvuid(my_cred);
586 pbsd->pbi_svgid = kauth_cred_getsvgid(my_cred);
587 kauth_cred_unref(&my_cred);
588
589 pbsd->pbi_nice = p->p_nice;
590 pbsd->pbi_start_tvsec = p->p_start.tv_sec;
591 pbsd->pbi_start_tvusec = p->p_start.tv_usec;
592 bcopy(&p->p_comm, &pbsd->pbi_comm[0], MAXCOMLEN);
593 pbsd->pbi_comm[MAXCOMLEN - 1] = '\0';
594 bcopy(&p->p_name, &pbsd->pbi_name[0], 2*MAXCOMLEN);
595 pbsd->pbi_name[(2*MAXCOMLEN) - 1] = '\0';
596
597 pbsd->pbi_flags = 0;
598 if ((p->p_flag & P_SYSTEM) == P_SYSTEM)
599 pbsd->pbi_flags |= PROC_FLAG_SYSTEM;
600 if ((p->p_lflag & P_LTRACED) == P_LTRACED)
601 pbsd->pbi_flags |= PROC_FLAG_TRACED;
602 if ((p->p_lflag & P_LEXIT) == P_LEXIT)
603 pbsd->pbi_flags |= PROC_FLAG_INEXIT;
604 if ((p->p_lflag & P_LPPWAIT) == P_LPPWAIT)
605 pbsd->pbi_flags |= PROC_FLAG_PPWAIT;
606 if ((p->p_flag & P_LP64) == P_LP64)
607 pbsd->pbi_flags |= PROC_FLAG_LP64;
608 if ((p->p_flag & P_CONTROLT) == P_CONTROLT)
609 pbsd->pbi_flags |= PROC_FLAG_CONTROLT;
610 if ((p->p_flag & P_THCWD) == P_THCWD)
611 pbsd->pbi_flags |= PROC_FLAG_THCWD;
612 if ((p->p_flag & P_SUGID) == P_SUGID)
613 pbsd->pbi_flags |= PROC_FLAG_PSUGID;
614 if ((p->p_flag & P_EXEC) == P_EXEC)
615 pbsd->pbi_flags |= PROC_FLAG_EXEC;
616
617 if (sessionp != SESSION_NULL) {
618 if (SESS_LEADER(p, sessionp))
619 pbsd->pbi_flags |= PROC_FLAG_SLEADER;
620 if (sessionp->s_ttyvp)
621 pbsd->pbi_flags |= PROC_FLAG_CTTY;
622 }
623
624 if ((p->p_flag & P_DELAYIDLESLEEP) == P_DELAYIDLESLEEP)
625 pbsd->pbi_flags |= PROC_FLAG_DELAYIDLESLEEP;
626
627 switch(PROC_CONTROL_STATE(p)) {
628 case P_PCTHROTTLE:
629 pbsd->pbi_flags |= PROC_FLAG_PC_THROTTLE;
630 break;
631 case P_PCSUSP:
632 pbsd->pbi_flags |= PROC_FLAG_PC_SUSP;
633 break;
634 case P_PCKILL:
635 pbsd->pbi_flags |= PROC_FLAG_PC_KILL;
636 break;
637 };
638
639 switch(PROC_ACTION_STATE(p)) {
640 case P_PCTHROTTLE:
641 pbsd->pbi_flags |= PROC_FLAG_PA_THROTTLE;
642 break;
643 case P_PCSUSP:
644 pbsd->pbi_flags |= PROC_FLAG_PA_SUSP;
645 break;
646 };
647
648 /* if process is a zombie skip bg state */
649 if ((zombie == 0) && (p->p_stat != SZOMB) && (p->task != TASK_NULL))
650 proc_get_darwinbgstate(p->task, &pbsd->pbi_flags);
651
652 if (zombie == 0)
653 pbsd->pbi_nfiles = p->p_fd->fd_nfiles;
654
655 pbsd->e_tdev = NODEV;
656 if (pg != PGRP_NULL) {
657 pbsd->pbi_pgid = p->p_pgrpid;
658 pbsd->pbi_pjobc = pg->pg_jobc;
659 if ((p->p_flag & P_CONTROLT) && (sessionp != SESSION_NULL) && (tp = SESSION_TP(sessionp))) {
660 pbsd->e_tdev = tp->t_dev;
661 pbsd->e_tpgid = sessionp->s_ttypgrpid;
662 }
663 }
664 if (sessionp != SESSION_NULL)
665 session_rele(sessionp);
666 if (pg != PGRP_NULL)
667 pg_rele(pg);
668
669 return(0);
670 }
671
672
673 int
674 proc_pidshortbsdinfo(proc_t p, struct proc_bsdshortinfo * pbsd_shortp, int zombie)
675 {
676 bzero(pbsd_shortp, sizeof(struct proc_bsdshortinfo));
677 pbsd_shortp->pbsi_pid = p->p_pid;
678 pbsd_shortp->pbsi_ppid = p->p_ppid;
679 pbsd_shortp->pbsi_pgid = p->p_pgrpid;
680 pbsd_shortp->pbsi_status = p->p_stat;
681 bcopy(&p->p_comm, &pbsd_shortp->pbsi_comm[0], MAXCOMLEN);
682 pbsd_shortp->pbsi_comm[MAXCOMLEN - 1] = '\0';
683
684 pbsd_shortp->pbsi_flags = 0;
685 if ((p->p_flag & P_SYSTEM) == P_SYSTEM)
686 pbsd_shortp->pbsi_flags |= PROC_FLAG_SYSTEM;
687 if ((p->p_lflag & P_LTRACED) == P_LTRACED)
688 pbsd_shortp->pbsi_flags |= PROC_FLAG_TRACED;
689 if ((p->p_lflag & P_LEXIT) == P_LEXIT)
690 pbsd_shortp->pbsi_flags |= PROC_FLAG_INEXIT;
691 if ((p->p_lflag & P_LPPWAIT) == P_LPPWAIT)
692 pbsd_shortp->pbsi_flags |= PROC_FLAG_PPWAIT;
693 if ((p->p_flag & P_LP64) == P_LP64)
694 pbsd_shortp->pbsi_flags |= PROC_FLAG_LP64;
695 if ((p->p_flag & P_CONTROLT) == P_CONTROLT)
696 pbsd_shortp->pbsi_flags |= PROC_FLAG_CONTROLT;
697 if ((p->p_flag & P_THCWD) == P_THCWD)
698 pbsd_shortp->pbsi_flags |= PROC_FLAG_THCWD;
699 if ((p->p_flag & P_SUGID) == P_SUGID)
700 pbsd_shortp->pbsi_flags |= PROC_FLAG_PSUGID;
701 if ((p->p_flag & P_EXEC) == P_EXEC)
702 pbsd_shortp->pbsi_flags |= PROC_FLAG_EXEC;
703 if ((p->p_flag & P_DELAYIDLESLEEP) == P_DELAYIDLESLEEP)
704 pbsd_shortp->pbsi_flags |= PROC_FLAG_DELAYIDLESLEEP;
705
706 switch(PROC_CONTROL_STATE(p)) {
707 case P_PCTHROTTLE:
708 pbsd_shortp->pbsi_flags |= PROC_FLAG_PC_THROTTLE;
709 break;
710 case P_PCSUSP:
711 pbsd_shortp->pbsi_flags |= PROC_FLAG_PC_SUSP;
712 break;
713 case P_PCKILL:
714 pbsd_shortp->pbsi_flags |= PROC_FLAG_PC_KILL;
715 break;
716 };
717
718 switch(PROC_ACTION_STATE(p)) {
719 case P_PCTHROTTLE:
720 pbsd_shortp->pbsi_flags |= PROC_FLAG_PA_THROTTLE;
721 break;
722 case P_PCSUSP:
723 pbsd_shortp->pbsi_flags |= PROC_FLAG_PA_SUSP;
724 break;
725 };
726
727 /* if process is a zombie skip bg state */
728 if ((zombie == 0) && (p->p_stat != SZOMB) && (p->task != TASK_NULL))
729 proc_get_darwinbgstate(p->task, &pbsd_shortp->pbsi_flags);
730
731 pbsd_shortp->pbsi_uid = p->p_uid;
732 pbsd_shortp->pbsi_gid = p->p_gid;
733 pbsd_shortp->pbsi_ruid = p->p_ruid;
734 pbsd_shortp->pbsi_rgid = p->p_rgid;
735 pbsd_shortp->pbsi_svuid = p->p_svuid;
736 pbsd_shortp->pbsi_svgid = p->p_svgid;
737
738 return(0);
739 }
740
741 int
742 proc_pidtaskinfo(proc_t p, struct proc_taskinfo * ptinfo)
743 {
744 task_t task;
745
746 task = p->task;
747
748 bzero(ptinfo, sizeof(struct proc_taskinfo));
749 fill_taskprocinfo(task, (struct proc_taskinfo_internal *)ptinfo);
750
751 return(0);
752 }
753
754
755
756 int
757 proc_pidthreadinfo(proc_t p, uint64_t arg, int thuniqueid, struct proc_threadinfo *pthinfo)
758 {
759 int error = 0;
760 uint64_t threadaddr = (uint64_t)arg;
761
762 bzero(pthinfo, sizeof(struct proc_threadinfo));
763
764 error = fill_taskthreadinfo(p->task, threadaddr, thuniqueid, (struct proc_threadinfo_internal *)pthinfo, NULL, NULL);
765 if (error)
766 return(ESRCH);
767 else
768 return(0);
769
770 }
771
772 boolean_t
773 bsd_hasthreadname(void *uth)
774 {
775 struct uthread *ut = (struct uthread*)uth;
776
777 /* This doesn't check for the empty string; do we care? */
778 if (ut->pth_name) {
779 return TRUE;
780 } else {
781 return FALSE;
782 }
783 }
784
785 void
786 bsd_getthreadname(void *uth, char *buffer)
787 {
788 struct uthread *ut = (struct uthread *)uth;
789 if(ut->pth_name)
790 bcopy(ut->pth_name,buffer,MAXTHREADNAMESIZE);
791 }
792
793 /*
794 * This is known to race with regards to the contents of the thread name; concurrent
795 * callers may result in a garbled name.
796 */
797 void
798 bsd_setthreadname(void *uth, const char *name) {
799 struct uthread *ut = (struct uthread *)uth;
800 char * name_buf = NULL;
801
802 if (!ut->pth_name) {
803 /* If there is no existing thread name, allocate a buffer for one. */
804 name_buf = kalloc(MAXTHREADNAMESIZE);
805 assert(name_buf);
806 bzero(name_buf, MAXTHREADNAMESIZE);
807
808 /* Someone could conceivably have named the thread at the same time we did. */
809 if (!OSCompareAndSwapPtr(NULL, name_buf, &ut->pth_name)) {
810 kfree(name_buf, MAXTHREADNAMESIZE);
811 }
812 } else {
813 kernel_debug_string_simple(TRACE_STRING_THREADNAME_PREV, ut->pth_name);
814 }
815
816 strncpy(ut->pth_name, name, MAXTHREADNAMESIZE - 1);
817 kernel_debug_string_simple(TRACE_STRING_THREADNAME, ut->pth_name);
818 }
819
820 void
821 bsd_copythreadname(void *dst_uth, void *src_uth)
822 {
823 struct uthread *dst_ut = (struct uthread *)dst_uth;
824 struct uthread *src_ut = (struct uthread *)src_uth;
825
826 if (src_ut->pth_name == NULL)
827 return;
828
829 if (dst_ut->pth_name == NULL) {
830 dst_ut->pth_name = (char *)kalloc(MAXTHREADNAMESIZE);
831 if (dst_ut->pth_name == NULL)
832 return;
833 }
834
835 bcopy(src_ut->pth_name, dst_ut->pth_name, MAXTHREADNAMESIZE);
836 return;
837 }
838
839 void
840 bsd_threadcdir(void * uth, void *vptr, int *vidp)
841 {
842 struct uthread * ut = (struct uthread *)uth;
843 vnode_t vp;
844 vnode_t *vpp = (vnode_t *)vptr;
845
846 vp = ut->uu_cdir;
847 if (vp != NULLVP) {
848 if (vpp != NULL) {
849 *vpp = vp;
850 if (vidp != NULL)
851 *vidp = vp->v_id;
852 }
853 }
854 }
855
856
857 int
858 proc_pidthreadpathinfo(proc_t p, uint64_t arg, struct proc_threadwithpathinfo *pinfo)
859 {
860 vnode_t vp = NULLVP;
861 int vid;
862 int error = 0;
863 uint64_t threadaddr = (uint64_t)arg;
864 int count;
865
866 bzero(pinfo, sizeof(struct proc_threadwithpathinfo));
867
868 error = fill_taskthreadinfo(p->task, threadaddr, 0, (struct proc_threadinfo_internal *)&pinfo->pt, (void *)&vp, &vid);
869 if (error)
870 return(ESRCH);
871
872 if ((vp != NULLVP) && ((vnode_getwithvid(vp, vid)) == 0)) {
873 error = fill_vnodeinfo(vp, &pinfo->pvip.vip_vi) ;
874 if (error == 0) {
875 count = MAXPATHLEN;
876 vn_getpath(vp, &pinfo->pvip.vip_path[0], &count);
877 pinfo->pvip.vip_path[MAXPATHLEN-1] = 0;
878 }
879 vnode_put(vp);
880 }
881 return(error);
882 }
883
884
885
886 int
887 proc_pidlistthreads(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval)
888 {
889 int count = 0;
890 int ret = 0;
891 int error = 0;
892 void * kbuf;
893 int numthreads;
894
895
896 count = buffersize/(sizeof(uint64_t));
897 numthreads = get_numthreads(p->task);
898
899 numthreads += 10;
900
901 if (numthreads > count)
902 numthreads = count;
903
904 kbuf = (void *)kalloc(numthreads * sizeof(uint64_t));
905 if (kbuf == NULL)
906 return(ENOMEM);
907 bzero(kbuf, numthreads * sizeof(uint64_t));
908
909 ret = fill_taskthreadlist(p->task, kbuf, numthreads);
910
911 error = copyout(kbuf, buffer, ret);
912 kfree(kbuf, numthreads * sizeof(uint64_t));
913 if (error == 0)
914 *retval = ret;
915 return(error);
916
917 }
918
919
920 int
921 proc_pidregioninfo(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
922 {
923 struct proc_regioninfo preginfo;
924 int ret, error = 0;
925
926 bzero(&preginfo, sizeof(struct proc_regioninfo));
927 ret = fill_procregioninfo( p->task, arg, (struct proc_regioninfo_internal *)&preginfo, (uintptr_t *)0, (uint32_t *)0);
928 if (ret == 0)
929 return(EINVAL);
930 error = copyout(&preginfo, buffer, sizeof(struct proc_regioninfo));
931 if (error == 0)
932 *retval = sizeof(struct proc_regioninfo);
933 return(error);
934 }
935
936
937 int
938 proc_pidregionpathinfo(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
939 {
940 struct proc_regionwithpathinfo preginfo;
941 int ret, error = 0;
942 uintptr_t vnodeaddr= 0;
943 uint32_t vnodeid= 0;
944 vnode_t vp;
945 int count;
946
947 bzero(&preginfo, sizeof(struct proc_regionwithpathinfo));
948
949 ret = fill_procregioninfo( p->task, arg, (struct proc_regioninfo_internal *)&preginfo.prp_prinfo, (uintptr_t *)&vnodeaddr, (uint32_t *)&vnodeid);
950 if (ret == 0)
951 return(EINVAL);
952 if (vnodeaddr) {
953 vp = (vnode_t)vnodeaddr;
954 if ((vnode_getwithvid(vp, vnodeid)) == 0) {
955 /* FILL THE VNODEINFO */
956 error = fill_vnodeinfo(vp, &preginfo.prp_vip.vip_vi);
957 count = MAXPATHLEN;
958 vn_getpath(vp, &preginfo.prp_vip.vip_path[0], &count);
959 /* Always make sure it is null terminated */
960 preginfo.prp_vip.vip_path[MAXPATHLEN-1] = 0;
961 vnode_put(vp);
962 }
963 }
964 error = copyout(&preginfo, buffer, sizeof(struct proc_regionwithpathinfo));
965 if (error == 0)
966 *retval = sizeof(struct proc_regionwithpathinfo);
967 return(error);
968 }
969
970 int
971 proc_pidregionpathinfo2(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
972 {
973 struct proc_regionwithpathinfo preginfo;
974 int ret, error = 0;
975 uintptr_t vnodeaddr= 0;
976 uint32_t vnodeid= 0;
977 vnode_t vp;
978 int count;
979
980 bzero(&preginfo, sizeof(struct proc_regionwithpathinfo));
981
982 ret = fill_procregioninfo_onlymappedvnodes( p->task, arg, (struct proc_regioninfo_internal *)&preginfo.prp_prinfo, (uintptr_t *)&vnodeaddr, (uint32_t *)&vnodeid);
983 if (ret == 0)
984 return(EINVAL);
985 if (!vnodeaddr)
986 return(EINVAL);
987
988 vp = (vnode_t)vnodeaddr;
989 if ((vnode_getwithvid(vp, vnodeid)) == 0) {
990 /* FILL THE VNODEINFO */
991 error = fill_vnodeinfo(vp, &preginfo.prp_vip.vip_vi);
992 count = MAXPATHLEN;
993 vn_getpath(vp, &preginfo.prp_vip.vip_path[0], &count);
994 /* Always make sure it is null terminated */
995 preginfo.prp_vip.vip_path[MAXPATHLEN-1] = 0;
996 vnode_put(vp);
997 } else {
998 return(EINVAL);
999 }
1000
1001 error = copyout(&preginfo, buffer, sizeof(struct proc_regionwithpathinfo));
1002 if (error == 0)
1003 *retval = sizeof(struct proc_regionwithpathinfo);
1004 return(error);
1005 }
1006
1007 int
1008 proc_pidregionpathinfo3(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
1009 {
1010 struct proc_regionwithpathinfo preginfo;
1011 int ret, error = 0;
1012 uintptr_t vnodeaddr;
1013 uint32_t vnodeid;
1014 vnode_t vp;
1015 int count;
1016 uint64_t addr = 0;
1017
1018 /* Loop while looking for vnodes that match dev_t filter */
1019 do {
1020 bzero(&preginfo, sizeof(struct proc_regionwithpathinfo));
1021 vnodeaddr = 0;
1022 vnodeid = 0;
1023
1024 ret = fill_procregioninfo_onlymappedvnodes( p->task, addr, (struct proc_regioninfo_internal *)&preginfo.prp_prinfo, (uintptr_t *)&vnodeaddr, (uint32_t *)&vnodeid);
1025 if (ret == 0)
1026 return(EINVAL);
1027 if (!vnodeaddr)
1028 return(EINVAL);
1029
1030 vp = (vnode_t)vnodeaddr;
1031 if ((vnode_getwithvid(vp, vnodeid)) == 0) {
1032 /* Check if the vnode matches the filter, otherwise loop looking for the next memory region backed by a vnode */
1033 struct vnode_attr va;
1034
1035 memset(&va, 0, sizeof(va));
1036 VATTR_INIT(&va);
1037 VATTR_WANTED(&va, va_fsid);
1038
1039 ret = vnode_getattr(vp, &va, vfs_context_current());
1040 if (ret) {
1041 vnode_put(vp);
1042 return(EINVAL);
1043 }
1044
1045 if (va.va_fsid == arg) {
1046 /* FILL THE VNODEINFO */
1047 error = fill_vnodeinfo(vp, &preginfo.prp_vip.vip_vi);
1048 count = MAXPATHLEN;
1049 vn_getpath(vp, &preginfo.prp_vip.vip_path[0], &count);
1050 /* Always make sure it is null terminated */
1051 preginfo.prp_vip.vip_path[MAXPATHLEN-1] = 0;
1052 vnode_put(vp);
1053 break;
1054 }
1055 vnode_put(vp);
1056 } else {
1057 return(EINVAL);
1058 }
1059
1060 addr = preginfo.prp_prinfo.pri_address + preginfo.prp_prinfo.pri_size;
1061 } while (1);
1062
1063 error = copyout(&preginfo, buffer, sizeof(struct proc_regionwithpathinfo));
1064 if (error == 0)
1065 *retval = sizeof(struct proc_regionwithpathinfo);
1066 return(error);
1067 }
1068
1069 /*
1070 * Path is relative to current process directory; may different from current
1071 * thread directory.
1072 */
1073 int
1074 proc_pidvnodepathinfo(proc_t p, __unused uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
1075 {
1076 struct proc_vnodepathinfo pvninfo;
1077 int error = 0;
1078 vnode_t vncdirvp = NULLVP;
1079 uint32_t vncdirid=0;
1080 vnode_t vnrdirvp = NULLVP;
1081 uint32_t vnrdirid=0;
1082 int count;
1083
1084 bzero(&pvninfo, sizeof(struct proc_vnodepathinfo));
1085
1086 proc_fdlock(p);
1087 if (p->p_fd->fd_cdir) {
1088 vncdirvp = p->p_fd->fd_cdir;
1089 vncdirid = p->p_fd->fd_cdir->v_id;
1090 }
1091 if (p->p_fd->fd_rdir) {
1092 vnrdirvp = p->p_fd->fd_rdir;
1093 vnrdirid = p->p_fd->fd_rdir->v_id;
1094 }
1095 proc_fdunlock(p);
1096
1097 if (vncdirvp != NULLVP) {
1098 if ((error = vnode_getwithvid(vncdirvp, vncdirid)) == 0) {
1099 /* FILL THE VNODEINFO */
1100 error = fill_vnodeinfo(vncdirvp, &pvninfo.pvi_cdir.vip_vi);
1101 if ( error == 0) {
1102 count = MAXPATHLEN;
1103 vn_getpath(vncdirvp, &pvninfo.pvi_cdir.vip_path[0], &count);
1104 pvninfo.pvi_cdir.vip_path[MAXPATHLEN-1] = 0;
1105 }
1106 vnode_put(vncdirvp);
1107 } else {
1108 goto out;
1109 }
1110 }
1111
1112 if ((error == 0) && (vnrdirvp != NULLVP)) {
1113 if ((error = vnode_getwithvid(vnrdirvp, vnrdirid)) == 0) {
1114 /* FILL THE VNODEINFO */
1115 error = fill_vnodeinfo(vnrdirvp, &pvninfo.pvi_rdir.vip_vi);
1116 if ( error == 0) {
1117 count = MAXPATHLEN;
1118 vn_getpath(vnrdirvp, &pvninfo.pvi_rdir.vip_path[0], &count);
1119 pvninfo.pvi_rdir.vip_path[MAXPATHLEN-1] = 0;
1120 }
1121 vnode_put(vnrdirvp);
1122 } else {
1123 goto out;
1124 }
1125 }
1126 if (error == 0) {
1127 error = copyout(&pvninfo, buffer, sizeof(struct proc_vnodepathinfo));
1128 if (error == 0)
1129 *retval = sizeof(struct proc_vnodepathinfo);
1130 }
1131 out:
1132 return(error);
1133 }
1134
1135 int
1136 proc_pidpathinfo(proc_t p, __unused uint64_t arg, user_addr_t buffer, uint32_t buffersize, __unused int32_t *retval)
1137 {
1138 int error;
1139 vnode_t tvp;
1140 int len = buffersize;
1141 char * buf;
1142
1143 tvp = p->p_textvp;
1144
1145 if (tvp == NULLVP)
1146 return(ESRCH);
1147
1148 buf = (char *)kalloc(buffersize);
1149 if (buf == NULL)
1150 return(ENOMEM);
1151
1152 bzero(buf, buffersize);
1153
1154 error = proc_pidpathinfo_internal(p, arg, buf, buffersize, retval);
1155 if (error == 0) {
1156 error = copyout(buf, buffer, len);
1157 }
1158 kfree(buf, buffersize);
1159 return(error);
1160 }
1161
1162 int
1163 proc_pidpathinfo_internal(proc_t p, __unused uint64_t arg, char *buf, uint32_t buffersize, __unused int32_t *retval)
1164 {
1165 int vid, error;
1166 vnode_t tvp;
1167 vnode_t nvp = NULLVP;
1168 int len = buffersize;
1169
1170 tvp = p->p_textvp;
1171
1172 if (tvp == NULLVP)
1173 return(ESRCH);
1174
1175 vid = vnode_vid(tvp);
1176 error = vnode_getwithvid(tvp, vid);
1177 if (error == 0) {
1178 error = vn_getpath_fsenter(tvp, buf, &len);
1179 vnode_put(tvp);
1180 if (error == 0) {
1181 error = vnode_lookup(buf, 0, &nvp, vfs_context_current());
1182 if ((error == 0) && ( nvp != NULLVP))
1183 vnode_put(nvp);
1184 }
1185 }
1186 return(error);
1187 }
1188
1189
1190 int
1191 proc_pidworkqueueinfo(proc_t p, struct proc_workqueueinfo *pwqinfo)
1192 {
1193 int error = 0;
1194
1195 bzero(pwqinfo, sizeof(struct proc_workqueueinfo));
1196
1197 error = fill_procworkqueue(p, pwqinfo);
1198 if (error)
1199 return(ESRCH);
1200 else
1201 return(0);
1202
1203 }
1204
1205
1206 void
1207 proc_piduniqidentifierinfo(proc_t p, struct proc_uniqidentifierinfo *p_uniqidinfo)
1208 {
1209 p_uniqidinfo->p_uniqueid = proc_uniqueid(p);
1210 proc_getexecutableuuid(p, (unsigned char *)&p_uniqidinfo->p_uuid, sizeof(p_uniqidinfo->p_uuid));
1211 p_uniqidinfo->p_puniqueid = proc_puniqueid(p);
1212 p_uniqidinfo->p_reserve2 = 0;
1213 p_uniqidinfo->p_reserve3 = 0;
1214 p_uniqidinfo->p_reserve4 = 0;
1215 }
1216
1217
1218 static int
1219 proc_piduuidinfo(pid_t pid, uuid_t uuid_buf, uint32_t buffersize)
1220 {
1221 struct proc * p = PROC_NULL;
1222 int zombref = 0;
1223
1224 if (buffersize < sizeof(uuid_t))
1225 return EINVAL;
1226
1227 if ((p = proc_find(pid)) == PROC_NULL) {
1228 p = proc_find_zombref(pid);
1229 zombref = 1;
1230 }
1231 if (p == PROC_NULL) {
1232 return ESRCH;
1233 }
1234
1235 proc_getexecutableuuid(p, (unsigned char *)uuid_buf, buffersize);
1236
1237 if (zombref)
1238 proc_drop_zombref(p);
1239 else
1240 proc_rele(p);
1241
1242 return 0;
1243 }
1244
1245 /*
1246 * Function to get the uuid and pid of the originator of the voucher.
1247 */
1248 int
1249 proc_pidoriginatorpid_uuid(uuid_t uuid, uint32_t buffersize, pid_t *pid)
1250 {
1251 pid_t originator_pid;
1252 kern_return_t kr;
1253 int error;
1254
1255 /*
1256 * Get the current voucher origin pid. The pid returned here
1257 * might not be valid or may have been recycled.
1258 */
1259 kr = thread_get_current_voucher_origin_pid(&originator_pid);
1260 /* If errors, convert errors to appropriate format */
1261 if (kr) {
1262 if (kr == KERN_INVALID_TASK)
1263 error = ESRCH;
1264 else if (kr == KERN_INVALID_VALUE)
1265 error = ENOATTR;
1266 else
1267 error = EINVAL;
1268 return error;
1269 }
1270
1271 *pid = originator_pid;
1272 error = proc_piduuidinfo(originator_pid, uuid, buffersize);
1273 return error;
1274 }
1275
1276 /*
1277 * Function to get the uuid of the originator of the voucher.
1278 */
1279 int
1280 proc_pidoriginatoruuid(uuid_t uuid, uint32_t buffersize)
1281 {
1282 pid_t originator_pid;
1283 return (proc_pidoriginatorpid_uuid(uuid, buffersize, &originator_pid));
1284 }
1285
1286 /***************************** proc_pidoriginatorinfo ***************************/
1287
1288 int
1289 proc_pidoriginatorinfo(int pid, int flavor, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
1290 {
1291 int error = ENOTSUP;
1292 uint32_t size;
1293
1294 switch (flavor) {
1295 case PROC_PIDORIGINATOR_UUID:
1296 size = PROC_PIDORIGINATOR_UUID_SIZE;
1297 break;
1298 case PROC_PIDORIGINATOR_BGSTATE:
1299 size = PROC_PIDORIGINATOR_BGSTATE_SIZE;
1300 break;
1301 case PROC_PIDORIGINATOR_PID_UUID:
1302 size = PROC_PIDORIGINATOR_PID_UUID_SIZE;
1303 break;
1304 default:
1305 return(EINVAL);
1306 }
1307
1308 if (buffersize < size)
1309 return(ENOMEM);
1310
1311 if (pid != 0 && pid != proc_selfpid())
1312 return (EINVAL);
1313
1314 switch (flavor) {
1315 case PROC_PIDORIGINATOR_UUID: {
1316 uuid_t uuid;
1317
1318 error = proc_pidoriginatoruuid(uuid, sizeof(uuid));
1319 if (error != 0)
1320 goto out;
1321
1322 error = copyout(uuid, buffer, size);
1323 if (error == 0)
1324 *retval = size;
1325 }
1326 break;
1327
1328 case PROC_PIDORIGINATOR_PID_UUID: {
1329 struct proc_originatorinfo originator_info;
1330 bzero(&originator_info, sizeof(originator_info));
1331
1332 error = proc_pidoriginatorpid_uuid(originator_info.originator_uuid,
1333 sizeof(uuid_t), &originator_info.originator_pid);
1334 if (error != 0)
1335 goto out;
1336
1337 error = copyout(&originator_info, buffer, size);
1338 if (error == 0)
1339 *retval = size;
1340 }
1341 break;
1342
1343 case PROC_PIDORIGINATOR_BGSTATE: {
1344 uint32_t is_backgrounded;
1345 error = proc_get_originatorbgstate(&is_backgrounded);
1346 if (error)
1347 goto out;
1348
1349 error = copyout(&is_backgrounded, buffer, size);
1350 if (error == 0)
1351 *retval = size;
1352 }
1353 break;
1354
1355 default:
1356 error = ENOTSUP;
1357 }
1358 out:
1359 return error;
1360 }
1361
1362 /***************************** proc_listcoalitions ***************************/
1363 int proc_listcoalitions(int flavor, int type, user_addr_t buffer,
1364 uint32_t buffersize, int32_t *retval)
1365 {
1366 #if CONFIG_COALITIONS
1367 int error = ENOTSUP;
1368 int coal_type;
1369 uint32_t elem_size;
1370 void *coalinfo = NULL;
1371 uint32_t k_buffersize = 0, copyout_sz = 0;
1372 int ncoals = 0, ncoals_ = 0;
1373
1374 /* struct procinfo_coalinfo; */
1375
1376 switch (flavor) {
1377 case LISTCOALITIONS_ALL_COALS:
1378 elem_size = LISTCOALITIONS_ALL_COALS_SIZE;
1379 coal_type = -1;
1380 break;
1381 case LISTCOALITIONS_SINGLE_TYPE:
1382 elem_size = LISTCOALITIONS_SINGLE_TYPE_SIZE;
1383 coal_type = type;
1384 break;
1385 default:
1386 return EINVAL;
1387 }
1388
1389 /* find the total number of coalitions */
1390 ncoals = coalitions_get_list(coal_type, NULL, 0);
1391
1392 if (ncoals == 0 || buffer == 0 || buffersize == 0) {
1393 /*
1394 * user just wants buffer size
1395 * or there are no coalitions
1396 */
1397 error = 0;
1398 *retval = (int)(ncoals * elem_size);
1399 goto out;
1400 }
1401
1402 k_buffersize = ncoals * elem_size;
1403 coalinfo = kalloc((vm_size_t)k_buffersize);
1404 if (!coalinfo) {
1405 error = ENOMEM;
1406 goto out;
1407 }
1408 bzero(coalinfo, k_buffersize);
1409
1410 switch (flavor) {
1411 case LISTCOALITIONS_ALL_COALS:
1412 case LISTCOALITIONS_SINGLE_TYPE:
1413 ncoals_ = coalitions_get_list(coal_type, coalinfo, ncoals);
1414 break;
1415 default:
1416 panic("memory corruption?!");
1417 }
1418
1419 if (ncoals_ == 0) {
1420 /* all the coalitions disappeared... weird but valid */
1421 error = 0;
1422 *retval = 0;
1423 goto out;
1424 }
1425
1426 /*
1427 * Some coalitions may have disappeared between our initial check,
1428 * and the the actual list acquisition.
1429 * Only copy out what we really need.
1430 */
1431 copyout_sz = k_buffersize;
1432 if (ncoals_ < ncoals)
1433 copyout_sz = ncoals_ * elem_size;
1434
1435 /*
1436 * copy the list up to user space
1437 * (we're guaranteed to have a non-null pointer/size here)
1438 */
1439 error = copyout(coalinfo, buffer,
1440 copyout_sz < buffersize ? copyout_sz : buffersize);
1441
1442 if (error == 0)
1443 *retval = (int)copyout_sz;
1444
1445 out:
1446 if (coalinfo)
1447 kfree(coalinfo, k_buffersize);
1448
1449 return error;
1450 #else
1451 /* no coalition support */
1452 (void)flavor;
1453 (void)type;
1454 (void)buffer;
1455 (void)buffersize;
1456 (void)retval;
1457 return ENOTSUP;
1458 #endif
1459 }
1460
1461
1462 /*************************** proc_can_use_forgeound_hw **************************/
1463 int proc_can_use_foreground_hw(int pid, user_addr_t u_reason, uint32_t reasonsize, int32_t *retval)
1464 {
1465 proc_t p = PROC_NULL;
1466 int error = 0;
1467 uint32_t reason = PROC_FGHW_ERROR;
1468 uint32_t isBG = 0;
1469 task_t task = TASK_NULL;
1470 #if CONFIG_COALITIONS
1471 coalition_t coal = COALITION_NULL;
1472 #endif
1473
1474 *retval = 0;
1475
1476 if (pid <= 0) {
1477 error = EINVAL;
1478 reason = PROC_FGHW_ERROR;
1479 goto out;
1480 }
1481
1482 p = proc_find(pid);
1483 if (p == PROC_NULL) {
1484 error = ESRCH;
1485 reason = PROC_FGHW_ERROR;
1486 goto out;
1487 }
1488
1489 #if CONFIG_COALITIONS
1490 if (p != current_proc() &&
1491 !kauth_cred_issuser(kauth_cred_get())) {
1492 error = EPERM;
1493 reason = PROC_FGHW_ERROR;
1494 goto out;
1495 }
1496
1497 task = p->task;
1498 task_reference(task);
1499 if (coalition_is_leader(task, COALITION_TYPE_JETSAM, &coal) == FALSE) {
1500 /* current task is not a coalition leader: find the leader */
1501 task_deallocate(task);
1502 task = coalition_get_leader(coal);
1503 }
1504
1505 if (task != TASK_NULL) {
1506 /*
1507 * If task is non-null, then it is the coalition leader of the
1508 * current process' coalition. This could be the same task as
1509 * the current_task, and that's OK.
1510 */
1511 uint32_t flags = 0;
1512 int role;
1513
1514 proc_get_darwinbgstate(task, &flags);
1515 if ((flags & PROC_FLAG_APPLICATION) != PROC_FLAG_APPLICATION) {
1516 /*
1517 * Coalition leader is not an application, continue
1518 * searching for other ways this task could gain
1519 * access to HW
1520 */
1521 reason = PROC_FGHW_DAEMON_LEADER;
1522 goto no_leader;
1523 }
1524
1525 if (proc_get_effective_task_policy(task, TASK_POLICY_DARWIN_BG)) {
1526 /*
1527 * If the leader of the current process' coalition has
1528 * been marked as DARWIN_BG, then it definitely should
1529 * not be using foreground hardware resources.
1530 */
1531 reason = PROC_FGHW_LEADER_BACKGROUND;
1532 goto out;
1533 }
1534
1535 role = proc_get_effective_task_policy(task, TASK_POLICY_ROLE);
1536 switch (role) {
1537 case TASK_FOREGROUND_APPLICATION: /* DARWIN_ROLE_UI_FOCAL */
1538 case TASK_BACKGROUND_APPLICATION: /* DARWIN_ROLE_UI */
1539 /*
1540 * The leader of this coalition is a focal, UI app:
1541 * access granted
1542 * TODO: should extensions/plugins be allowed to use
1543 * this hardware?
1544 */
1545 *retval = 1;
1546 reason = PROC_FGHW_OK;
1547 goto out;
1548 case TASK_DEFAULT_APPLICATION: /* DARWIN_ROLE_UI_NON_FOCAL */
1549 case TASK_NONUI_APPLICATION: /* DARWIN_ROLE_NON_UI */
1550 case TASK_THROTTLE_APPLICATION:
1551 case TASK_UNSPECIFIED:
1552 default:
1553 /* non-focal, non-ui apps don't get access */
1554 reason = PROC_FGHW_LEADER_NONUI;
1555 goto out;
1556 }
1557 }
1558
1559 no_leader:
1560 if (task != TASK_NULL) {
1561 task_deallocate(task);
1562 task = TASK_NULL;
1563 }
1564 #endif /* CONFIG_COALITIONS */
1565
1566 /*
1567 * There is no reasonable semantic to investigate the currently
1568 * adopted voucher of an arbitrary thread in a non-current process.
1569 * We return '0'
1570 */
1571 if (p != current_proc()) {
1572 error = EINVAL;
1573 goto out;
1574 }
1575
1576 /*
1577 * In the absence of coalitions, fall back to a voucher-based lookup
1578 * where a daemon can used foreground HW if it's operating on behalf
1579 * of a foreground application.
1580 * NOTE: this is equivalent to a call to
1581 * proc_pidoriginatorinfo(PROC_PIDORIGINATOR_BGSTATE, &isBG, sizeof(isBG))
1582 */
1583 isBG = 1;
1584 error = proc_get_originatorbgstate(&isBG);
1585 switch (error) {
1586 case 0:
1587 break;
1588 case ESRCH:
1589 reason = PROC_FGHW_NO_ORIGINATOR;
1590 error = 0;
1591 goto out;
1592 case ENOATTR:
1593 reason = PROC_FGHW_NO_VOUCHER_ATTR;
1594 error = 0;
1595 goto out;
1596 case EINVAL:
1597 reason = PROC_FGHW_DAEMON_NO_VOUCHER;
1598 error = 0;
1599 goto out;
1600 default:
1601 /* some other error occurred: report that to the caller */
1602 reason = PROC_FGHW_VOUCHER_ERROR;
1603 goto out;
1604 }
1605
1606 if (isBG) {
1607 reason = PROC_FGHW_ORIGINATOR_BACKGROUND;
1608 error = 0;
1609 } else {
1610 /*
1611 * The process itself is either a foreground app, or has
1612 * adopted a voucher originating from an app that's still in
1613 * the foreground
1614 */
1615 reason = PROC_FGHW_DAEMON_OK;
1616 *retval = 1;
1617 }
1618
1619 out:
1620 if (task != TASK_NULL)
1621 task_deallocate(task);
1622 if (p != PROC_NULL)
1623 proc_rele(p);
1624 if (reasonsize >= sizeof(reason) && u_reason != (user_addr_t)0)
1625 (void)copyout(&reason, u_reason, sizeof(reason));
1626 return error;
1627 }
1628
1629
1630 /********************************** proc_pidinfo ********************************/
1631
1632
1633 int
1634 proc_pidinfo(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
1635 {
1636 struct proc * p = PROC_NULL;
1637 int error = ENOTSUP;
1638 int gotref = 0;
1639 int findzomb = 0;
1640 int shortversion = 0;
1641 uint32_t size;
1642 int zombie = 0;
1643 int thuniqueid = 0;
1644 int uniqidversion = 0;
1645 boolean_t check_same_user;
1646
1647 switch (flavor) {
1648 case PROC_PIDLISTFDS:
1649 size = PROC_PIDLISTFD_SIZE;
1650 if (buffer == (user_addr_t)0)
1651 size = 0;
1652 break;
1653 case PROC_PIDTBSDINFO:
1654 size = PROC_PIDTBSDINFO_SIZE;
1655 break;
1656 case PROC_PIDTASKINFO:
1657 size = PROC_PIDTASKINFO_SIZE;
1658 break;
1659 case PROC_PIDTASKALLINFO:
1660 size = PROC_PIDTASKALLINFO_SIZE;
1661 break;
1662 case PROC_PIDTHREADINFO:
1663 size = PROC_PIDTHREADINFO_SIZE;
1664 break;
1665 case PROC_PIDLISTTHREADS:
1666 size = PROC_PIDLISTTHREADS_SIZE;
1667 break;
1668 case PROC_PIDREGIONINFO:
1669 size = PROC_PIDREGIONINFO_SIZE;
1670 break;
1671 case PROC_PIDREGIONPATHINFO:
1672 size = PROC_PIDREGIONPATHINFO_SIZE;
1673 break;
1674 case PROC_PIDVNODEPATHINFO:
1675 size = PROC_PIDVNODEPATHINFO_SIZE;
1676 break;
1677 case PROC_PIDTHREADPATHINFO:
1678 size = PROC_PIDTHREADPATHINFO_SIZE;
1679 break;
1680 case PROC_PIDPATHINFO:
1681 size = MAXPATHLEN;
1682 break;
1683 case PROC_PIDWORKQUEUEINFO:
1684 /* kernel does not have workq info */
1685 if (pid == 0)
1686 return(EINVAL);
1687 else
1688 size = PROC_PIDWORKQUEUEINFO_SIZE;
1689 break;
1690 case PROC_PIDT_SHORTBSDINFO:
1691 size = PROC_PIDT_SHORTBSDINFO_SIZE;
1692 break;
1693 case PROC_PIDLISTFILEPORTS:
1694 size = PROC_PIDLISTFILEPORTS_SIZE;
1695 if (buffer == (user_addr_t)0)
1696 size = 0;
1697 break;
1698 case PROC_PIDTHREADID64INFO:
1699 size = PROC_PIDTHREADID64INFO_SIZE;
1700 break;
1701 case PROC_PIDUNIQIDENTIFIERINFO:
1702 size = PROC_PIDUNIQIDENTIFIERINFO_SIZE;
1703 break;
1704 case PROC_PIDT_BSDINFOWITHUNIQID:
1705 size = PROC_PIDT_BSDINFOWITHUNIQID_SIZE;
1706 break;
1707 case PROC_PIDARCHINFO:
1708 size = PROC_PIDARCHINFO_SIZE;
1709 break;
1710 case PROC_PIDCOALITIONINFO:
1711 size = PROC_PIDCOALITIONINFO_SIZE;
1712 break;
1713 case PROC_PIDNOTEEXIT:
1714 /*
1715 * Set findzomb explicitly because arg passed
1716 * in is used as note exit status bits.
1717 */
1718 size = PROC_PIDNOTEEXIT_SIZE;
1719 findzomb = 1;
1720 break;
1721 case PROC_PIDEXITREASONINFO:
1722 size = PROC_PIDEXITREASONINFO_SIZE;
1723 findzomb = 1;
1724 break;
1725 case PROC_PIDEXITREASONBASICINFO:
1726 size = PROC_PIDEXITREASONBASICINFOSIZE;
1727 findzomb = 1;
1728 break;
1729 case PROC_PIDREGIONPATHINFO2:
1730 size = PROC_PIDREGIONPATHINFO2_SIZE;
1731 break;
1732 case PROC_PIDREGIONPATHINFO3:
1733 size = PROC_PIDREGIONPATHINFO3_SIZE;
1734 break;
1735 default:
1736 return(EINVAL);
1737 }
1738
1739 if (buffersize < size)
1740 return(ENOMEM);
1741
1742 if ((flavor == PROC_PIDPATHINFO) && (buffersize > PROC_PIDPATHINFO_MAXSIZE)) {
1743 return(EOVERFLOW);
1744 }
1745
1746 /* Check if we need to look for zombies */
1747 if ((flavor == PROC_PIDTBSDINFO) || (flavor == PROC_PIDT_SHORTBSDINFO) || (flavor == PROC_PIDT_BSDINFOWITHUNIQID)
1748 || (flavor == PROC_PIDUNIQIDENTIFIERINFO)) {
1749 if (arg)
1750 findzomb = 1;
1751 }
1752
1753 if ((p = proc_find(pid)) == PROC_NULL) {
1754 if (findzomb)
1755 p = proc_find_zombref(pid);
1756 if (p == PROC_NULL) {
1757 error = ESRCH;
1758 goto out;
1759 }
1760 zombie = 1;
1761 } else {
1762 gotref = 1;
1763 }
1764
1765 /* Certain operations don't require privileges */
1766 switch (flavor) {
1767 case PROC_PIDT_SHORTBSDINFO:
1768 case PROC_PIDUNIQIDENTIFIERINFO:
1769 case PROC_PIDPATHINFO:
1770 case PROC_PIDCOALITIONINFO:
1771 check_same_user = NO_CHECK_SAME_USER;
1772 break;
1773 default:
1774 check_same_user = CHECK_SAME_USER;
1775 break;
1776 }
1777
1778 /* Do we have permission to look into this? */
1779 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDINFO, flavor, check_same_user)))
1780 goto out;
1781
1782 switch (flavor) {
1783 case PROC_PIDLISTFDS: {
1784 error = proc_pidfdlist(p, buffer, buffersize, retval);
1785 }
1786 break;
1787
1788 case PROC_PIDUNIQIDENTIFIERINFO: {
1789 struct proc_uniqidentifierinfo p_uniqidinfo;
1790 bzero(&p_uniqidinfo, sizeof(p_uniqidinfo));
1791 proc_piduniqidentifierinfo(p, &p_uniqidinfo);
1792 error = copyout(&p_uniqidinfo, buffer, sizeof(struct proc_uniqidentifierinfo));
1793 if (error == 0)
1794 *retval = sizeof(struct proc_uniqidentifierinfo);
1795 }
1796 break;
1797
1798 case PROC_PIDT_SHORTBSDINFO:
1799 shortversion = 1;
1800 case PROC_PIDT_BSDINFOWITHUNIQID:
1801 case PROC_PIDTBSDINFO: {
1802 struct proc_bsdinfo pbsd;
1803 struct proc_bsdshortinfo pbsd_short;
1804 struct proc_bsdinfowithuniqid pbsd_uniqid;
1805
1806 if (flavor == PROC_PIDT_BSDINFOWITHUNIQID)
1807 uniqidversion = 1;
1808
1809 if (shortversion != 0) {
1810 error = proc_pidshortbsdinfo(p, &pbsd_short, zombie);
1811 } else {
1812 error = proc_pidbsdinfo(p, &pbsd, zombie);
1813 if (uniqidversion != 0) {
1814 bzero(&pbsd_uniqid, sizeof(pbsd_uniqid));
1815 proc_piduniqidentifierinfo(p, &pbsd_uniqid.p_uniqidentifier);
1816 pbsd_uniqid.pbsd = pbsd;
1817 }
1818 }
1819
1820 if (error == 0) {
1821 if (shortversion != 0) {
1822 error = copyout(&pbsd_short, buffer, sizeof(struct proc_bsdshortinfo));
1823 if (error == 0)
1824 *retval = sizeof(struct proc_bsdshortinfo);
1825 } else if (uniqidversion != 0) {
1826 error = copyout(&pbsd_uniqid, buffer, sizeof(struct proc_bsdinfowithuniqid));
1827 if (error == 0)
1828 *retval = sizeof(struct proc_bsdinfowithuniqid);
1829 } else {
1830 error = copyout(&pbsd, buffer, sizeof(struct proc_bsdinfo));
1831 if (error == 0)
1832 *retval = sizeof(struct proc_bsdinfo);
1833 }
1834 }
1835 }
1836 break;
1837
1838 case PROC_PIDTASKINFO: {
1839 struct proc_taskinfo ptinfo;
1840
1841 error = proc_pidtaskinfo(p, &ptinfo);
1842 if (error == 0) {
1843 error = copyout(&ptinfo, buffer, sizeof(struct proc_taskinfo));
1844 if (error == 0)
1845 *retval = sizeof(struct proc_taskinfo);
1846 }
1847 }
1848 break;
1849
1850 case PROC_PIDTASKALLINFO: {
1851 struct proc_taskallinfo pall;
1852 bzero(&pall, sizeof(pall));
1853 error = proc_pidbsdinfo(p, &pall.pbsd, 0);
1854 error = proc_pidtaskinfo(p, &pall.ptinfo);
1855 if (error == 0) {
1856 error = copyout(&pall, buffer, sizeof(struct proc_taskallinfo));
1857 if (error == 0)
1858 *retval = sizeof(struct proc_taskallinfo);
1859 }
1860 }
1861 break;
1862
1863 case PROC_PIDTHREADID64INFO:
1864 thuniqueid = 1;
1865 case PROC_PIDTHREADINFO:{
1866 struct proc_threadinfo pthinfo;
1867
1868 error = proc_pidthreadinfo(p, arg, thuniqueid, &pthinfo);
1869 if (error == 0) {
1870 error = copyout(&pthinfo, buffer, sizeof(struct proc_threadinfo));
1871 if (error == 0)
1872 *retval = sizeof(struct proc_threadinfo);
1873 }
1874 }
1875 break;
1876
1877 case PROC_PIDLISTTHREADS:{
1878 error = proc_pidlistthreads(p, buffer, buffersize, retval);
1879 }
1880 break;
1881
1882 case PROC_PIDREGIONINFO:{
1883 error = proc_pidregioninfo(p, arg, buffer, buffersize, retval);
1884 }
1885 break;
1886
1887
1888 case PROC_PIDREGIONPATHINFO:{
1889 error = proc_pidregionpathinfo(p, arg, buffer, buffersize, retval);
1890 }
1891 break;
1892
1893 case PROC_PIDREGIONPATHINFO2:{
1894 error = proc_pidregionpathinfo2(p, arg, buffer, buffersize, retval);
1895 }
1896 break;
1897
1898 case PROC_PIDREGIONPATHINFO3:{
1899 error = proc_pidregionpathinfo3(p, arg, buffer, buffersize, retval);
1900 }
1901 break;
1902
1903 case PROC_PIDVNODEPATHINFO:{
1904 error = proc_pidvnodepathinfo(p, arg, buffer, buffersize, retval);
1905 }
1906 break;
1907
1908
1909 case PROC_PIDTHREADPATHINFO:{
1910 struct proc_threadwithpathinfo pinfo;
1911
1912 error = proc_pidthreadpathinfo(p, arg, &pinfo);
1913 if (error == 0) {
1914 error = copyout((caddr_t)&pinfo, buffer, sizeof(struct proc_threadwithpathinfo));
1915 if (error == 0)
1916 *retval = sizeof(struct proc_threadwithpathinfo);
1917 }
1918 }
1919 break;
1920
1921 case PROC_PIDPATHINFO: {
1922 error = proc_pidpathinfo(p, arg, buffer, buffersize, retval);
1923 }
1924 break;
1925
1926
1927 case PROC_PIDWORKQUEUEINFO:{
1928 struct proc_workqueueinfo pwqinfo;
1929
1930 error = proc_pidworkqueueinfo(p, &pwqinfo);
1931 if (error == 0) {
1932 error = copyout(&pwqinfo, buffer, sizeof(struct proc_workqueueinfo));
1933 if (error == 0)
1934 *retval = sizeof(struct proc_workqueueinfo);
1935 }
1936 }
1937 break;
1938
1939 case PROC_PIDLISTFILEPORTS: {
1940 error = proc_pidfileportlist(p, buffer, buffersize, retval);
1941 }
1942 break;
1943
1944 case PROC_PIDARCHINFO: {
1945 struct proc_archinfo pai;
1946 bzero(&pai, sizeof(pai));
1947 proc_archinfo(p, &pai);
1948 error = copyout(&pai, buffer, sizeof(struct proc_archinfo));
1949 if (error == 0) {
1950 *retval = sizeof(struct proc_archinfo);
1951 }
1952 }
1953 break;
1954
1955 case PROC_PIDCOALITIONINFO: {
1956 struct proc_pidcoalitioninfo pci;
1957 proc_pidcoalitioninfo(p, &pci);
1958 error = copyout(&pci, buffer, sizeof(struct proc_pidcoalitioninfo));
1959 if (error == 0) {
1960 *retval = sizeof(struct proc_pidcoalitioninfo);
1961 }
1962 }
1963 break;
1964
1965 case PROC_PIDNOTEEXIT: {
1966 uint32_t data;
1967 error = proc_pidnoteexit(p, arg, &data);
1968 if (error == 0) {
1969 error = copyout(&data, buffer, sizeof(data));
1970 if (error == 0) {
1971 *retval = sizeof(data);
1972 }
1973 }
1974 }
1975 break;
1976
1977 case PROC_PIDEXITREASONINFO: {
1978 struct proc_exitreasoninfo eri;
1979
1980 error = copyin(buffer, &eri, sizeof(eri));
1981 if (error != 0) {
1982 break;
1983 }
1984
1985 error = proc_pidexitreasoninfo(p, &eri, NULL);
1986 if (error == 0) {
1987 error = copyout(&eri, buffer, sizeof(eri));
1988 if (error == 0) {
1989 *retval = sizeof(eri);
1990 }
1991 }
1992 }
1993 break;
1994
1995 case PROC_PIDEXITREASONBASICINFO: {
1996 struct proc_exitreasonbasicinfo beri;
1997
1998 bzero(&beri, sizeof(struct proc_exitreasonbasicinfo));
1999
2000 error = proc_pidexitreasoninfo(p, NULL, &beri);
2001 if (error == 0) {
2002 error = copyout(&beri, buffer, sizeof(beri));
2003 if (error == 0) {
2004 *retval = sizeof(beri);
2005 }
2006 }
2007 }
2008 break;
2009
2010 default:
2011 error = ENOTSUP;
2012 }
2013
2014 out:
2015 if (gotref)
2016 proc_rele(p);
2017 else if (zombie)
2018 proc_drop_zombref(p);
2019 return(error);
2020 }
2021
2022
2023 int
2024 pid_vnodeinfo(vnode_t vp, uint32_t vid, struct fileproc * fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2025 {
2026 struct vnode_fdinfo vfi;
2027 int error= 0;
2028
2029 if ((error = vnode_getwithvid(vp, vid)) != 0) {
2030 return(error);
2031 }
2032 bzero(&vfi, sizeof(struct vnode_fdinfo));
2033 fill_fileinfo(fp, proc, fd, &vfi.pfi);
2034 error = fill_vnodeinfo(vp, &vfi.pvi);
2035 vnode_put(vp);
2036 if (error == 0) {
2037 error = copyout((caddr_t)&vfi, buffer, sizeof(struct vnode_fdinfo));
2038 if (error == 0)
2039 *retval = sizeof(struct vnode_fdinfo);
2040 }
2041 return(error);
2042 }
2043
2044 int
2045 pid_vnodeinfopath(vnode_t vp, uint32_t vid, struct fileproc * fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2046 {
2047 struct vnode_fdinfowithpath vfip;
2048 int count, error= 0;
2049
2050 if ((error = vnode_getwithvid(vp, vid)) != 0) {
2051 return(error);
2052 }
2053 bzero(&vfip, sizeof(struct vnode_fdinfowithpath));
2054 fill_fileinfo(fp, proc, fd, &vfip.pfi);
2055 error = fill_vnodeinfo(vp, &vfip.pvip.vip_vi) ;
2056 if (error == 0) {
2057 count = MAXPATHLEN;
2058 vn_getpath(vp, &vfip.pvip.vip_path[0], &count);
2059 vfip.pvip.vip_path[MAXPATHLEN-1] = 0;
2060 vnode_put(vp);
2061 error = copyout((caddr_t)&vfip, buffer, sizeof(struct vnode_fdinfowithpath));
2062 if (error == 0)
2063 *retval = sizeof(struct vnode_fdinfowithpath);
2064 } else
2065 vnode_put(vp);
2066 return(error);
2067 }
2068
2069 void
2070 fill_fileinfo(struct fileproc * fp, proc_t proc, int fd, struct proc_fileinfo * fproc)
2071 {
2072 fproc->fi_openflags = fp->f_fglob->fg_flag;
2073 fproc->fi_status = 0;
2074 fproc->fi_offset = fp->f_fglob->fg_offset;
2075 fproc->fi_type = FILEGLOB_DTYPE(fp->f_fglob);
2076 if (fp->f_fglob->fg_count > 1)
2077 fproc->fi_status |= PROC_FP_SHARED;
2078 if (proc != PROC_NULL) {
2079 if ((FDFLAGS_GET(proc, fd) & UF_EXCLOSE) != 0)
2080 fproc->fi_status |= PROC_FP_CLEXEC;
2081 if ((FDFLAGS_GET(proc, fd) & UF_FORKCLOSE) != 0)
2082 fproc->fi_status |= PROC_FP_CLFORK;
2083 }
2084 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
2085 fproc->fi_status |= PROC_FP_GUARDED;
2086 fproc->fi_guardflags = 0;
2087 if (fp_isguarded(fp, GUARD_CLOSE))
2088 fproc->fi_guardflags |= PROC_FI_GUARD_CLOSE;
2089 if (fp_isguarded(fp, GUARD_DUP))
2090 fproc->fi_guardflags |= PROC_FI_GUARD_DUP;
2091 if (fp_isguarded(fp, GUARD_SOCKET_IPC))
2092 fproc->fi_guardflags |= PROC_FI_GUARD_SOCKET_IPC;
2093 if (fp_isguarded(fp, GUARD_FILEPORT))
2094 fproc->fi_guardflags |= PROC_FI_GUARD_FILEPORT;
2095 }
2096 }
2097
2098
2099
2100 int
2101 fill_vnodeinfo(vnode_t vp, struct vnode_info *vinfo)
2102 {
2103 vfs_context_t context;
2104 struct stat64 sb;
2105 int error = 0;
2106
2107 bzero(&sb, sizeof(struct stat64));
2108 context = vfs_context_create((vfs_context_t)0);
2109 error = vn_stat(vp, &sb, NULL, 1, context);
2110 (void)vfs_context_rele(context);
2111
2112 munge_vinfo_stat(&sb, &vinfo->vi_stat);
2113
2114 if (error != 0)
2115 goto out;
2116
2117 if (vp->v_mount != dead_mountp) {
2118 vinfo->vi_fsid = vp->v_mount->mnt_vfsstat.f_fsid;
2119 } else {
2120 vinfo->vi_fsid.val[0] = 0;
2121 vinfo->vi_fsid.val[1] = 0;
2122 }
2123 vinfo->vi_type = vp->v_type;
2124 out:
2125 return(error);
2126 }
2127
2128 int
2129 pid_socketinfo(socket_t so, struct fileproc *fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2130 {
2131 #if SOCKETS
2132 struct socket_fdinfo s;
2133 int error = 0;
2134
2135 bzero(&s, sizeof(struct socket_fdinfo));
2136 fill_fileinfo(fp, proc, fd, &s.pfi);
2137 if ((error = fill_socketinfo(so, &s.psi)) == 0) {
2138 if ((error = copyout(&s, buffer, sizeof(struct socket_fdinfo))) == 0)
2139 *retval = sizeof(struct socket_fdinfo);
2140 }
2141 return (error);
2142 #else
2143 #pragma unused(so, fp, proc, fd, buffer)
2144 *retval = 0;
2145 return (ENOTSUP);
2146 #endif
2147 }
2148
2149 int
2150 pid_pseminfo(struct psemnode *psem, struct fileproc *fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2151 {
2152 struct psem_fdinfo pseminfo;
2153 int error = 0;
2154
2155 bzero(&pseminfo, sizeof(struct psem_fdinfo));
2156 fill_fileinfo(fp, proc, fd, &pseminfo.pfi);
2157
2158 if ((error = fill_pseminfo(psem, &pseminfo.pseminfo)) == 0) {
2159 if ((error = copyout(&pseminfo, buffer, sizeof(struct psem_fdinfo))) == 0)
2160 *retval = sizeof(struct psem_fdinfo);
2161 }
2162
2163 return(error);
2164 }
2165
2166 int
2167 pid_pshminfo(struct pshmnode *pshm, struct fileproc *fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2168 {
2169 struct pshm_fdinfo pshminfo;
2170 int error = 0;
2171
2172 bzero(&pshminfo, sizeof(struct pshm_fdinfo));
2173 fill_fileinfo(fp, proc, fd, &pshminfo.pfi);
2174
2175 if ((error = fill_pshminfo(pshm, &pshminfo.pshminfo)) == 0) {
2176 if ((error = copyout(&pshminfo, buffer, sizeof(struct pshm_fdinfo))) == 0)
2177 *retval = sizeof(struct pshm_fdinfo);
2178 }
2179
2180 return(error);
2181 }
2182
2183 int
2184 pid_pipeinfo(struct pipe * p, struct fileproc *fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2185 {
2186 struct pipe_fdinfo pipeinfo;
2187 int error = 0;
2188
2189 bzero(&pipeinfo, sizeof(struct pipe_fdinfo));
2190 fill_fileinfo(fp, proc, fd, &pipeinfo.pfi);
2191 if ((error = fill_pipeinfo(p, &pipeinfo.pipeinfo)) == 0) {
2192 if ((error = copyout(&pipeinfo, buffer, sizeof(struct pipe_fdinfo))) == 0)
2193 *retval = sizeof(struct pipe_fdinfo);
2194 }
2195
2196 return(error);
2197 }
2198
2199 int
2200 pid_kqueueinfo(struct kqueue * kq, struct fileproc *fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2201 {
2202 struct kqueue_fdinfo kqinfo;
2203 int error = 0;
2204
2205 bzero(&kqinfo, sizeof(struct kqueue_fdinfo));
2206
2207 /* not all kq's are associated with a file (e.g. workqkq) */
2208 if (fp) {
2209 assert(fd >= 0);
2210 fill_fileinfo(fp, proc, fd, &kqinfo.pfi);
2211 }
2212
2213 if ((error = fill_kqueueinfo(kq, &kqinfo.kqueueinfo)) == 0) {
2214 if ((error = copyout(&kqinfo, buffer, sizeof(struct kqueue_fdinfo))) == 0)
2215 *retval = sizeof(struct kqueue_fdinfo);
2216 }
2217
2218 return(error);
2219 }
2220
2221 int
2222 pid_atalkinfo(__unused struct atalk * at, __unused struct fileproc *fp, __unused proc_t proc, __unused int fd, __unused user_addr_t buffer, __unused uint32_t buffersize, __unused int32_t * retval)
2223 {
2224 return ENOTSUP;
2225 }
2226
2227
2228 /************************** proc_pidfdinfo routine ***************************/
2229 int
2230 proc_pidfdinfo(int pid, int flavor, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
2231 {
2232 proc_t p;
2233 int error = ENOTSUP;
2234 struct fileproc * fp = NULL;
2235 uint32_t size;
2236
2237 switch (flavor) {
2238 case PROC_PIDFDVNODEINFO:
2239 size = PROC_PIDFDVNODEINFO_SIZE;
2240 break;
2241 case PROC_PIDFDVNODEPATHINFO:
2242 size = PROC_PIDFDVNODEPATHINFO_SIZE;
2243 break;
2244 case PROC_PIDFDSOCKETINFO:
2245 size = PROC_PIDFDSOCKETINFO_SIZE;
2246 break;
2247 case PROC_PIDFDPSEMINFO:
2248 size = PROC_PIDFDPSEMINFO_SIZE;
2249 break;
2250 case PROC_PIDFDPSHMINFO:
2251 size = PROC_PIDFDPSHMINFO_SIZE;
2252 break;
2253 case PROC_PIDFDPIPEINFO:
2254 size = PROC_PIDFDPIPEINFO_SIZE;
2255 break;
2256 case PROC_PIDFDKQUEUEINFO:
2257 size = PROC_PIDFDKQUEUEINFO_SIZE;
2258 break;
2259 case PROC_PIDFDKQUEUE_EXTINFO:
2260 size = PROC_PIDFDKQUEUE_EXTINFO_SIZE;
2261 if (buffer == (user_addr_t)0)
2262 size = 0;
2263 break;
2264 case PROC_PIDFDATALKINFO:
2265 size = PROC_PIDFDATALKINFO_SIZE;
2266 break;
2267
2268 default:
2269 return(EINVAL);
2270
2271 }
2272
2273 if (buffersize < size)
2274 return(ENOMEM);
2275
2276 if ((p = proc_find(pid)) == PROC_NULL) {
2277 error = ESRCH;
2278 goto out;
2279 }
2280
2281 /* Do we have permission to look into this? */
2282 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDFDINFO, flavor, CHECK_SAME_USER)))
2283 goto out1;
2284
2285 switch (flavor) {
2286 case PROC_PIDFDVNODEINFO: {
2287 vnode_t vp;
2288 uint32_t vid=0;
2289
2290 if ((error = fp_getfvpandvid(p, fd, &fp, &vp, &vid)) !=0) {
2291 goto out1;
2292 }
2293 /* no need to be under the fdlock */
2294 error = pid_vnodeinfo(vp, vid, fp, p, fd, buffer, buffersize, retval);
2295 }
2296 break;
2297
2298 case PROC_PIDFDVNODEPATHINFO: {
2299 vnode_t vp;
2300 uint32_t vid=0;
2301
2302 if ((error = fp_getfvpandvid(p, fd, &fp, &vp, &vid)) !=0) {
2303 goto out1;
2304 }
2305
2306 /* no need to be under the fdlock */
2307 error = pid_vnodeinfopath(vp, vid, fp, p, fd, buffer, buffersize, retval);
2308 }
2309 break;
2310
2311 case PROC_PIDFDSOCKETINFO: {
2312 socket_t so;
2313
2314 if ((error = fp_getfsock(p, fd, &fp, &so)) !=0) {
2315 goto out1;
2316 }
2317 /* no need to be under the fdlock */
2318 error = pid_socketinfo(so, fp, p, fd, buffer, buffersize, retval);
2319 }
2320 break;
2321
2322 case PROC_PIDFDPSEMINFO: {
2323 struct psemnode * psem;
2324
2325 if ((error = fp_getfpsem(p, fd, &fp, &psem)) !=0) {
2326 goto out1;
2327 }
2328 /* no need to be under the fdlock */
2329 error = pid_pseminfo(psem, fp, p, fd, buffer, buffersize, retval);
2330 }
2331 break;
2332
2333 case PROC_PIDFDPSHMINFO: {
2334 struct pshmnode * pshm;
2335
2336 if ((error = fp_getfpshm(p, fd, &fp, &pshm)) !=0) {
2337 goto out1;
2338 }
2339 /* no need to be under the fdlock */
2340 error = pid_pshminfo(pshm, fp, p, fd, buffer, buffersize, retval);
2341 }
2342 break;
2343
2344 case PROC_PIDFDPIPEINFO: {
2345 struct pipe * cpipe;
2346
2347 if ((error = fp_getfpipe(p, fd, &fp, &cpipe)) !=0) {
2348 goto out1;
2349 }
2350 /* no need to be under the fdlock */
2351 error = pid_pipeinfo(cpipe, fp, p, fd, buffer, buffersize, retval);
2352 }
2353 break;
2354
2355 case PROC_PIDFDKQUEUEINFO: {
2356 struct kqueue * kq;
2357
2358 if (fd == -1) {
2359 if ((kq = p->p_wqkqueue) == NULL) {
2360 /* wqkqueue is initialized on-demand */
2361 error = 0;
2362 break;
2363 }
2364 } else if ((error = fp_getfkq(p, fd, &fp, &kq)) != 0) {
2365 goto out1;
2366 }
2367
2368 /* no need to be under the fdlock */
2369 error = pid_kqueueinfo(kq, fp, p, fd, buffer, buffersize, retval);
2370 }
2371 break;
2372
2373 case PROC_PIDFDKQUEUE_EXTINFO: {
2374 struct kqueue * kq;
2375
2376 if (fd == -1) {
2377 if ((kq = p->p_wqkqueue) == NULL) {
2378 /* wqkqueue is initialized on-demand */
2379 error = 0;
2380 break;
2381 }
2382 } else if ((error = fp_getfkq(p, fd, &fp, &kq)) != 0) {
2383 goto out1;
2384 }
2385 error = pid_kqueue_extinfo(p, kq, buffer, buffersize, retval);
2386 }
2387 break;
2388
2389 default: {
2390 error = EINVAL;
2391 goto out1;
2392 }
2393 }
2394
2395 if (fp) {
2396 fp_drop(p, fd, fp , 0);
2397 }
2398 out1 :
2399 proc_rele(p);
2400 out:
2401 return(error);
2402 }
2403
2404 int
2405 proc_listfd_kqueue(proc_t p, int32_t *fdlist, int len)
2406 {
2407 int numfds;
2408 struct fileproc * fp;
2409 int n;
2410 int count = 0;
2411
2412 numfds = p->p_fd->fd_nfiles;
2413 if (len < numfds) {
2414 return -1;
2415 }
2416
2417 proc_fdlock(p);
2418 for (n = 0; ((n < numfds) && (n < p->p_fd->fd_nfiles)); n++) {
2419 if (((fp = p->p_fd->fd_ofiles[n]) != 0)
2420 && ((p->p_fd->fd_ofileflags[n] & UF_RESERVED) == 0)
2421 && (FILEGLOB_DTYPE(fp->f_fglob) == PROX_FDTYPE_KQUEUE)) {
2422 fdlist[count++] = n;
2423 }
2424 }
2425 proc_fdunlock(p);
2426 return count;
2427 }
2428
2429 int
2430 proc_kqueue_udata_info(proc_t p, int32_t fd, uint64_t *buffer, int bufsize)
2431 {
2432 struct kqueue *kq;
2433 struct fileproc * fp = NULL;
2434 int retval;
2435
2436 if (fd == -1) {
2437 /* wqkqueue is initialized on-demand */
2438 if ((kq = p->p_wqkqueue) == NULL) {
2439 return 0;
2440 }
2441 } else {
2442 int error = fp_getfkq(p, fd, &fp, &kq);
2443 if (error != 0) {
2444 return 0;
2445 }
2446 }
2447
2448 retval = pid_kqueue_udatainfo(p, kq, buffer, bufsize);
2449 if (fp) {
2450 fp_drop(p, fd, fp , 0);
2451 }
2452
2453 return retval;
2454 }
2455
2456 int
2457 proc_list_uptrs(proc_t p, uint64_t *udata_buffer, int size)
2458 {
2459 int32_t *fdlist = NULL;
2460 int nfds;
2461 int i;
2462 int count = 0;
2463 int ret;
2464 int knote_max = 4096;
2465 uint64_t *buffer;
2466 int bufsize = knote_max * sizeof(uint64_t);
2467
2468 fdlist = (int32_t *)kalloc((OPEN_MAX + 1) * sizeof(int32_t));
2469 if (!fdlist) {
2470 return -1;
2471 }
2472
2473 nfds = proc_listfd_kqueue(p, &fdlist[1], OPEN_MAX);
2474 if (nfds < 0 || nfds > OPEN_MAX) {
2475 kfree(fdlist, (OPEN_MAX + 1) * sizeof(int32_t));
2476 return 0;
2477 }
2478
2479 /* Add FD -1, the implicit workq kqueue */
2480 fdlist[0] = -1;
2481 nfds++;
2482
2483 if (size == 0) {
2484 bufsize = 0;
2485 buffer = NULL;
2486 } else {
2487 bufsize = knote_max * sizeof(uint64_t);
2488 buffer = (uint64_t *)kalloc(bufsize);
2489 }
2490
2491 for (i = 0; i < nfds; i++) {
2492 again:
2493 ret = proc_kqueue_udata_info(p, fdlist[i], buffer, bufsize);
2494 if (bufsize != 0 && ret > knote_max) {
2495 kfree(buffer, bufsize);
2496 knote_max = ret + 32;
2497 bufsize = knote_max * sizeof(uint64_t);
2498 buffer = kalloc(bufsize);
2499 goto again;
2500 }
2501
2502 if (ret == 0)
2503 continue;
2504
2505 /* Copy the udata ptrs */
2506 if (size >= (int)((count + ret) * sizeof(uint64_t))) {
2507 memcpy(&udata_buffer[count], buffer, ret * sizeof(uint64_t));
2508 }
2509 count = count + ret;
2510 }
2511
2512 kfree(fdlist, (OPEN_MAX + 1) * sizeof(int32_t));
2513 if (buffer) {
2514 kfree(buffer, bufsize);
2515 }
2516 return count;
2517 }
2518
2519 /*
2520 * Helper function for proc_pidfileportinfo
2521 */
2522
2523 struct fileport_info_args {
2524 int fia_flavor;
2525 user_addr_t fia_buffer;
2526 uint32_t fia_buffersize;
2527 int32_t *fia_retval;
2528 };
2529
2530 static kern_return_t
2531 proc_fileport_info(__unused mach_port_name_t name,
2532 struct fileglob *fg, void *arg)
2533 {
2534 struct fileport_info_args *fia = arg;
2535 struct fileproc __fileproc, *fp = &__fileproc;
2536 int error;
2537
2538 bzero(fp, sizeof (*fp));
2539 fp->f_fglob = fg;
2540
2541 switch (fia->fia_flavor) {
2542 case PROC_PIDFILEPORTVNODEPATHINFO: {
2543 vnode_t vp;
2544
2545 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
2546 error = ENOTSUP;
2547 break;
2548 }
2549 vp = (struct vnode *)fg->fg_data;
2550 error = pid_vnodeinfopath(vp, vnode_vid(vp), fp, PROC_NULL, 0,
2551 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
2552 } break;
2553
2554 case PROC_PIDFILEPORTSOCKETINFO: {
2555 socket_t so;
2556
2557 if (FILEGLOB_DTYPE(fg) != DTYPE_SOCKET) {
2558 error = EOPNOTSUPP;
2559 break;
2560 }
2561 so = (socket_t)fg->fg_data;
2562 error = pid_socketinfo(so, fp, PROC_NULL, 0,
2563 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
2564 } break;
2565
2566 case PROC_PIDFILEPORTPSHMINFO: {
2567 struct pshmnode *pshm;
2568
2569 if (FILEGLOB_DTYPE(fg) != DTYPE_PSXSHM) {
2570 error = EBADF; /* ick - mirror fp_getfpshm */
2571 break;
2572 }
2573 pshm = (struct pshmnode *)fg->fg_data;
2574 error = pid_pshminfo(pshm, fp, PROC_NULL, 0,
2575 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
2576 } break;
2577
2578 case PROC_PIDFILEPORTPIPEINFO: {
2579 struct pipe *cpipe;
2580
2581 if (FILEGLOB_DTYPE(fg) != DTYPE_PIPE) {
2582 error = EBADF; /* ick - mirror fp_getfpipe */
2583 break;
2584 }
2585 cpipe = (struct pipe *)fg->fg_data;
2586 error = pid_pipeinfo(cpipe, fp, PROC_NULL, 0,
2587 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
2588 } break;
2589
2590 default:
2591 error = EINVAL;
2592 break;
2593 }
2594
2595 return (error);
2596 }
2597
2598 /************************* proc_pidfileportinfo routine *********************/
2599 int
2600 proc_pidfileportinfo(int pid, int flavor, mach_port_name_t name,
2601 user_addr_t buffer, uint32_t buffersize, int32_t *retval)
2602 {
2603 proc_t p;
2604 int error = ENOTSUP;
2605 uint32_t size;
2606 struct fileport_info_args fia;
2607
2608 /* fileport types are restricted by file_issendable() */
2609
2610 switch (flavor) {
2611 case PROC_PIDFILEPORTVNODEPATHINFO:
2612 size = PROC_PIDFILEPORTVNODEPATHINFO_SIZE;
2613 break;
2614 case PROC_PIDFILEPORTSOCKETINFO:
2615 size = PROC_PIDFILEPORTSOCKETINFO_SIZE;
2616 break;
2617 case PROC_PIDFILEPORTPSHMINFO:
2618 size = PROC_PIDFILEPORTPSHMINFO_SIZE;
2619 break;
2620 case PROC_PIDFILEPORTPIPEINFO:
2621 size = PROC_PIDFILEPORTPIPEINFO_SIZE;
2622 break;
2623 default:
2624 return (EINVAL);
2625 }
2626
2627 if (buffersize < size)
2628 return (ENOMEM);
2629 if ((p = proc_find(pid)) == PROC_NULL) {
2630 error = ESRCH;
2631 goto out;
2632 }
2633
2634 /* Do we have permission to look into this? */
2635 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDFILEPORTINFO, flavor, CHECK_SAME_USER)))
2636 goto out1;
2637
2638 fia.fia_flavor = flavor;
2639 fia.fia_buffer = buffer;
2640 fia.fia_buffersize = buffersize;
2641 fia.fia_retval = retval;
2642
2643 if (fileport_invoke(p->task, name,
2644 proc_fileport_info, &fia, &error) != KERN_SUCCESS)
2645 error = EINVAL;
2646 out1:
2647 proc_rele(p);
2648 out:
2649 return (error);
2650 }
2651
2652 int
2653 proc_security_policy(proc_t targetp, __unused int callnum, __unused int flavor, boolean_t check_same_user)
2654 {
2655 #if CONFIG_MACF
2656 int error = 0;
2657
2658 if ((error = mac_proc_check_proc_info(current_proc(), targetp, callnum, flavor)))
2659 return (error);
2660 #endif
2661
2662 /* The 'listpids' call doesn't have a target proc */
2663 if (targetp == PROC_NULL) {
2664 assert(callnum == PROC_INFO_CALL_LISTPIDS && check_same_user == NO_CHECK_SAME_USER);
2665 return (0);
2666 }
2667
2668 /*
2669 * Check for 'get information for processes owned by other users' privilege
2670 * root has this privilege by default
2671 */
2672 if (priv_check_cred(kauth_cred_get(), PRIV_GLOBAL_PROC_INFO, 0) == 0)
2673 check_same_user = FALSE;
2674
2675 if (check_same_user) {
2676 kauth_cred_t target_cred;
2677 uid_t target_uid;
2678
2679 target_cred = kauth_cred_proc_ref(targetp);
2680 target_uid = kauth_cred_getuid(target_cred);
2681 kauth_cred_unref(&target_cred);
2682
2683 if (kauth_getuid() != target_uid)
2684 return(EPERM);
2685 }
2686
2687 return(0);
2688 }
2689
2690 int
2691 proc_kernmsgbuf(user_addr_t buffer, uint32_t buffersize, int32_t * retval)
2692 {
2693 if (suser(kauth_cred_get(), (u_short *)0) == 0) {
2694 return(log_dmesg(buffer, buffersize, retval));
2695 } else
2696 return(EPERM);
2697 }
2698
2699 /* ********* process control sets on self only */
2700 int
2701 proc_setcontrol(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, __unused int32_t * retval)
2702 {
2703 struct proc * pself = PROC_NULL;
2704 int error = 0;
2705 uint32_t pcontrol = (uint32_t)arg;
2706 struct uthread *ut = NULL;
2707 char name_buf[MAXTHREADNAMESIZE];
2708
2709 pself = current_proc();
2710 if (pid != pself->p_pid)
2711 return(EINVAL);
2712
2713 /* Do we have permission to look into this? */
2714 if ((error = proc_security_policy(pself, PROC_INFO_CALL_SETCONTROL, flavor, NO_CHECK_SAME_USER)))
2715 goto out;
2716
2717 switch (flavor) {
2718 case PROC_SELFSET_PCONTROL: {
2719 if (pcontrol > P_PCMAX)
2720 return(EINVAL);
2721 proc_lock(pself);
2722 /* reset existing control setting while retaining action state */
2723 pself->p_pcaction &= PROC_ACTION_MASK;
2724 /* set new control state */
2725 pself->p_pcaction |= pcontrol;
2726 proc_unlock(pself);
2727 }
2728 break;
2729
2730 case PROC_SELFSET_THREADNAME: {
2731 /*
2732 * This is a bit ugly, as it copies the name into the kernel, and then
2733 * invokes bsd_setthreadname again to copy it into the uthread name
2734 * buffer. Hopefully this isn't such a hot codepath that an additional
2735 * MAXTHREADNAMESIZE copy is a big issue.
2736 */
2737 if (buffersize > (MAXTHREADNAMESIZE - 1)) {
2738 return ENAMETOOLONG;
2739 }
2740
2741 ut = current_uthread();
2742
2743 bzero(name_buf, MAXTHREADNAMESIZE);
2744 error = copyin(buffer, name_buf, buffersize);
2745
2746 if (!error) {
2747 bsd_setthreadname(ut, name_buf);
2748 }
2749 }
2750 break;
2751
2752 case PROC_SELFSET_VMRSRCOWNER: {
2753 /* need to to be superuser */
2754 if (suser(kauth_cred_get(), (u_short *)0) != 0) {
2755 error = EPERM;
2756 goto out;
2757 }
2758
2759 proc_lock(pself);
2760 /* reset existing control setting while retaining action state */
2761 pself->p_lflag |= P_LVMRSRCOWNER;
2762 proc_unlock(pself);
2763 }
2764 break;
2765
2766 case PROC_SELFSET_DELAYIDLESLEEP: {
2767 /* mark or clear the process property to delay idle sleep disk IO */
2768 if (pcontrol != 0)
2769 OSBitOrAtomic(P_DELAYIDLESLEEP, &pself->p_flag);
2770 else
2771 OSBitAndAtomic(~((uint32_t)P_DELAYIDLESLEEP), &pself->p_flag);
2772 }
2773 break;
2774
2775 default:
2776 error = ENOTSUP;
2777 }
2778
2779 out:
2780 return(error);
2781 }
2782
2783 #if CONFIG_MEMORYSTATUS
2784
2785 int
2786 proc_dirtycontrol(int pid, int flavor, uint64_t arg, int32_t *retval) {
2787 struct proc *target_p;
2788 int error = 0;
2789 uint32_t pcontrol = (uint32_t)arg;
2790 kauth_cred_t my_cred, target_cred;
2791 boolean_t self = FALSE;
2792 boolean_t child = FALSE;
2793 boolean_t zombref = FALSE;
2794 pid_t selfpid;
2795
2796 target_p = proc_find(pid);
2797
2798 if (target_p == PROC_NULL) {
2799 if (flavor == PROC_DIRTYCONTROL_GET) {
2800 target_p = proc_find_zombref(pid);
2801 zombref = 1;
2802 }
2803
2804 if (target_p == PROC_NULL)
2805 return(ESRCH);
2806
2807 }
2808
2809 my_cred = kauth_cred_get();
2810 target_cred = kauth_cred_proc_ref(target_p);
2811
2812 /* Do we have permission to look into this? */
2813 if ((error = proc_security_policy(target_p, PROC_INFO_CALL_DIRTYCONTROL, flavor, NO_CHECK_SAME_USER)))
2814 goto out;
2815
2816 selfpid = proc_selfpid();
2817 if (pid == selfpid) {
2818 self = TRUE;
2819 } else if (target_p->p_ppid == selfpid) {
2820 child = TRUE;
2821 }
2822
2823 switch (flavor) {
2824 case PROC_DIRTYCONTROL_TRACK: {
2825 /* Only allow the process itself, its parent, or root */
2826 if ((self == FALSE) && (child == FALSE) && kauth_cred_issuser(kauth_cred_get()) != TRUE) {
2827 error = EPERM;
2828 goto out;
2829 }
2830
2831 error = memorystatus_dirty_track(target_p, pcontrol);
2832 }
2833 break;
2834
2835 case PROC_DIRTYCONTROL_SET: {
2836 /* Check privileges; use cansignal() here since the process could be terminated */
2837 if (!cansignal(current_proc(), my_cred, target_p, SIGKILL, 0)) {
2838 error = EPERM;
2839 goto out;
2840 }
2841
2842 error = memorystatus_dirty_set(target_p, self, pcontrol);
2843 }
2844 break;
2845
2846 case PROC_DIRTYCONTROL_GET: {
2847 /* No permissions check - dirty state is freely available */
2848 if (retval) {
2849 *retval = memorystatus_dirty_get(target_p);
2850 } else {
2851 error = EINVAL;
2852 }
2853 }
2854 break;
2855
2856 case PROC_DIRTYCONTROL_CLEAR: {
2857 /* Check privileges; use cansignal() here since the process could be terminated */
2858 if (!cansignal(current_proc(), my_cred, target_p, SIGKILL, 0)) {
2859 error = EPERM;
2860 goto out;
2861 }
2862
2863 error = memorystatus_dirty_clear(target_p, pcontrol);
2864 }
2865 break;
2866 }
2867
2868 out:
2869 if (zombref)
2870 proc_drop_zombref(target_p);
2871 else
2872 proc_rele(target_p);
2873
2874 kauth_cred_unref(&target_cred);
2875
2876 return(error);
2877 }
2878 #else
2879
2880 int
2881 proc_dirtycontrol(__unused int pid, __unused int flavor, __unused uint64_t arg, __unused int32_t *retval) {
2882 return ENOTSUP;
2883 }
2884
2885 #endif /* CONFIG_MEMORYSTATUS */
2886
2887 /*
2888 * proc_terminate() provides support for sudden termination.
2889 * SIGKILL is issued to tracked, clean processes; otherwise,
2890 * SIGTERM is sent.
2891 */
2892
2893 int
2894 proc_terminate(int pid, int32_t *retval)
2895 {
2896 int error = 0;
2897 proc_t p;
2898 kauth_cred_t uc = kauth_cred_get();
2899 int sig;
2900
2901 #if 0
2902 /* XXX: Check if these are necessary */
2903 AUDIT_ARG(pid, pid);
2904 AUDIT_ARG(signum, sig);
2905 #endif
2906
2907 if (pid <= 0 || retval == NULL) {
2908 return (EINVAL);
2909 }
2910
2911 if ((p = proc_find(pid)) == NULL) {
2912 return (ESRCH);
2913 }
2914
2915 #if 0
2916 /* XXX: Check if these are necessary */
2917 AUDIT_ARG(process, p);
2918 #endif
2919
2920 /* Check privileges; if SIGKILL can be issued, then SIGTERM is also OK */
2921 if (!cansignal(current_proc(), uc, p, SIGKILL, 0)) {
2922 error = EPERM;
2923 goto out;
2924 }
2925
2926 /* Not allowed to sudden terminate yourself */
2927 if (p == current_proc()) {
2928 error = EPERM;
2929 goto out;
2930 }
2931
2932 #if CONFIG_MEMORYSTATUS
2933 /* Determine requisite signal to issue */
2934 sig = memorystatus_on_terminate(p);
2935 #else
2936 sig = SIGTERM;
2937 #endif
2938
2939 proc_set_task_policy(p->task, TASK_POLICY_ATTRIBUTE,
2940 TASK_POLICY_TERMINATED, TASK_POLICY_ENABLE);
2941
2942 psignal(p, sig);
2943 *retval = sig;
2944
2945 out:
2946 proc_rele(p);
2947
2948 return error;
2949 }
2950
2951 /*
2952 * copy stat64 structure into vinfo_stat structure.
2953 */
2954 static void
2955 munge_vinfo_stat(struct stat64 *sbp, struct vinfo_stat *vsbp)
2956 {
2957 bzero(vsbp, sizeof(struct vinfo_stat));
2958
2959 vsbp->vst_dev = sbp->st_dev;
2960 vsbp->vst_mode = sbp->st_mode;
2961 vsbp->vst_nlink = sbp->st_nlink;
2962 vsbp->vst_ino = sbp->st_ino;
2963 vsbp->vst_uid = sbp->st_uid;
2964 vsbp->vst_gid = sbp->st_gid;
2965 vsbp->vst_atime = sbp->st_atimespec.tv_sec;
2966 vsbp->vst_atimensec = sbp->st_atimespec.tv_nsec;
2967 vsbp->vst_mtime = sbp->st_mtimespec.tv_sec;
2968 vsbp->vst_mtimensec = sbp->st_mtimespec.tv_nsec;
2969 vsbp->vst_ctime = sbp->st_ctimespec.tv_sec;
2970 vsbp->vst_ctimensec = sbp->st_ctimespec.tv_nsec;
2971 vsbp->vst_birthtime = sbp->st_birthtimespec.tv_sec;
2972 vsbp->vst_birthtimensec = sbp->st_birthtimespec.tv_nsec;
2973 vsbp->vst_size = sbp->st_size;
2974 vsbp->vst_blocks = sbp->st_blocks;
2975 vsbp->vst_blksize = sbp->st_blksize;
2976 vsbp->vst_flags = sbp->st_flags;
2977 vsbp->vst_gen = sbp->st_gen;
2978 vsbp->vst_rdev = sbp->st_rdev;
2979 vsbp->vst_qspare[0] = sbp->st_qspare[0];
2980 vsbp->vst_qspare[1] = sbp->st_qspare[1];
2981 }
2982
2983 int
2984 proc_pid_rusage(int pid, int flavor, user_addr_t buffer, __unused int32_t *retval)
2985 {
2986 proc_t p;
2987 int error;
2988 int zombie = 0;
2989
2990 if ((p = proc_find(pid)) == PROC_NULL) {
2991 if ((p = proc_find_zombref(pid)) == PROC_NULL) {
2992 return (ESRCH);
2993 }
2994 zombie = 1;
2995 }
2996
2997 /* Do we have permission to look into this? */
2998 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDRUSAGE, flavor, CHECK_SAME_USER)))
2999 goto out;
3000
3001 error = proc_get_rusage(p, flavor, buffer, zombie);
3002
3003 out:
3004 if (zombie)
3005 proc_drop_zombref(p);
3006 else
3007 proc_rele(p);
3008
3009 return (error);
3010 }
3011
3012 void
3013 proc_archinfo(proc_t p, struct proc_archinfo *pai)
3014 {
3015 proc_lock(p);
3016 pai->p_cputype = p->p_cputype;
3017 pai->p_cpusubtype = p->p_cpusubtype;
3018 proc_unlock(p);
3019 }
3020
3021 void
3022 proc_pidcoalitioninfo(proc_t p, struct proc_pidcoalitioninfo *ppci)
3023 {
3024 bzero(ppci, sizeof(*ppci));
3025 proc_coalitionids(p, ppci->coalition_id);
3026 }
3027
3028 int
3029 proc_pidexitreasoninfo(proc_t p, struct proc_exitreasoninfo *peri, struct proc_exitreasonbasicinfo *pberi)
3030 {
3031 uint32_t reason_data_size = 0;
3032 int error = 0;
3033 pid_t selfpid = proc_selfpid();
3034
3035 proc_lock(p);
3036
3037 /*
3038 * One (and only one) of peri and pberi must be non-NULL.
3039 */
3040 assert((peri != NULL) || (pberi != NULL));
3041 assert((peri == NULL) || (pberi == NULL));
3042
3043 /*
3044 * Allow access to the parent of the exiting
3045 * child or the parent debugger only.
3046 */
3047 do {
3048 if (p->p_ppid == selfpid)
3049 break; /* parent => ok */
3050
3051 if ((p->p_lflag & P_LTRACED) != 0 &&
3052 (p->p_oppid == selfpid))
3053 break; /* parent-in-waiting => ok */
3054
3055 proc_unlock(p);
3056 return EACCES;
3057 } while (0);
3058
3059 if (p->p_exit_reason == OS_REASON_NULL) {
3060 proc_unlock(p);
3061 return ENOENT;
3062 }
3063
3064 if (p->p_exit_reason->osr_kcd_buf != NULL) {
3065 reason_data_size = kcdata_memory_get_used_bytes(&p->p_exit_reason->osr_kcd_descriptor);
3066 }
3067
3068 if (peri != NULL) {
3069 peri->eri_namespace = p->p_exit_reason->osr_namespace;
3070 peri->eri_code = p->p_exit_reason->osr_code;
3071 peri->eri_flags = p->p_exit_reason->osr_flags;
3072
3073 if ((peri->eri_kcd_buf == 0) || (peri->eri_reason_buf_size < reason_data_size)) {
3074 proc_unlock(p);
3075 return ENOMEM;
3076 }
3077
3078 peri->eri_reason_buf_size = reason_data_size;
3079 if (reason_data_size != 0) {
3080 error = copyout(p->p_exit_reason->osr_kcd_buf, peri->eri_kcd_buf, reason_data_size);
3081 }
3082 } else {
3083 pberi->beri_namespace = p->p_exit_reason->osr_namespace;
3084 pberi->beri_code = p->p_exit_reason->osr_code;
3085 pberi->beri_flags = p->p_exit_reason->osr_flags;
3086 pberi->beri_reason_buf_size = reason_data_size;
3087 }
3088
3089 proc_unlock(p);
3090
3091 return error;
3092 }
3093
3094 /*
3095 * Wrapper to provide NOTE_EXIT_DETAIL and NOTE_EXITSTATUS
3096 * It mimics the data that is typically captured by the
3097 * EVFILT_PROC, NOTE_EXIT event mechanism.
3098 * See filt_proc() in kern_event.c.
3099 */
3100 int
3101 proc_pidnoteexit(proc_t p, uint64_t flags, uint32_t *data)
3102 {
3103 uint32_t exit_data = 0;
3104 uint32_t exit_flags = (uint32_t)flags;
3105
3106 proc_lock(p);
3107
3108 /*
3109 * Allow access to the parent of the exiting
3110 * child or the parent debugger only.
3111 */
3112 do {
3113 pid_t selfpid = proc_selfpid();
3114
3115 if (p->p_ppid == selfpid)
3116 break; /* parent => ok */
3117
3118 if ((p->p_lflag & P_LTRACED) != 0 &&
3119 (p->p_oppid == selfpid))
3120 break; /* parent-in-waiting => ok */
3121
3122 proc_unlock(p);
3123 return (EACCES);
3124 } while (0);
3125
3126 if ((exit_flags & NOTE_EXITSTATUS) != 0) {
3127 /* The signal and exit status */
3128 exit_data |= (p->p_xstat & NOTE_PDATAMASK);
3129 }
3130
3131 if ((exit_flags & NOTE_EXIT_DETAIL) != 0) {
3132 /* The exit detail */
3133 if ((p->p_lflag & P_LTERM_DECRYPTFAIL) != 0) {
3134 exit_data |= NOTE_EXIT_DECRYPTFAIL;
3135 }
3136
3137 if ((p->p_lflag & P_LTERM_JETSAM) != 0) {
3138 exit_data |= NOTE_EXIT_MEMORY;
3139
3140 switch (p->p_lflag & P_JETSAM_MASK) {
3141 case P_JETSAM_VMPAGESHORTAGE:
3142 exit_data |= NOTE_EXIT_MEMORY_VMPAGESHORTAGE;
3143 break;
3144 case P_JETSAM_VMTHRASHING:
3145 exit_data |= NOTE_EXIT_MEMORY_VMTHRASHING;
3146 break;
3147 case P_JETSAM_FCTHRASHING:
3148 exit_data |= NOTE_EXIT_MEMORY_FCTHRASHING;
3149 break;
3150 case P_JETSAM_VNODE:
3151 exit_data |= NOTE_EXIT_MEMORY_VNODE;
3152 break;
3153 case P_JETSAM_HIWAT:
3154 exit_data |= NOTE_EXIT_MEMORY_HIWAT;
3155 break;
3156 case P_JETSAM_PID:
3157 exit_data |= NOTE_EXIT_MEMORY_PID;
3158 break;
3159 case P_JETSAM_IDLEEXIT:
3160 exit_data |= NOTE_EXIT_MEMORY_IDLE;
3161 break;
3162 }
3163 }
3164
3165 if ((p->p_csflags & CS_KILLED) != 0) {
3166 exit_data |= NOTE_EXIT_CSERROR;
3167 }
3168 }
3169
3170 proc_unlock(p);
3171
3172 *data = exit_data;
3173
3174 return (0);
3175 }
3176