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