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