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