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