]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/proc_info.c
xnu-3789.1.32.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 error = proc_pidpathinfo_internal(p, arg, buf, buffersize, retval);
1153 if (error == 0) {
1154 error = copyout(buf, buffer, len);
1155 }
1156 kfree(buf, buffersize);
1157 return(error);
1158 }
1159
1160 int
1161 proc_pidpathinfo_internal(proc_t p, __unused uint64_t arg, char *buf, uint32_t buffersize, __unused int32_t *retval)
1162 {
1163 int vid, error;
1164 vnode_t tvp;
1165 vnode_t nvp = NULLVP;
1166 int len = buffersize;
1167
1168 tvp = p->p_textvp;
1169
1170 if (tvp == NULLVP)
1171 return(ESRCH);
1172
1173 vid = vnode_vid(tvp);
1174 error = vnode_getwithvid(tvp, vid);
1175 if (error == 0) {
1176 error = vn_getpath_fsenter(tvp, buf, &len);
1177 vnode_put(tvp);
1178 if (error == 0) {
1179 error = vnode_lookup(buf, 0, &nvp, vfs_context_current());
1180 if ((error == 0) && ( nvp != NULLVP))
1181 vnode_put(nvp);
1182 }
1183 }
1184 return(error);
1185 }
1186
1187
1188 int
1189 proc_pidworkqueueinfo(proc_t p, struct proc_workqueueinfo *pwqinfo)
1190 {
1191 int error = 0;
1192
1193 bzero(pwqinfo, sizeof(struct proc_workqueueinfo));
1194
1195 error = fill_procworkqueue(p, pwqinfo);
1196 if (error)
1197 return(ESRCH);
1198 else
1199 return(0);
1200
1201 }
1202
1203
1204 void
1205 proc_piduniqidentifierinfo(proc_t p, struct proc_uniqidentifierinfo *p_uniqidinfo)
1206 {
1207 p_uniqidinfo->p_uniqueid = proc_uniqueid(p);
1208 proc_getexecutableuuid(p, (unsigned char *)&p_uniqidinfo->p_uuid, sizeof(p_uniqidinfo->p_uuid));
1209 p_uniqidinfo->p_puniqueid = proc_puniqueid(p);
1210 p_uniqidinfo->p_reserve2 = 0;
1211 p_uniqidinfo->p_reserve3 = 0;
1212 p_uniqidinfo->p_reserve4 = 0;
1213 }
1214
1215
1216 static int
1217 proc_piduuidinfo(pid_t pid, uuid_t uuid_buf, uint32_t buffersize)
1218 {
1219 struct proc * p = PROC_NULL;
1220 int zombref = 0;
1221
1222 if (buffersize < sizeof(uuid_t))
1223 return EINVAL;
1224
1225 if ((p = proc_find(pid)) == PROC_NULL) {
1226 p = proc_find_zombref(pid);
1227 zombref = 1;
1228 }
1229 if (p == PROC_NULL) {
1230 return ESRCH;
1231 }
1232
1233 proc_getexecutableuuid(p, (unsigned char *)uuid_buf, buffersize);
1234
1235 if (zombref)
1236 proc_drop_zombref(p);
1237 else
1238 proc_rele(p);
1239
1240 return 0;
1241 }
1242
1243 /*
1244 * Function to get the uuid and pid of the originator of the voucher.
1245 */
1246 int
1247 proc_pidoriginatorpid_uuid(uuid_t uuid, uint32_t buffersize, pid_t *pid)
1248 {
1249 pid_t originator_pid;
1250 kern_return_t kr;
1251 int error;
1252
1253 /*
1254 * Get the current voucher origin pid. The pid returned here
1255 * might not be valid or may have been recycled.
1256 */
1257 kr = thread_get_current_voucher_origin_pid(&originator_pid);
1258 /* If errors, convert errors to appropriate format */
1259 if (kr) {
1260 if (kr == KERN_INVALID_TASK)
1261 error = ESRCH;
1262 else if (kr == KERN_INVALID_VALUE)
1263 error = ENOATTR;
1264 else
1265 error = EINVAL;
1266 return error;
1267 }
1268
1269 *pid = originator_pid;
1270 error = proc_piduuidinfo(originator_pid, uuid, buffersize);
1271 return error;
1272 }
1273
1274 /*
1275 * Function to get the uuid of the originator of the voucher.
1276 */
1277 int
1278 proc_pidoriginatoruuid(uuid_t uuid, uint32_t buffersize)
1279 {
1280 pid_t originator_pid;
1281 return (proc_pidoriginatorpid_uuid(uuid, buffersize, &originator_pid));
1282 }
1283
1284 /***************************** proc_pidoriginatorinfo ***************************/
1285
1286 int
1287 proc_pidoriginatorinfo(int pid, int flavor, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
1288 {
1289 int error = ENOTSUP;
1290 uint32_t size;
1291
1292 switch (flavor) {
1293 case PROC_PIDORIGINATOR_UUID:
1294 size = PROC_PIDORIGINATOR_UUID_SIZE;
1295 break;
1296 case PROC_PIDORIGINATOR_BGSTATE:
1297 size = PROC_PIDORIGINATOR_BGSTATE_SIZE;
1298 break;
1299 case PROC_PIDORIGINATOR_PID_UUID:
1300 size = PROC_PIDORIGINATOR_PID_UUID_SIZE;
1301 break;
1302 default:
1303 return(EINVAL);
1304 }
1305
1306 if (buffersize < size)
1307 return(ENOMEM);
1308
1309 if (pid != 0 && pid != proc_selfpid())
1310 return (EINVAL);
1311
1312 switch (flavor) {
1313 case PROC_PIDORIGINATOR_UUID: {
1314 uuid_t uuid;
1315
1316 error = proc_pidoriginatoruuid(uuid, sizeof(uuid));
1317 if (error != 0)
1318 goto out;
1319
1320 error = copyout(uuid, buffer, size);
1321 if (error == 0)
1322 *retval = size;
1323 }
1324 break;
1325
1326 case PROC_PIDORIGINATOR_PID_UUID: {
1327 struct proc_originatorinfo originator_info;
1328 bzero(&originator_info, sizeof(originator_info));
1329
1330 error = proc_pidoriginatorpid_uuid(originator_info.originator_uuid,
1331 sizeof(uuid_t), &originator_info.originator_pid);
1332 if (error != 0)
1333 goto out;
1334
1335 error = copyout(&originator_info, buffer, size);
1336 if (error == 0)
1337 *retval = size;
1338 }
1339 break;
1340
1341 case PROC_PIDORIGINATOR_BGSTATE: {
1342 uint32_t is_backgrounded;
1343 error = proc_get_originatorbgstate(&is_backgrounded);
1344 if (error)
1345 goto out;
1346
1347 error = copyout(&is_backgrounded, buffer, size);
1348 if (error == 0)
1349 *retval = size;
1350 }
1351 break;
1352
1353 default:
1354 error = ENOTSUP;
1355 }
1356 out:
1357 return error;
1358 }
1359
1360 /***************************** proc_listcoalitions ***************************/
1361 int proc_listcoalitions(int flavor, int type, user_addr_t buffer,
1362 uint32_t buffersize, int32_t *retval)
1363 {
1364 #if CONFIG_COALITIONS
1365 int error = ENOTSUP;
1366 int coal_type;
1367 uint32_t elem_size;
1368 void *coalinfo = NULL;
1369 uint32_t k_buffersize = 0, copyout_sz = 0;
1370 int ncoals = 0, ncoals_ = 0;
1371
1372 /* struct procinfo_coalinfo; */
1373
1374 switch (flavor) {
1375 case LISTCOALITIONS_ALL_COALS:
1376 elem_size = LISTCOALITIONS_ALL_COALS_SIZE;
1377 coal_type = -1;
1378 break;
1379 case LISTCOALITIONS_SINGLE_TYPE:
1380 elem_size = LISTCOALITIONS_SINGLE_TYPE_SIZE;
1381 coal_type = type;
1382 break;
1383 default:
1384 return EINVAL;
1385 }
1386
1387 /* find the total number of coalitions */
1388 ncoals = coalitions_get_list(coal_type, NULL, 0);
1389
1390 if (ncoals == 0 || buffer == 0 || buffersize == 0) {
1391 /*
1392 * user just wants buffer size
1393 * or there are no coalitions
1394 */
1395 error = 0;
1396 *retval = (int)(ncoals * elem_size);
1397 goto out;
1398 }
1399
1400 k_buffersize = ncoals * elem_size;
1401 coalinfo = kalloc((vm_size_t)k_buffersize);
1402 if (!coalinfo) {
1403 error = ENOMEM;
1404 goto out;
1405 }
1406 bzero(coalinfo, k_buffersize);
1407
1408 switch (flavor) {
1409 case LISTCOALITIONS_ALL_COALS:
1410 case LISTCOALITIONS_SINGLE_TYPE:
1411 ncoals_ = coalitions_get_list(coal_type, coalinfo, ncoals);
1412 break;
1413 default:
1414 panic("memory corruption?!");
1415 }
1416
1417 if (ncoals_ == 0) {
1418 /* all the coalitions disappeared... weird but valid */
1419 error = 0;
1420 *retval = 0;
1421 goto out;
1422 }
1423
1424 /*
1425 * Some coalitions may have disappeared between our initial check,
1426 * and the the actual list acquisition.
1427 * Only copy out what we really need.
1428 */
1429 copyout_sz = k_buffersize;
1430 if (ncoals_ < ncoals)
1431 copyout_sz = ncoals_ * elem_size;
1432
1433 /*
1434 * copy the list up to user space
1435 * (we're guaranteed to have a non-null pointer/size here)
1436 */
1437 error = copyout(coalinfo, buffer,
1438 copyout_sz < buffersize ? copyout_sz : buffersize);
1439
1440 if (error == 0)
1441 *retval = (int)copyout_sz;
1442
1443 out:
1444 if (coalinfo)
1445 kfree(coalinfo, k_buffersize);
1446
1447 return error;
1448 #else
1449 /* no coalition support */
1450 (void)flavor;
1451 (void)type;
1452 (void)buffer;
1453 (void)buffersize;
1454 (void)retval;
1455 return ENOTSUP;
1456 #endif
1457 }
1458
1459
1460 /*************************** proc_can_use_forgeound_hw **************************/
1461 int proc_can_use_foreground_hw(int pid, user_addr_t u_reason, uint32_t reasonsize, int32_t *retval)
1462 {
1463 proc_t p = PROC_NULL;
1464 int error = 0;
1465 uint32_t reason = PROC_FGHW_ERROR;
1466 uint32_t isBG = 0;
1467 task_t task = TASK_NULL;
1468 #if CONFIG_COALITIONS
1469 coalition_t coal = COALITION_NULL;
1470 #endif
1471
1472 *retval = 0;
1473
1474 if (pid <= 0) {
1475 error = EINVAL;
1476 reason = PROC_FGHW_ERROR;
1477 goto out;
1478 }
1479
1480 p = proc_find(pid);
1481 if (p == PROC_NULL) {
1482 error = ESRCH;
1483 reason = PROC_FGHW_ERROR;
1484 goto out;
1485 }
1486
1487 #if CONFIG_COALITIONS
1488 if (p != current_proc() &&
1489 !kauth_cred_issuser(kauth_cred_get())) {
1490 error = EPERM;
1491 reason = PROC_FGHW_ERROR;
1492 goto out;
1493 }
1494
1495 task = p->task;
1496 task_reference(task);
1497 if (coalition_is_leader(task, COALITION_TYPE_JETSAM, &coal) == FALSE) {
1498 /* current task is not a coalition leader: find the leader */
1499 task_deallocate(task);
1500 task = coalition_get_leader(coal);
1501 }
1502
1503 if (task != TASK_NULL) {
1504 /*
1505 * If task is non-null, then it is the coalition leader of the
1506 * current process' coalition. This could be the same task as
1507 * the current_task, and that's OK.
1508 */
1509 uint32_t flags = 0;
1510 int role;
1511
1512 proc_get_darwinbgstate(task, &flags);
1513 if ((flags & PROC_FLAG_APPLICATION) != PROC_FLAG_APPLICATION) {
1514 /*
1515 * Coalition leader is not an application, continue
1516 * searching for other ways this task could gain
1517 * access to HW
1518 */
1519 reason = PROC_FGHW_DAEMON_LEADER;
1520 goto no_leader;
1521 }
1522
1523 if (proc_get_effective_task_policy(task, TASK_POLICY_DARWIN_BG)) {
1524 /*
1525 * If the leader of the current process' coalition has
1526 * been marked as DARWIN_BG, then it definitely should
1527 * not be using foreground hardware resources.
1528 */
1529 reason = PROC_FGHW_LEADER_BACKGROUND;
1530 goto out;
1531 }
1532
1533 role = proc_get_effective_task_policy(task, TASK_POLICY_ROLE);
1534 switch (role) {
1535 case TASK_FOREGROUND_APPLICATION: /* DARWIN_ROLE_UI_FOCAL */
1536 case TASK_BACKGROUND_APPLICATION: /* DARWIN_ROLE_UI */
1537 /*
1538 * The leader of this coalition is a focal, UI app:
1539 * access granted
1540 * TODO: should extensions/plugins be allowed to use
1541 * this hardware?
1542 */
1543 *retval = 1;
1544 reason = PROC_FGHW_OK;
1545 goto out;
1546 case TASK_DEFAULT_APPLICATION: /* DARWIN_ROLE_UI_NON_FOCAL */
1547 case TASK_NONUI_APPLICATION: /* DARWIN_ROLE_NON_UI */
1548 case TASK_THROTTLE_APPLICATION:
1549 case TASK_UNSPECIFIED:
1550 default:
1551 /* non-focal, non-ui apps don't get access */
1552 reason = PROC_FGHW_LEADER_NONUI;
1553 goto out;
1554 }
1555 }
1556
1557 no_leader:
1558 if (task != TASK_NULL) {
1559 task_deallocate(task);
1560 task = TASK_NULL;
1561 }
1562 #endif /* CONFIG_COALITIONS */
1563
1564 /*
1565 * There is no reasonable semantic to investigate the currently
1566 * adopted voucher of an arbitrary thread in a non-current process.
1567 * We return '0'
1568 */
1569 if (p != current_proc()) {
1570 error = EINVAL;
1571 goto out;
1572 }
1573
1574 /*
1575 * In the absence of coalitions, fall back to a voucher-based lookup
1576 * where a daemon can used foreground HW if it's operating on behalf
1577 * of a foreground application.
1578 * NOTE: this is equivalent to a call to
1579 * proc_pidoriginatorinfo(PROC_PIDORIGINATOR_BGSTATE, &isBG, sizeof(isBG))
1580 */
1581 isBG = 1;
1582 error = proc_get_originatorbgstate(&isBG);
1583 switch (error) {
1584 case 0:
1585 break;
1586 case ESRCH:
1587 reason = PROC_FGHW_NO_ORIGINATOR;
1588 error = 0;
1589 goto out;
1590 case ENOATTR:
1591 reason = PROC_FGHW_NO_VOUCHER_ATTR;
1592 error = 0;
1593 goto out;
1594 case EINVAL:
1595 reason = PROC_FGHW_DAEMON_NO_VOUCHER;
1596 error = 0;
1597 goto out;
1598 default:
1599 /* some other error occurred: report that to the caller */
1600 reason = PROC_FGHW_VOUCHER_ERROR;
1601 goto out;
1602 }
1603
1604 if (isBG) {
1605 reason = PROC_FGHW_ORIGINATOR_BACKGROUND;
1606 error = 0;
1607 } else {
1608 /*
1609 * The process itself is either a foreground app, or has
1610 * adopted a voucher originating from an app that's still in
1611 * the foreground
1612 */
1613 reason = PROC_FGHW_DAEMON_OK;
1614 *retval = 1;
1615 }
1616
1617 out:
1618 if (task != TASK_NULL)
1619 task_deallocate(task);
1620 if (p != PROC_NULL)
1621 proc_rele(p);
1622 if (reasonsize >= sizeof(reason) && u_reason != (user_addr_t)0)
1623 (void)copyout(&reason, u_reason, sizeof(reason));
1624 return error;
1625 }
1626
1627
1628 /********************************** proc_pidinfo ********************************/
1629
1630
1631 int
1632 proc_pidinfo(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
1633 {
1634 struct proc * p = PROC_NULL;
1635 int error = ENOTSUP;
1636 int gotref = 0;
1637 int findzomb = 0;
1638 int shortversion = 0;
1639 uint32_t size;
1640 int zombie = 0;
1641 int thuniqueid = 0;
1642 int uniqidversion = 0;
1643 boolean_t check_same_user;
1644
1645 switch (flavor) {
1646 case PROC_PIDLISTFDS:
1647 size = PROC_PIDLISTFD_SIZE;
1648 if (buffer == (user_addr_t)0)
1649 size = 0;
1650 break;
1651 case PROC_PIDTBSDINFO:
1652 size = PROC_PIDTBSDINFO_SIZE;
1653 break;
1654 case PROC_PIDTASKINFO:
1655 size = PROC_PIDTASKINFO_SIZE;
1656 break;
1657 case PROC_PIDTASKALLINFO:
1658 size = PROC_PIDTASKALLINFO_SIZE;
1659 break;
1660 case PROC_PIDTHREADINFO:
1661 size = PROC_PIDTHREADINFO_SIZE;
1662 break;
1663 case PROC_PIDLISTTHREADS:
1664 size = PROC_PIDLISTTHREADS_SIZE;
1665 break;
1666 case PROC_PIDREGIONINFO:
1667 size = PROC_PIDREGIONINFO_SIZE;
1668 break;
1669 case PROC_PIDREGIONPATHINFO:
1670 size = PROC_PIDREGIONPATHINFO_SIZE;
1671 break;
1672 case PROC_PIDVNODEPATHINFO:
1673 size = PROC_PIDVNODEPATHINFO_SIZE;
1674 break;
1675 case PROC_PIDTHREADPATHINFO:
1676 size = PROC_PIDTHREADPATHINFO_SIZE;
1677 break;
1678 case PROC_PIDPATHINFO:
1679 size = MAXPATHLEN;
1680 break;
1681 case PROC_PIDWORKQUEUEINFO:
1682 /* kernel does not have workq info */
1683 if (pid == 0)
1684 return(EINVAL);
1685 else
1686 size = PROC_PIDWORKQUEUEINFO_SIZE;
1687 break;
1688 case PROC_PIDT_SHORTBSDINFO:
1689 size = PROC_PIDT_SHORTBSDINFO_SIZE;
1690 break;
1691 case PROC_PIDLISTFILEPORTS:
1692 size = PROC_PIDLISTFILEPORTS_SIZE;
1693 if (buffer == (user_addr_t)0)
1694 size = 0;
1695 break;
1696 case PROC_PIDTHREADID64INFO:
1697 size = PROC_PIDTHREADID64INFO_SIZE;
1698 break;
1699 case PROC_PIDUNIQIDENTIFIERINFO:
1700 size = PROC_PIDUNIQIDENTIFIERINFO_SIZE;
1701 break;
1702 case PROC_PIDT_BSDINFOWITHUNIQID:
1703 size = PROC_PIDT_BSDINFOWITHUNIQID_SIZE;
1704 break;
1705 case PROC_PIDARCHINFO:
1706 size = PROC_PIDARCHINFO_SIZE;
1707 break;
1708 case PROC_PIDCOALITIONINFO:
1709 size = PROC_PIDCOALITIONINFO_SIZE;
1710 break;
1711 case PROC_PIDNOTEEXIT:
1712 /*
1713 * Set findzomb explicitly because arg passed
1714 * in is used as note exit status bits.
1715 */
1716 size = PROC_PIDNOTEEXIT_SIZE;
1717 findzomb = 1;
1718 break;
1719 case PROC_PIDEXITREASONINFO:
1720 size = PROC_PIDEXITREASONINFO_SIZE;
1721 findzomb = 1;
1722 break;
1723 case PROC_PIDEXITREASONBASICINFO:
1724 size = PROC_PIDEXITREASONBASICINFOSIZE;
1725 findzomb = 1;
1726 break;
1727 case PROC_PIDREGIONPATHINFO2:
1728 size = PROC_PIDREGIONPATHINFO2_SIZE;
1729 break;
1730 case PROC_PIDREGIONPATHINFO3:
1731 size = PROC_PIDREGIONPATHINFO3_SIZE;
1732 break;
1733 default:
1734 return(EINVAL);
1735 }
1736
1737 if (buffersize < size)
1738 return(ENOMEM);
1739
1740 if ((flavor == PROC_PIDPATHINFO) && (buffersize > PROC_PIDPATHINFO_MAXSIZE)) {
1741 return(EOVERFLOW);
1742 }
1743
1744 /* Check if we need to look for zombies */
1745 if ((flavor == PROC_PIDTBSDINFO) || (flavor == PROC_PIDT_SHORTBSDINFO) || (flavor == PROC_PIDT_BSDINFOWITHUNIQID)
1746 || (flavor == PROC_PIDUNIQIDENTIFIERINFO)) {
1747 if (arg)
1748 findzomb = 1;
1749 }
1750
1751 if ((p = proc_find(pid)) == PROC_NULL) {
1752 if (findzomb)
1753 p = proc_find_zombref(pid);
1754 if (p == PROC_NULL) {
1755 error = ESRCH;
1756 goto out;
1757 }
1758 zombie = 1;
1759 } else {
1760 gotref = 1;
1761 }
1762
1763 /* Certain operations don't require privileges */
1764 switch (flavor) {
1765 case PROC_PIDT_SHORTBSDINFO:
1766 case PROC_PIDUNIQIDENTIFIERINFO:
1767 case PROC_PIDPATHINFO:
1768 case PROC_PIDCOALITIONINFO:
1769 check_same_user = NO_CHECK_SAME_USER;
1770 break;
1771 default:
1772 check_same_user = CHECK_SAME_USER;
1773 break;
1774 }
1775
1776 /* Do we have permission to look into this? */
1777 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDINFO, flavor, check_same_user)))
1778 goto out;
1779
1780 switch (flavor) {
1781 case PROC_PIDLISTFDS: {
1782 error = proc_pidfdlist(p, buffer, buffersize, retval);
1783 }
1784 break;
1785
1786 case PROC_PIDUNIQIDENTIFIERINFO: {
1787 struct proc_uniqidentifierinfo p_uniqidinfo;
1788 bzero(&p_uniqidinfo, sizeof(p_uniqidinfo));
1789 proc_piduniqidentifierinfo(p, &p_uniqidinfo);
1790 error = copyout(&p_uniqidinfo, buffer, sizeof(struct proc_uniqidentifierinfo));
1791 if (error == 0)
1792 *retval = sizeof(struct proc_uniqidentifierinfo);
1793 }
1794 break;
1795
1796 case PROC_PIDT_SHORTBSDINFO:
1797 shortversion = 1;
1798 case PROC_PIDT_BSDINFOWITHUNIQID:
1799 case PROC_PIDTBSDINFO: {
1800 struct proc_bsdinfo pbsd;
1801 struct proc_bsdshortinfo pbsd_short;
1802 struct proc_bsdinfowithuniqid pbsd_uniqid;
1803
1804 if (flavor == PROC_PIDT_BSDINFOWITHUNIQID)
1805 uniqidversion = 1;
1806
1807 if (shortversion != 0) {
1808 error = proc_pidshortbsdinfo(p, &pbsd_short, zombie);
1809 } else {
1810 error = proc_pidbsdinfo(p, &pbsd, zombie);
1811 if (uniqidversion != 0) {
1812 bzero(&pbsd_uniqid, sizeof(pbsd_uniqid));
1813 proc_piduniqidentifierinfo(p, &pbsd_uniqid.p_uniqidentifier);
1814 pbsd_uniqid.pbsd = pbsd;
1815 }
1816 }
1817
1818 if (error == 0) {
1819 if (shortversion != 0) {
1820 error = copyout(&pbsd_short, buffer, sizeof(struct proc_bsdshortinfo));
1821 if (error == 0)
1822 *retval = sizeof(struct proc_bsdshortinfo);
1823 } else if (uniqidversion != 0) {
1824 error = copyout(&pbsd_uniqid, buffer, sizeof(struct proc_bsdinfowithuniqid));
1825 if (error == 0)
1826 *retval = sizeof(struct proc_bsdinfowithuniqid);
1827 } else {
1828 error = copyout(&pbsd, buffer, sizeof(struct proc_bsdinfo));
1829 if (error == 0)
1830 *retval = sizeof(struct proc_bsdinfo);
1831 }
1832 }
1833 }
1834 break;
1835
1836 case PROC_PIDTASKINFO: {
1837 struct proc_taskinfo ptinfo;
1838
1839 error = proc_pidtaskinfo(p, &ptinfo);
1840 if (error == 0) {
1841 error = copyout(&ptinfo, buffer, sizeof(struct proc_taskinfo));
1842 if (error == 0)
1843 *retval = sizeof(struct proc_taskinfo);
1844 }
1845 }
1846 break;
1847
1848 case PROC_PIDTASKALLINFO: {
1849 struct proc_taskallinfo pall;
1850 bzero(&pall, sizeof(pall));
1851 error = proc_pidbsdinfo(p, &pall.pbsd, 0);
1852 error = proc_pidtaskinfo(p, &pall.ptinfo);
1853 if (error == 0) {
1854 error = copyout(&pall, buffer, sizeof(struct proc_taskallinfo));
1855 if (error == 0)
1856 *retval = sizeof(struct proc_taskallinfo);
1857 }
1858 }
1859 break;
1860
1861 case PROC_PIDTHREADID64INFO:
1862 thuniqueid = 1;
1863 case PROC_PIDTHREADINFO:{
1864 struct proc_threadinfo pthinfo;
1865
1866 error = proc_pidthreadinfo(p, arg, thuniqueid, &pthinfo);
1867 if (error == 0) {
1868 error = copyout(&pthinfo, buffer, sizeof(struct proc_threadinfo));
1869 if (error == 0)
1870 *retval = sizeof(struct proc_threadinfo);
1871 }
1872 }
1873 break;
1874
1875 case PROC_PIDLISTTHREADS:{
1876 error = proc_pidlistthreads(p, buffer, buffersize, retval);
1877 }
1878 break;
1879
1880 case PROC_PIDREGIONINFO:{
1881 error = proc_pidregioninfo(p, arg, buffer, buffersize, retval);
1882 }
1883 break;
1884
1885
1886 case PROC_PIDREGIONPATHINFO:{
1887 error = proc_pidregionpathinfo(p, arg, buffer, buffersize, retval);
1888 }
1889 break;
1890
1891 case PROC_PIDREGIONPATHINFO2:{
1892 error = proc_pidregionpathinfo2(p, arg, buffer, buffersize, retval);
1893 }
1894 break;
1895
1896 case PROC_PIDREGIONPATHINFO3:{
1897 error = proc_pidregionpathinfo3(p, arg, buffer, buffersize, retval);
1898 }
1899 break;
1900
1901 case PROC_PIDVNODEPATHINFO:{
1902 error = proc_pidvnodepathinfo(p, arg, buffer, buffersize, retval);
1903 }
1904 break;
1905
1906
1907 case PROC_PIDTHREADPATHINFO:{
1908 struct proc_threadwithpathinfo pinfo;
1909
1910 error = proc_pidthreadpathinfo(p, arg, &pinfo);
1911 if (error == 0) {
1912 error = copyout((caddr_t)&pinfo, buffer, sizeof(struct proc_threadwithpathinfo));
1913 if (error == 0)
1914 *retval = sizeof(struct proc_threadwithpathinfo);
1915 }
1916 }
1917 break;
1918
1919 case PROC_PIDPATHINFO: {
1920 error = proc_pidpathinfo(p, arg, buffer, buffersize, retval);
1921 }
1922 break;
1923
1924
1925 case PROC_PIDWORKQUEUEINFO:{
1926 struct proc_workqueueinfo pwqinfo;
1927
1928 error = proc_pidworkqueueinfo(p, &pwqinfo);
1929 if (error == 0) {
1930 error = copyout(&pwqinfo, buffer, sizeof(struct proc_workqueueinfo));
1931 if (error == 0)
1932 *retval = sizeof(struct proc_workqueueinfo);
1933 }
1934 }
1935 break;
1936
1937 case PROC_PIDLISTFILEPORTS: {
1938 error = proc_pidfileportlist(p, buffer, buffersize, retval);
1939 }
1940 break;
1941
1942 case PROC_PIDARCHINFO: {
1943 struct proc_archinfo pai;
1944 bzero(&pai, sizeof(pai));
1945 proc_archinfo(p, &pai);
1946 error = copyout(&pai, buffer, sizeof(struct proc_archinfo));
1947 if (error == 0) {
1948 *retval = sizeof(struct proc_archinfo);
1949 }
1950 }
1951 break;
1952
1953 case PROC_PIDCOALITIONINFO: {
1954 struct proc_pidcoalitioninfo pci;
1955 proc_pidcoalitioninfo(p, &pci);
1956 error = copyout(&pci, buffer, sizeof(struct proc_pidcoalitioninfo));
1957 if (error == 0) {
1958 *retval = sizeof(struct proc_pidcoalitioninfo);
1959 }
1960 }
1961 break;
1962
1963 case PROC_PIDNOTEEXIT: {
1964 uint32_t data;
1965 error = proc_pidnoteexit(p, arg, &data);
1966 if (error == 0) {
1967 error = copyout(&data, buffer, sizeof(data));
1968 if (error == 0) {
1969 *retval = sizeof(data);
1970 }
1971 }
1972 }
1973 break;
1974
1975 case PROC_PIDEXITREASONINFO: {
1976 struct proc_exitreasoninfo eri;
1977
1978 error = copyin(buffer, &eri, sizeof(eri));
1979 if (error != 0) {
1980 break;
1981 }
1982
1983 error = proc_pidexitreasoninfo(p, &eri, NULL);
1984 if (error == 0) {
1985 error = copyout(&eri, buffer, sizeof(eri));
1986 if (error == 0) {
1987 *retval = sizeof(eri);
1988 }
1989 }
1990 }
1991 break;
1992
1993 case PROC_PIDEXITREASONBASICINFO: {
1994 struct proc_exitreasonbasicinfo beri;
1995
1996 bzero(&beri, sizeof(struct proc_exitreasonbasicinfo));
1997
1998 error = proc_pidexitreasoninfo(p, NULL, &beri);
1999 if (error == 0) {
2000 error = copyout(&beri, buffer, sizeof(beri));
2001 if (error == 0) {
2002 *retval = sizeof(beri);
2003 }
2004 }
2005 }
2006 break;
2007
2008 default:
2009 error = ENOTSUP;
2010 }
2011
2012 out:
2013 if (gotref)
2014 proc_rele(p);
2015 else if (zombie)
2016 proc_drop_zombref(p);
2017 return(error);
2018 }
2019
2020
2021 int
2022 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)
2023 {
2024 struct vnode_fdinfo vfi;
2025 int error= 0;
2026
2027 if ((error = vnode_getwithvid(vp, vid)) != 0) {
2028 return(error);
2029 }
2030 bzero(&vfi, sizeof(struct vnode_fdinfo));
2031 fill_fileinfo(fp, proc, fd, &vfi.pfi);
2032 error = fill_vnodeinfo(vp, &vfi.pvi);
2033 vnode_put(vp);
2034 if (error == 0) {
2035 error = copyout((caddr_t)&vfi, buffer, sizeof(struct vnode_fdinfo));
2036 if (error == 0)
2037 *retval = sizeof(struct vnode_fdinfo);
2038 }
2039 return(error);
2040 }
2041
2042 int
2043 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)
2044 {
2045 struct vnode_fdinfowithpath vfip;
2046 int count, error= 0;
2047
2048 if ((error = vnode_getwithvid(vp, vid)) != 0) {
2049 return(error);
2050 }
2051 bzero(&vfip, sizeof(struct vnode_fdinfowithpath));
2052 fill_fileinfo(fp, proc, fd, &vfip.pfi);
2053 error = fill_vnodeinfo(vp, &vfip.pvip.vip_vi) ;
2054 if (error == 0) {
2055 count = MAXPATHLEN;
2056 vn_getpath(vp, &vfip.pvip.vip_path[0], &count);
2057 vfip.pvip.vip_path[MAXPATHLEN-1] = 0;
2058 vnode_put(vp);
2059 error = copyout((caddr_t)&vfip, buffer, sizeof(struct vnode_fdinfowithpath));
2060 if (error == 0)
2061 *retval = sizeof(struct vnode_fdinfowithpath);
2062 } else
2063 vnode_put(vp);
2064 return(error);
2065 }
2066
2067 void
2068 fill_fileinfo(struct fileproc * fp, proc_t proc, int fd, struct proc_fileinfo * fproc)
2069 {
2070 fproc->fi_openflags = fp->f_fglob->fg_flag;
2071 fproc->fi_status = 0;
2072 fproc->fi_offset = fp->f_fglob->fg_offset;
2073 fproc->fi_type = FILEGLOB_DTYPE(fp->f_fglob);
2074 if (fp->f_fglob->fg_count > 1)
2075 fproc->fi_status |= PROC_FP_SHARED;
2076 if (proc != PROC_NULL) {
2077 if ((FDFLAGS_GET(proc, fd) & UF_EXCLOSE) != 0)
2078 fproc->fi_status |= PROC_FP_CLEXEC;
2079 if ((FDFLAGS_GET(proc, fd) & UF_FORKCLOSE) != 0)
2080 fproc->fi_status |= PROC_FP_CLFORK;
2081 }
2082 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
2083 fproc->fi_status |= PROC_FP_GUARDED;
2084 fproc->fi_guardflags = 0;
2085 if (fp_isguarded(fp, GUARD_CLOSE))
2086 fproc->fi_guardflags |= PROC_FI_GUARD_CLOSE;
2087 if (fp_isguarded(fp, GUARD_DUP))
2088 fproc->fi_guardflags |= PROC_FI_GUARD_DUP;
2089 if (fp_isguarded(fp, GUARD_SOCKET_IPC))
2090 fproc->fi_guardflags |= PROC_FI_GUARD_SOCKET_IPC;
2091 if (fp_isguarded(fp, GUARD_FILEPORT))
2092 fproc->fi_guardflags |= PROC_FI_GUARD_FILEPORT;
2093 }
2094 }
2095
2096
2097
2098 int
2099 fill_vnodeinfo(vnode_t vp, struct vnode_info *vinfo)
2100 {
2101 vfs_context_t context;
2102 struct stat64 sb;
2103 int error = 0;
2104
2105 bzero(&sb, sizeof(struct stat64));
2106 context = vfs_context_create((vfs_context_t)0);
2107 error = vn_stat(vp, &sb, NULL, 1, context);
2108 (void)vfs_context_rele(context);
2109
2110 munge_vinfo_stat(&sb, &vinfo->vi_stat);
2111
2112 if (error != 0)
2113 goto out;
2114
2115 if (vp->v_mount != dead_mountp) {
2116 vinfo->vi_fsid = vp->v_mount->mnt_vfsstat.f_fsid;
2117 } else {
2118 vinfo->vi_fsid.val[0] = 0;
2119 vinfo->vi_fsid.val[1] = 0;
2120 }
2121 vinfo->vi_type = vp->v_type;
2122 out:
2123 return(error);
2124 }
2125
2126 int
2127 pid_socketinfo(socket_t so, struct fileproc *fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2128 {
2129 #if SOCKETS
2130 struct socket_fdinfo s;
2131 int error = 0;
2132
2133 bzero(&s, sizeof(struct socket_fdinfo));
2134 fill_fileinfo(fp, proc, fd, &s.pfi);
2135 if ((error = fill_socketinfo(so, &s.psi)) == 0) {
2136 if ((error = copyout(&s, buffer, sizeof(struct socket_fdinfo))) == 0)
2137 *retval = sizeof(struct socket_fdinfo);
2138 }
2139 return (error);
2140 #else
2141 #pragma unused(so, fp, proc, fd, buffer)
2142 *retval = 0;
2143 return (ENOTSUP);
2144 #endif
2145 }
2146
2147 int
2148 pid_pseminfo(struct psemnode *psem, struct fileproc *fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2149 {
2150 struct psem_fdinfo pseminfo;
2151 int error = 0;
2152
2153 bzero(&pseminfo, sizeof(struct psem_fdinfo));
2154 fill_fileinfo(fp, proc, fd, &pseminfo.pfi);
2155
2156 if ((error = fill_pseminfo(psem, &pseminfo.pseminfo)) == 0) {
2157 if ((error = copyout(&pseminfo, buffer, sizeof(struct psem_fdinfo))) == 0)
2158 *retval = sizeof(struct psem_fdinfo);
2159 }
2160
2161 return(error);
2162 }
2163
2164 int
2165 pid_pshminfo(struct pshmnode *pshm, struct fileproc *fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2166 {
2167 struct pshm_fdinfo pshminfo;
2168 int error = 0;
2169
2170 bzero(&pshminfo, sizeof(struct pshm_fdinfo));
2171 fill_fileinfo(fp, proc, fd, &pshminfo.pfi);
2172
2173 if ((error = fill_pshminfo(pshm, &pshminfo.pshminfo)) == 0) {
2174 if ((error = copyout(&pshminfo, buffer, sizeof(struct pshm_fdinfo))) == 0)
2175 *retval = sizeof(struct pshm_fdinfo);
2176 }
2177
2178 return(error);
2179 }
2180
2181 int
2182 pid_pipeinfo(struct pipe * p, struct fileproc *fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2183 {
2184 struct pipe_fdinfo pipeinfo;
2185 int error = 0;
2186
2187 bzero(&pipeinfo, sizeof(struct pipe_fdinfo));
2188 fill_fileinfo(fp, proc, fd, &pipeinfo.pfi);
2189 if ((error = fill_pipeinfo(p, &pipeinfo.pipeinfo)) == 0) {
2190 if ((error = copyout(&pipeinfo, buffer, sizeof(struct pipe_fdinfo))) == 0)
2191 *retval = sizeof(struct pipe_fdinfo);
2192 }
2193
2194 return(error);
2195 }
2196
2197 int
2198 pid_kqueueinfo(struct kqueue * kq, struct fileproc *fp, proc_t proc, int fd, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2199 {
2200 struct kqueue_fdinfo kqinfo;
2201 int error = 0;
2202
2203 bzero(&kqinfo, sizeof(struct kqueue_fdinfo));
2204
2205 /* not all kq's are associated with a file (e.g. workqkq) */
2206 if (fp) {
2207 assert(fd >= 0);
2208 fill_fileinfo(fp, proc, fd, &kqinfo.pfi);
2209 }
2210
2211 if ((error = fill_kqueueinfo(kq, &kqinfo.kqueueinfo)) == 0) {
2212 if ((error = copyout(&kqinfo, buffer, sizeof(struct kqueue_fdinfo))) == 0)
2213 *retval = sizeof(struct kqueue_fdinfo);
2214 }
2215
2216 return(error);
2217 }
2218
2219 int
2220 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)
2221 {
2222 return ENOTSUP;
2223 }
2224
2225
2226 /************************** proc_pidfdinfo routine ***************************/
2227 int
2228 proc_pidfdinfo(int pid, int flavor, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
2229 {
2230 proc_t p;
2231 int error = ENOTSUP;
2232 struct fileproc * fp = NULL;
2233 uint32_t size;
2234
2235 switch (flavor) {
2236 case PROC_PIDFDVNODEINFO:
2237 size = PROC_PIDFDVNODEINFO_SIZE;
2238 break;
2239 case PROC_PIDFDVNODEPATHINFO:
2240 size = PROC_PIDFDVNODEPATHINFO_SIZE;
2241 break;
2242 case PROC_PIDFDSOCKETINFO:
2243 size = PROC_PIDFDSOCKETINFO_SIZE;
2244 break;
2245 case PROC_PIDFDPSEMINFO:
2246 size = PROC_PIDFDPSEMINFO_SIZE;
2247 break;
2248 case PROC_PIDFDPSHMINFO:
2249 size = PROC_PIDFDPSHMINFO_SIZE;
2250 break;
2251 case PROC_PIDFDPIPEINFO:
2252 size = PROC_PIDFDPIPEINFO_SIZE;
2253 break;
2254 case PROC_PIDFDKQUEUEINFO:
2255 size = PROC_PIDFDKQUEUEINFO_SIZE;
2256 break;
2257 case PROC_PIDFDKQUEUE_EXTINFO:
2258 size = PROC_PIDFDKQUEUE_EXTINFO_SIZE;
2259 if (buffer == (user_addr_t)0)
2260 size = 0;
2261 break;
2262 case PROC_PIDFDATALKINFO:
2263 size = PROC_PIDFDATALKINFO_SIZE;
2264 break;
2265
2266 default:
2267 return(EINVAL);
2268
2269 }
2270
2271 if (buffersize < size)
2272 return(ENOMEM);
2273
2274 if ((p = proc_find(pid)) == PROC_NULL) {
2275 error = ESRCH;
2276 goto out;
2277 }
2278
2279 /* Do we have permission to look into this? */
2280 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDFDINFO, flavor, CHECK_SAME_USER)))
2281 goto out1;
2282
2283 switch (flavor) {
2284 case PROC_PIDFDVNODEINFO: {
2285 vnode_t vp;
2286 uint32_t vid=0;
2287
2288 if ((error = fp_getfvpandvid(p, fd, &fp, &vp, &vid)) !=0) {
2289 goto out1;
2290 }
2291 /* no need to be under the fdlock */
2292 error = pid_vnodeinfo(vp, vid, fp, p, fd, buffer, buffersize, retval);
2293 }
2294 break;
2295
2296 case PROC_PIDFDVNODEPATHINFO: {
2297 vnode_t vp;
2298 uint32_t vid=0;
2299
2300 if ((error = fp_getfvpandvid(p, fd, &fp, &vp, &vid)) !=0) {
2301 goto out1;
2302 }
2303
2304 /* no need to be under the fdlock */
2305 error = pid_vnodeinfopath(vp, vid, fp, p, fd, buffer, buffersize, retval);
2306 }
2307 break;
2308
2309 case PROC_PIDFDSOCKETINFO: {
2310 socket_t so;
2311
2312 if ((error = fp_getfsock(p, fd, &fp, &so)) !=0) {
2313 goto out1;
2314 }
2315 /* no need to be under the fdlock */
2316 error = pid_socketinfo(so, fp, p, fd, buffer, buffersize, retval);
2317 }
2318 break;
2319
2320 case PROC_PIDFDPSEMINFO: {
2321 struct psemnode * psem;
2322
2323 if ((error = fp_getfpsem(p, fd, &fp, &psem)) !=0) {
2324 goto out1;
2325 }
2326 /* no need to be under the fdlock */
2327 error = pid_pseminfo(psem, fp, p, fd, buffer, buffersize, retval);
2328 }
2329 break;
2330
2331 case PROC_PIDFDPSHMINFO: {
2332 struct pshmnode * pshm;
2333
2334 if ((error = fp_getfpshm(p, fd, &fp, &pshm)) !=0) {
2335 goto out1;
2336 }
2337 /* no need to be under the fdlock */
2338 error = pid_pshminfo(pshm, fp, p, fd, buffer, buffersize, retval);
2339 }
2340 break;
2341
2342 case PROC_PIDFDPIPEINFO: {
2343 struct pipe * cpipe;
2344
2345 if ((error = fp_getfpipe(p, fd, &fp, &cpipe)) !=0) {
2346 goto out1;
2347 }
2348 /* no need to be under the fdlock */
2349 error = pid_pipeinfo(cpipe, fp, p, fd, buffer, buffersize, retval);
2350 }
2351 break;
2352
2353 case PROC_PIDFDKQUEUEINFO: {
2354 struct kqueue * kq;
2355
2356 if (fd == -1) {
2357 if ((kq = p->p_wqkqueue) == NULL) {
2358 /* wqkqueue is initialized on-demand */
2359 error = 0;
2360 break;
2361 }
2362 } else if ((error = fp_getfkq(p, fd, &fp, &kq)) != 0) {
2363 goto out1;
2364 }
2365
2366 /* no need to be under the fdlock */
2367 error = pid_kqueueinfo(kq, fp, p, fd, buffer, buffersize, retval);
2368 }
2369 break;
2370
2371 case PROC_PIDFDKQUEUE_EXTINFO: {
2372 struct kqueue * kq;
2373
2374 if (fd == -1) {
2375 if ((kq = p->p_wqkqueue) == NULL) {
2376 /* wqkqueue is initialized on-demand */
2377 error = 0;
2378 break;
2379 }
2380 } else if ((error = fp_getfkq(p, fd, &fp, &kq)) != 0) {
2381 goto out1;
2382 }
2383 error = pid_kqueue_extinfo(p, kq, buffer, buffersize, retval);
2384 }
2385 break;
2386
2387 default: {
2388 error = EINVAL;
2389 goto out1;
2390 }
2391 }
2392
2393 if (fp) {
2394 fp_drop(p, fd, fp , 0);
2395 }
2396 out1 :
2397 proc_rele(p);
2398 out:
2399 return(error);
2400 }
2401
2402 int
2403 proc_listfd_kqueue(proc_t p, int32_t *fdlist, int len)
2404 {
2405 int numfds;
2406 struct fileproc * fp;
2407 int n;
2408 int count = 0;
2409
2410 numfds = p->p_fd->fd_nfiles;
2411 if (len < numfds) {
2412 return -1;
2413 }
2414
2415 proc_fdlock(p);
2416 for (n = 0; ((n < numfds) && (n < p->p_fd->fd_nfiles)); n++) {
2417 if (((fp = p->p_fd->fd_ofiles[n]) != 0)
2418 && ((p->p_fd->fd_ofileflags[n] & UF_RESERVED) == 0)
2419 && (FILEGLOB_DTYPE(fp->f_fglob) == PROX_FDTYPE_KQUEUE)) {
2420 fdlist[count++] = n;
2421 }
2422 }
2423 proc_fdunlock(p);
2424 return count;
2425 }
2426
2427 int
2428 proc_kqueue_udata_info(proc_t p, int32_t fd, uint64_t *buffer, int bufsize)
2429 {
2430 struct kqueue *kq;
2431 struct fileproc * fp = NULL;
2432 int retval;
2433
2434 if (fd == -1) {
2435 /* wqkqueue is initialized on-demand */
2436 if ((kq = p->p_wqkqueue) == NULL) {
2437 return 0;
2438 }
2439 } else {
2440 int error = fp_getfkq(p, fd, &fp, &kq);
2441 if (error != 0) {
2442 return 0;
2443 }
2444 }
2445
2446 retval = pid_kqueue_udatainfo(p, kq, buffer, bufsize);
2447 if (fp) {
2448 fp_drop(p, fd, fp , 0);
2449 }
2450
2451 return retval;
2452 }
2453
2454 int
2455 proc_list_uptrs(proc_t p, uint64_t *udata_buffer, int size)
2456 {
2457 int32_t *fdlist = NULL;
2458 int nfds;
2459 int i;
2460 int count = 0;
2461 int ret;
2462 int knote_max = 4096;
2463 uint64_t *buffer;
2464 int bufsize = knote_max * sizeof(uint64_t);
2465
2466 fdlist = (int32_t *)kalloc((OPEN_MAX + 1) * sizeof(int32_t));
2467 if (!fdlist) {
2468 return -1;
2469 }
2470
2471 nfds = proc_listfd_kqueue(p, &fdlist[1], OPEN_MAX);
2472 if (nfds < 0 || nfds > OPEN_MAX) {
2473 kfree(fdlist, (OPEN_MAX + 1) * sizeof(int32_t));
2474 return 0;
2475 }
2476
2477 /* Add FD -1, the implicit workq kqueue */
2478 fdlist[0] = -1;
2479 nfds++;
2480
2481 if (size == 0) {
2482 bufsize = 0;
2483 buffer = NULL;
2484 } else {
2485 bufsize = knote_max * sizeof(uint64_t);
2486 buffer = (uint64_t *)kalloc(bufsize);
2487 }
2488
2489 for (i = 0; i < nfds; i++) {
2490 again:
2491 ret = proc_kqueue_udata_info(p, fdlist[i], buffer, bufsize);
2492 if (bufsize != 0 && ret > knote_max) {
2493 kfree(buffer, bufsize);
2494 knote_max = ret + 32;
2495 bufsize = knote_max * sizeof(uint64_t);
2496 buffer = kalloc(bufsize);
2497 goto again;
2498 }
2499
2500 if (ret == 0)
2501 continue;
2502
2503 /* Copy the udata ptrs */
2504 if (size >= (int)((count + ret) * sizeof(uint64_t))) {
2505 memcpy(&udata_buffer[count], buffer, ret * sizeof(uint64_t));
2506 }
2507 count = count + ret;
2508 }
2509
2510 kfree(fdlist, (OPEN_MAX + 1) * sizeof(int32_t));
2511 if (buffer) {
2512 kfree(buffer, bufsize);
2513 }
2514 return count;
2515 }
2516
2517 /*
2518 * Helper function for proc_pidfileportinfo
2519 */
2520
2521 struct fileport_info_args {
2522 int fia_flavor;
2523 user_addr_t fia_buffer;
2524 uint32_t fia_buffersize;
2525 int32_t *fia_retval;
2526 };
2527
2528 static kern_return_t
2529 proc_fileport_info(__unused mach_port_name_t name,
2530 struct fileglob *fg, void *arg)
2531 {
2532 struct fileport_info_args *fia = arg;
2533 struct fileproc __fileproc, *fp = &__fileproc;
2534 int error;
2535
2536 bzero(fp, sizeof (*fp));
2537 fp->f_fglob = fg;
2538
2539 switch (fia->fia_flavor) {
2540 case PROC_PIDFILEPORTVNODEPATHINFO: {
2541 vnode_t vp;
2542
2543 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
2544 error = ENOTSUP;
2545 break;
2546 }
2547 vp = (struct vnode *)fg->fg_data;
2548 error = pid_vnodeinfopath(vp, vnode_vid(vp), fp, PROC_NULL, 0,
2549 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
2550 } break;
2551
2552 case PROC_PIDFILEPORTSOCKETINFO: {
2553 socket_t so;
2554
2555 if (FILEGLOB_DTYPE(fg) != DTYPE_SOCKET) {
2556 error = EOPNOTSUPP;
2557 break;
2558 }
2559 so = (socket_t)fg->fg_data;
2560 error = pid_socketinfo(so, fp, PROC_NULL, 0,
2561 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
2562 } break;
2563
2564 case PROC_PIDFILEPORTPSHMINFO: {
2565 struct pshmnode *pshm;
2566
2567 if (FILEGLOB_DTYPE(fg) != DTYPE_PSXSHM) {
2568 error = EBADF; /* ick - mirror fp_getfpshm */
2569 break;
2570 }
2571 pshm = (struct pshmnode *)fg->fg_data;
2572 error = pid_pshminfo(pshm, fp, PROC_NULL, 0,
2573 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
2574 } break;
2575
2576 case PROC_PIDFILEPORTPIPEINFO: {
2577 struct pipe *cpipe;
2578
2579 if (FILEGLOB_DTYPE(fg) != DTYPE_PIPE) {
2580 error = EBADF; /* ick - mirror fp_getfpipe */
2581 break;
2582 }
2583 cpipe = (struct pipe *)fg->fg_data;
2584 error = pid_pipeinfo(cpipe, fp, PROC_NULL, 0,
2585 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
2586 } break;
2587
2588 default:
2589 error = EINVAL;
2590 break;
2591 }
2592
2593 return (error);
2594 }
2595
2596 /************************* proc_pidfileportinfo routine *********************/
2597 int
2598 proc_pidfileportinfo(int pid, int flavor, mach_port_name_t name,
2599 user_addr_t buffer, uint32_t buffersize, int32_t *retval)
2600 {
2601 proc_t p;
2602 int error = ENOTSUP;
2603 uint32_t size;
2604 struct fileport_info_args fia;
2605
2606 /* fileport types are restricted by file_issendable() */
2607
2608 switch (flavor) {
2609 case PROC_PIDFILEPORTVNODEPATHINFO:
2610 size = PROC_PIDFILEPORTVNODEPATHINFO_SIZE;
2611 break;
2612 case PROC_PIDFILEPORTSOCKETINFO:
2613 size = PROC_PIDFILEPORTSOCKETINFO_SIZE;
2614 break;
2615 case PROC_PIDFILEPORTPSHMINFO:
2616 size = PROC_PIDFILEPORTPSHMINFO_SIZE;
2617 break;
2618 case PROC_PIDFILEPORTPIPEINFO:
2619 size = PROC_PIDFILEPORTPIPEINFO_SIZE;
2620 break;
2621 default:
2622 return (EINVAL);
2623 }
2624
2625 if (buffersize < size)
2626 return (ENOMEM);
2627 if ((p = proc_find(pid)) == PROC_NULL) {
2628 error = ESRCH;
2629 goto out;
2630 }
2631
2632 /* Do we have permission to look into this? */
2633 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDFILEPORTINFO, flavor, CHECK_SAME_USER)))
2634 goto out1;
2635
2636 fia.fia_flavor = flavor;
2637 fia.fia_buffer = buffer;
2638 fia.fia_buffersize = buffersize;
2639 fia.fia_retval = retval;
2640
2641 if (fileport_invoke(p->task, name,
2642 proc_fileport_info, &fia, &error) != KERN_SUCCESS)
2643 error = EINVAL;
2644 out1:
2645 proc_rele(p);
2646 out:
2647 return (error);
2648 }
2649
2650 int
2651 proc_security_policy(proc_t targetp, __unused int callnum, __unused int flavor, boolean_t check_same_user)
2652 {
2653 #if CONFIG_MACF
2654 int error = 0;
2655
2656 if ((error = mac_proc_check_proc_info(current_proc(), targetp, callnum, flavor)))
2657 return (error);
2658 #endif
2659
2660 /* The 'listpids' call doesn't have a target proc */
2661 if (targetp == PROC_NULL) {
2662 assert(callnum == PROC_INFO_CALL_LISTPIDS && check_same_user == NO_CHECK_SAME_USER);
2663 return (0);
2664 }
2665
2666 /*
2667 * Check for 'get information for processes owned by other users' privilege
2668 * root has this privilege by default
2669 */
2670 if (priv_check_cred(kauth_cred_get(), PRIV_GLOBAL_PROC_INFO, 0) == 0)
2671 check_same_user = FALSE;
2672
2673 if (check_same_user) {
2674 kauth_cred_t target_cred;
2675 uid_t target_uid;
2676
2677 target_cred = kauth_cred_proc_ref(targetp);
2678 target_uid = kauth_cred_getuid(target_cred);
2679 kauth_cred_unref(&target_cred);
2680
2681 if (kauth_getuid() != target_uid)
2682 return(EPERM);
2683 }
2684
2685 return(0);
2686 }
2687
2688 int
2689 proc_kernmsgbuf(user_addr_t buffer, uint32_t buffersize, int32_t * retval)
2690 {
2691 if (suser(kauth_cred_get(), (u_short *)0) == 0) {
2692 return(log_dmesg(buffer, buffersize, retval));
2693 } else
2694 return(EPERM);
2695 }
2696
2697 /* ********* process control sets on self only */
2698 int
2699 proc_setcontrol(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, __unused int32_t * retval)
2700 {
2701 struct proc * pself = PROC_NULL;
2702 int error = 0;
2703 uint32_t pcontrol = (uint32_t)arg;
2704 struct uthread *ut = NULL;
2705 char name_buf[MAXTHREADNAMESIZE];
2706
2707 pself = current_proc();
2708 if (pid != pself->p_pid)
2709 return(EINVAL);
2710
2711 /* Do we have permission to look into this? */
2712 if ((error = proc_security_policy(pself, PROC_INFO_CALL_SETCONTROL, flavor, NO_CHECK_SAME_USER)))
2713 goto out;
2714
2715 switch (flavor) {
2716 case PROC_SELFSET_PCONTROL: {
2717 if (pcontrol > P_PCMAX)
2718 return(EINVAL);
2719 proc_lock(pself);
2720 /* reset existing control setting while retaining action state */
2721 pself->p_pcaction &= PROC_ACTION_MASK;
2722 /* set new control state */
2723 pself->p_pcaction |= pcontrol;
2724 proc_unlock(pself);
2725 }
2726 break;
2727
2728 case PROC_SELFSET_THREADNAME: {
2729 /*
2730 * This is a bit ugly, as it copies the name into the kernel, and then
2731 * invokes bsd_setthreadname again to copy it into the uthread name
2732 * buffer. Hopefully this isn't such a hot codepath that an additional
2733 * MAXTHREADNAMESIZE copy is a big issue.
2734 */
2735 if (buffersize > (MAXTHREADNAMESIZE - 1)) {
2736 return ENAMETOOLONG;
2737 }
2738
2739 ut = current_uthread();
2740
2741 bzero(name_buf, MAXTHREADNAMESIZE);
2742 error = copyin(buffer, name_buf, buffersize);
2743
2744 if (!error) {
2745 bsd_setthreadname(ut, name_buf);
2746 }
2747 }
2748 break;
2749
2750 case PROC_SELFSET_VMRSRCOWNER: {
2751 /* need to to be superuser */
2752 if (suser(kauth_cred_get(), (u_short *)0) != 0) {
2753 error = EPERM;
2754 goto out;
2755 }
2756
2757 proc_lock(pself);
2758 /* reset existing control setting while retaining action state */
2759 pself->p_lflag |= P_LVMRSRCOWNER;
2760 proc_unlock(pself);
2761 }
2762 break;
2763
2764 case PROC_SELFSET_DELAYIDLESLEEP: {
2765 /* mark or clear the process property to delay idle sleep disk IO */
2766 if (pcontrol != 0)
2767 OSBitOrAtomic(P_DELAYIDLESLEEP, &pself->p_flag);
2768 else
2769 OSBitAndAtomic(~((uint32_t)P_DELAYIDLESLEEP), &pself->p_flag);
2770 }
2771 break;
2772
2773 default:
2774 error = ENOTSUP;
2775 }
2776
2777 out:
2778 return(error);
2779 }
2780
2781 #if CONFIG_MEMORYSTATUS
2782
2783 int
2784 proc_dirtycontrol(int pid, int flavor, uint64_t arg, int32_t *retval) {
2785 struct proc *target_p;
2786 int error = 0;
2787 uint32_t pcontrol = (uint32_t)arg;
2788 kauth_cred_t my_cred, target_cred;
2789 boolean_t self = FALSE;
2790 boolean_t child = FALSE;
2791 boolean_t zombref = FALSE;
2792 pid_t selfpid;
2793
2794 target_p = proc_find(pid);
2795
2796 if (target_p == PROC_NULL) {
2797 if (flavor == PROC_DIRTYCONTROL_GET) {
2798 target_p = proc_find_zombref(pid);
2799 zombref = 1;
2800 }
2801
2802 if (target_p == PROC_NULL)
2803 return(ESRCH);
2804
2805 }
2806
2807 my_cred = kauth_cred_get();
2808 target_cred = kauth_cred_proc_ref(target_p);
2809
2810 /* Do we have permission to look into this? */
2811 if ((error = proc_security_policy(target_p, PROC_INFO_CALL_DIRTYCONTROL, flavor, NO_CHECK_SAME_USER)))
2812 goto out;
2813
2814 selfpid = proc_selfpid();
2815 if (pid == selfpid) {
2816 self = TRUE;
2817 } else if (target_p->p_ppid == selfpid) {
2818 child = TRUE;
2819 }
2820
2821 switch (flavor) {
2822 case PROC_DIRTYCONTROL_TRACK: {
2823 /* Only allow the process itself, its parent, or root */
2824 if ((self == FALSE) && (child == FALSE) && kauth_cred_issuser(kauth_cred_get()) != TRUE) {
2825 error = EPERM;
2826 goto out;
2827 }
2828
2829 error = memorystatus_dirty_track(target_p, pcontrol);
2830 }
2831 break;
2832
2833 case PROC_DIRTYCONTROL_SET: {
2834 /* Check privileges; use cansignal() here since the process could be terminated */
2835 if (!cansignal(current_proc(), my_cred, target_p, SIGKILL, 0)) {
2836 error = EPERM;
2837 goto out;
2838 }
2839
2840 error = memorystatus_dirty_set(target_p, self, pcontrol);
2841 }
2842 break;
2843
2844 case PROC_DIRTYCONTROL_GET: {
2845 /* No permissions check - dirty state is freely available */
2846 if (retval) {
2847 *retval = memorystatus_dirty_get(target_p);
2848 } else {
2849 error = EINVAL;
2850 }
2851 }
2852 break;
2853
2854 case PROC_DIRTYCONTROL_CLEAR: {
2855 /* Check privileges; use cansignal() here since the process could be terminated */
2856 if (!cansignal(current_proc(), my_cred, target_p, SIGKILL, 0)) {
2857 error = EPERM;
2858 goto out;
2859 }
2860
2861 error = memorystatus_dirty_clear(target_p, pcontrol);
2862 }
2863 break;
2864 }
2865
2866 out:
2867 if (zombref)
2868 proc_drop_zombref(target_p);
2869 else
2870 proc_rele(target_p);
2871
2872 kauth_cred_unref(&target_cred);
2873
2874 return(error);
2875 }
2876 #else
2877
2878 int
2879 proc_dirtycontrol(__unused int pid, __unused int flavor, __unused uint64_t arg, __unused int32_t *retval) {
2880 return ENOTSUP;
2881 }
2882
2883 #endif /* CONFIG_MEMORYSTATUS */
2884
2885 /*
2886 * proc_terminate() provides support for sudden termination.
2887 * SIGKILL is issued to tracked, clean processes; otherwise,
2888 * SIGTERM is sent.
2889 */
2890
2891 int
2892 proc_terminate(int pid, int32_t *retval)
2893 {
2894 int error = 0;
2895 proc_t p;
2896 kauth_cred_t uc = kauth_cred_get();
2897 int sig;
2898
2899 #if 0
2900 /* XXX: Check if these are necessary */
2901 AUDIT_ARG(pid, pid);
2902 AUDIT_ARG(signum, sig);
2903 #endif
2904
2905 if (pid <= 0 || retval == NULL) {
2906 return (EINVAL);
2907 }
2908
2909 if ((p = proc_find(pid)) == NULL) {
2910 return (ESRCH);
2911 }
2912
2913 #if 0
2914 /* XXX: Check if these are necessary */
2915 AUDIT_ARG(process, p);
2916 #endif
2917
2918 /* Check privileges; if SIGKILL can be issued, then SIGTERM is also OK */
2919 if (!cansignal(current_proc(), uc, p, SIGKILL, 0)) {
2920 error = EPERM;
2921 goto out;
2922 }
2923
2924 /* Not allowed to sudden terminate yourself */
2925 if (p == current_proc()) {
2926 error = EPERM;
2927 goto out;
2928 }
2929
2930 #if CONFIG_MEMORYSTATUS
2931 /* Determine requisite signal to issue */
2932 sig = memorystatus_on_terminate(p);
2933 #else
2934 sig = SIGTERM;
2935 #endif
2936
2937 proc_set_task_policy(p->task, TASK_POLICY_ATTRIBUTE,
2938 TASK_POLICY_TERMINATED, TASK_POLICY_ENABLE);
2939
2940 psignal(p, sig);
2941 *retval = sig;
2942
2943 out:
2944 proc_rele(p);
2945
2946 return error;
2947 }
2948
2949 /*
2950 * copy stat64 structure into vinfo_stat structure.
2951 */
2952 static void
2953 munge_vinfo_stat(struct stat64 *sbp, struct vinfo_stat *vsbp)
2954 {
2955 bzero(vsbp, sizeof(struct vinfo_stat));
2956
2957 vsbp->vst_dev = sbp->st_dev;
2958 vsbp->vst_mode = sbp->st_mode;
2959 vsbp->vst_nlink = sbp->st_nlink;
2960 vsbp->vst_ino = sbp->st_ino;
2961 vsbp->vst_uid = sbp->st_uid;
2962 vsbp->vst_gid = sbp->st_gid;
2963 vsbp->vst_atime = sbp->st_atimespec.tv_sec;
2964 vsbp->vst_atimensec = sbp->st_atimespec.tv_nsec;
2965 vsbp->vst_mtime = sbp->st_mtimespec.tv_sec;
2966 vsbp->vst_mtimensec = sbp->st_mtimespec.tv_nsec;
2967 vsbp->vst_ctime = sbp->st_ctimespec.tv_sec;
2968 vsbp->vst_ctimensec = sbp->st_ctimespec.tv_nsec;
2969 vsbp->vst_birthtime = sbp->st_birthtimespec.tv_sec;
2970 vsbp->vst_birthtimensec = sbp->st_birthtimespec.tv_nsec;
2971 vsbp->vst_size = sbp->st_size;
2972 vsbp->vst_blocks = sbp->st_blocks;
2973 vsbp->vst_blksize = sbp->st_blksize;
2974 vsbp->vst_flags = sbp->st_flags;
2975 vsbp->vst_gen = sbp->st_gen;
2976 vsbp->vst_rdev = sbp->st_rdev;
2977 vsbp->vst_qspare[0] = sbp->st_qspare[0];
2978 vsbp->vst_qspare[1] = sbp->st_qspare[1];
2979 }
2980
2981 int
2982 proc_pid_rusage(int pid, int flavor, user_addr_t buffer, __unused int32_t *retval)
2983 {
2984 proc_t p;
2985 int error;
2986 int zombie = 0;
2987
2988 if ((p = proc_find(pid)) == PROC_NULL) {
2989 if ((p = proc_find_zombref(pid)) == PROC_NULL) {
2990 return (ESRCH);
2991 }
2992 zombie = 1;
2993 }
2994
2995 /* Do we have permission to look into this? */
2996 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDRUSAGE, flavor, CHECK_SAME_USER)))
2997 goto out;
2998
2999 error = proc_get_rusage(p, flavor, buffer, zombie);
3000
3001 out:
3002 if (zombie)
3003 proc_drop_zombref(p);
3004 else
3005 proc_rele(p);
3006
3007 return (error);
3008 }
3009
3010 void
3011 proc_archinfo(proc_t p, struct proc_archinfo *pai)
3012 {
3013 proc_lock(p);
3014 pai->p_cputype = p->p_cputype;
3015 pai->p_cpusubtype = p->p_cpusubtype;
3016 proc_unlock(p);
3017 }
3018
3019 void
3020 proc_pidcoalitioninfo(proc_t p, struct proc_pidcoalitioninfo *ppci)
3021 {
3022 bzero(ppci, sizeof(*ppci));
3023 proc_coalitionids(p, ppci->coalition_id);
3024 }
3025
3026 int
3027 proc_pidexitreasoninfo(proc_t p, struct proc_exitreasoninfo *peri, struct proc_exitreasonbasicinfo *pberi)
3028 {
3029 uint32_t reason_data_size = 0;
3030 int error = 0;
3031 pid_t selfpid = proc_selfpid();
3032
3033 proc_lock(p);
3034
3035 /*
3036 * One (and only one) of peri and pberi must be non-NULL.
3037 */
3038 assert((peri != NULL) || (pberi != NULL));
3039 assert((peri == NULL) || (pberi == NULL));
3040
3041 /*
3042 * Allow access to the parent of the exiting
3043 * child or the parent debugger only.
3044 */
3045 do {
3046 if (p->p_ppid == selfpid)
3047 break; /* parent => ok */
3048
3049 if ((p->p_lflag & P_LTRACED) != 0 &&
3050 (p->p_oppid == selfpid))
3051 break; /* parent-in-waiting => ok */
3052
3053 proc_unlock(p);
3054 return EACCES;
3055 } while (0);
3056
3057 if (p->p_exit_reason == OS_REASON_NULL) {
3058 proc_unlock(p);
3059 return ENOENT;
3060 }
3061
3062 if (p->p_exit_reason->osr_kcd_buf != NULL) {
3063 reason_data_size = kcdata_memory_get_used_bytes(&p->p_exit_reason->osr_kcd_descriptor);
3064 }
3065
3066 if (peri != NULL) {
3067 peri->eri_namespace = p->p_exit_reason->osr_namespace;
3068 peri->eri_code = p->p_exit_reason->osr_code;
3069 peri->eri_flags = p->p_exit_reason->osr_flags;
3070
3071 if ((peri->eri_kcd_buf == 0) || (peri->eri_reason_buf_size < reason_data_size)) {
3072 proc_unlock(p);
3073 return ENOMEM;
3074 }
3075
3076 peri->eri_reason_buf_size = reason_data_size;
3077 if (reason_data_size != 0) {
3078 error = copyout(p->p_exit_reason->osr_kcd_buf, peri->eri_kcd_buf, reason_data_size);
3079 }
3080 } else {
3081 pberi->beri_namespace = p->p_exit_reason->osr_namespace;
3082 pberi->beri_code = p->p_exit_reason->osr_code;
3083 pberi->beri_flags = p->p_exit_reason->osr_flags;
3084 pberi->beri_reason_buf_size = reason_data_size;
3085 }
3086
3087 proc_unlock(p);
3088
3089 return error;
3090 }
3091
3092 /*
3093 * Wrapper to provide NOTE_EXIT_DETAIL and NOTE_EXITSTATUS
3094 * It mimics the data that is typically captured by the
3095 * EVFILT_PROC, NOTE_EXIT event mechanism.
3096 * See filt_proc() in kern_event.c.
3097 */
3098 int
3099 proc_pidnoteexit(proc_t p, uint64_t flags, uint32_t *data)
3100 {
3101 uint32_t exit_data = 0;
3102 uint32_t exit_flags = (uint32_t)flags;
3103
3104 proc_lock(p);
3105
3106 /*
3107 * Allow access to the parent of the exiting
3108 * child or the parent debugger only.
3109 */
3110 do {
3111 pid_t selfpid = proc_selfpid();
3112
3113 if (p->p_ppid == selfpid)
3114 break; /* parent => ok */
3115
3116 if ((p->p_lflag & P_LTRACED) != 0 &&
3117 (p->p_oppid == selfpid))
3118 break; /* parent-in-waiting => ok */
3119
3120 proc_unlock(p);
3121 return (EACCES);
3122 } while (0);
3123
3124 if ((exit_flags & NOTE_EXITSTATUS) != 0) {
3125 /* The signal and exit status */
3126 exit_data |= (p->p_xstat & NOTE_PDATAMASK);
3127 }
3128
3129 if ((exit_flags & NOTE_EXIT_DETAIL) != 0) {
3130 /* The exit detail */
3131 if ((p->p_lflag & P_LTERM_DECRYPTFAIL) != 0) {
3132 exit_data |= NOTE_EXIT_DECRYPTFAIL;
3133 }
3134
3135 if ((p->p_lflag & P_LTERM_JETSAM) != 0) {
3136 exit_data |= NOTE_EXIT_MEMORY;
3137
3138 switch (p->p_lflag & P_JETSAM_MASK) {
3139 case P_JETSAM_VMPAGESHORTAGE:
3140 exit_data |= NOTE_EXIT_MEMORY_VMPAGESHORTAGE;
3141 break;
3142 case P_JETSAM_VMTHRASHING:
3143 exit_data |= NOTE_EXIT_MEMORY_VMTHRASHING;
3144 break;
3145 case P_JETSAM_FCTHRASHING:
3146 exit_data |= NOTE_EXIT_MEMORY_FCTHRASHING;
3147 break;
3148 case P_JETSAM_VNODE:
3149 exit_data |= NOTE_EXIT_MEMORY_VNODE;
3150 break;
3151 case P_JETSAM_HIWAT:
3152 exit_data |= NOTE_EXIT_MEMORY_HIWAT;
3153 break;
3154 case P_JETSAM_PID:
3155 exit_data |= NOTE_EXIT_MEMORY_PID;
3156 break;
3157 case P_JETSAM_IDLEEXIT:
3158 exit_data |= NOTE_EXIT_MEMORY_IDLE;
3159 break;
3160 }
3161 }
3162
3163 if ((p->p_csflags & CS_KILLED) != 0) {
3164 exit_data |= NOTE_EXIT_CSERROR;
3165 }
3166 }
3167
3168 proc_unlock(p);
3169
3170 *data = exit_data;
3171
3172 return (0);
3173 }
3174