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