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