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