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