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