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