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