xref: /xnu-11215.41.3/bsd/kern/proc_info.c (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
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 DEVELOPMENT || DEBUG
1421 					printf("%s : EACCES returned by 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 DEVELOPMENT || DEBUG
1434 						printf("%s : EACCES returned by 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 					} else {
1441 #if DEVELOPMENT || DEBUG
1442 						printf("%s : vnode_lookup for path %s returned error %d\n",
1443 						    __FUNCTION__, buf, error);
1444 #else
1445 						printf("%s : vnode_lookup returned error %d\n",
1446 						    __FUNCTION__, error);
1447 #endif
1448 					}
1449 				}
1450 			}
1451 			vnode_rele_ext(tvp, O_EVTONLY, 0);
1452 		} else {
1453 			error = ESRCH;
1454 		}
1455 	} else {
1456 		error = ESRCH;
1457 	}
1458 	return error;
1459 }
1460 
1461 
1462 int
proc_pidworkqueueinfo(proc_t p,struct proc_workqueueinfo * pwqinfo)1463 proc_pidworkqueueinfo(proc_t p, struct proc_workqueueinfo *pwqinfo)
1464 {
1465 	int error = 0;
1466 
1467 	bzero(pwqinfo, sizeof(struct proc_workqueueinfo));
1468 
1469 	error = fill_procworkqueue(p, pwqinfo);
1470 	if (error) {
1471 		return ESRCH;
1472 	} else {
1473 		return 0;
1474 	}
1475 }
1476 
1477 
1478 void
proc_piduniqidentifierinfo(proc_t p,struct proc_uniqidentifierinfo * p_uniqidinfo)1479 proc_piduniqidentifierinfo(proc_t p, struct proc_uniqidentifierinfo *p_uniqidinfo)
1480 {
1481 	p_uniqidinfo->p_uniqueid = proc_uniqueid(p);
1482 	proc_getexecutableuuid(p, (unsigned char *)&p_uniqidinfo->p_uuid, sizeof(p_uniqidinfo->p_uuid));
1483 	p_uniqidinfo->p_puniqueid = proc_puniqueid(p);
1484 	p_uniqidinfo->p_idversion = proc_pidversion(p);
1485 	p_uniqidinfo->p_reserve2 = 0;
1486 	p_uniqidinfo->p_reserve3 = 0;
1487 	p_uniqidinfo->p_reserve4 = 0;
1488 }
1489 
1490 
1491 static int
proc_piduuidinfo(pid_t pid,uuid_t uuid_buf,uint32_t buffersize)1492 proc_piduuidinfo(pid_t pid, uuid_t uuid_buf, uint32_t buffersize)
1493 {
1494 	struct proc * p = PROC_NULL;
1495 	int zombref = 0;
1496 
1497 	if (buffersize < sizeof(uuid_t)) {
1498 		return EINVAL;
1499 	}
1500 
1501 	if ((p = proc_find(pid)) == PROC_NULL) {
1502 		p = proc_find_zombref(pid);
1503 		zombref = 1;
1504 	}
1505 	if (p == PROC_NULL) {
1506 		return ESRCH;
1507 	}
1508 
1509 	proc_getexecutableuuid(p, (unsigned char *)uuid_buf, buffersize);
1510 
1511 	if (zombref) {
1512 		proc_drop_zombref(p);
1513 	} else {
1514 		proc_rele(p);
1515 	}
1516 
1517 	return 0;
1518 }
1519 
1520 /*
1521  * Function to get the uuid and pid of the originator of the voucher.
1522  */
1523 int
proc_pidoriginatorpid_uuid(uuid_t uuid,uint32_t buffersize,pid_t * pid)1524 proc_pidoriginatorpid_uuid(uuid_t uuid, uint32_t buffersize, pid_t *pid)
1525 {
1526 	pid_t originator_pid;
1527 	kern_return_t kr;
1528 	int error;
1529 
1530 	/*
1531 	 * Get the current voucher origin pid. The pid returned here
1532 	 * might not be valid or may have been recycled.
1533 	 */
1534 	kr = thread_get_current_voucher_origin_pid(&originator_pid);
1535 	/* If errors, convert errors to appropriate format */
1536 	if (kr) {
1537 		if (kr == KERN_INVALID_TASK) {
1538 			error = ESRCH;
1539 		} else if (kr == KERN_INVALID_VALUE) {
1540 			error = ENOATTR;
1541 		} else {
1542 			error = EINVAL;
1543 		}
1544 		return error;
1545 	}
1546 
1547 	*pid = originator_pid;
1548 	error = proc_piduuidinfo(originator_pid, uuid, buffersize);
1549 	return error;
1550 }
1551 
1552 /*
1553  * Function to get the uuid of the originator of the voucher.
1554  */
1555 int
proc_pidoriginatoruuid(uuid_t uuid,uint32_t buffersize)1556 proc_pidoriginatoruuid(uuid_t uuid, uint32_t buffersize)
1557 {
1558 	pid_t originator_pid;
1559 	return proc_pidoriginatorpid_uuid(uuid, buffersize, &originator_pid);
1560 }
1561 
1562 /*
1563  * Function to get the task ipc table size.
1564  */
1565 int
proc_pidipctableinfo(proc_t p,struct proc_ipctableinfo * table_info)1566 proc_pidipctableinfo(proc_t p, struct proc_ipctableinfo *table_info)
1567 {
1568 	task_t task;
1569 	int error = 0;
1570 
1571 	task = proc_task(p);
1572 
1573 	bzero(table_info, sizeof(struct proc_ipctableinfo));
1574 	error = fill_taskipctableinfo(task, &(table_info->table_size), &(table_info->table_free));
1575 
1576 	if (error) {
1577 		error = EINVAL;
1578 	}
1579 
1580 	return error;
1581 }
1582 
1583 int
proc_pidthreadschedinfo(proc_t p,uint64_t arg,struct proc_threadschedinfo * sched_info)1584 proc_pidthreadschedinfo(proc_t p, uint64_t arg, struct proc_threadschedinfo *sched_info)
1585 {
1586 	int error;
1587 	uint64_t const thread_id = (uint64_t)arg;
1588 	task_t const task = proc_task(p);
1589 
1590 	bzero(sched_info, sizeof(*sched_info));
1591 	error = fill_taskthreadschedinfo(task, thread_id, (struct proc_threadschedinfo_internal*)sched_info);
1592 
1593 	if (error != 0) {
1594 		error = EINVAL;
1595 	}
1596 
1597 	return error;
1598 }
1599 
1600 /***************************** proc_pidoriginatorinfo ***************************/
1601 
1602 int
proc_pidoriginatorinfo(int pid,int flavor,user_addr_t buffer,uint32_t buffersize,int32_t * retval)1603 proc_pidoriginatorinfo(int pid, int flavor, user_addr_t buffer, uint32_t  buffersize, int32_t * retval)
1604 {
1605 	int error = ENOTSUP;
1606 	uint32_t size;
1607 
1608 	switch (flavor) {
1609 	case PROC_PIDORIGINATOR_UUID:
1610 		size = PROC_PIDORIGINATOR_UUID_SIZE;
1611 		break;
1612 	case PROC_PIDORIGINATOR_BGSTATE:
1613 		size = PROC_PIDORIGINATOR_BGSTATE_SIZE;
1614 		break;
1615 	case PROC_PIDORIGINATOR_PID_UUID:
1616 		size = PROC_PIDORIGINATOR_PID_UUID_SIZE;
1617 		break;
1618 	default:
1619 		return EINVAL;
1620 	}
1621 
1622 	if (buffersize < size) {
1623 		return ENOMEM;
1624 	}
1625 
1626 	if (pid != 0 && pid != proc_selfpid()) {
1627 		return EINVAL;
1628 	}
1629 
1630 	switch (flavor) {
1631 	case PROC_PIDORIGINATOR_UUID: {
1632 		uuid_t uuid = {};
1633 
1634 		error = proc_pidoriginatoruuid(uuid, sizeof(uuid));
1635 		if (error != 0) {
1636 			goto out;
1637 		}
1638 
1639 		error = copyout(uuid, buffer, size);
1640 		if (error == 0) {
1641 			*retval = size;
1642 		}
1643 	}
1644 	break;
1645 
1646 	case PROC_PIDORIGINATOR_PID_UUID: {
1647 		struct proc_originatorinfo originator_info;
1648 		bzero(&originator_info, sizeof(originator_info));
1649 
1650 		error = proc_pidoriginatorpid_uuid(originator_info.originator_uuid,
1651 		    sizeof(uuid_t), &originator_info.originator_pid);
1652 		if (error != 0) {
1653 			goto out;
1654 		}
1655 
1656 		error = copyout(&originator_info, buffer, size);
1657 		if (error == 0) {
1658 			*retval = size;
1659 		}
1660 	}
1661 	break;
1662 
1663 	case PROC_PIDORIGINATOR_BGSTATE: {
1664 		uint32_t is_backgrounded = 0;
1665 		error = proc_get_originatorbgstate(&is_backgrounded);
1666 		if (error) {
1667 			goto out;
1668 		}
1669 
1670 		error = copyout(&is_backgrounded, buffer, size);
1671 		if (error == 0) {
1672 			*retval = size;
1673 		}
1674 	}
1675 	break;
1676 
1677 	default:
1678 		error = ENOTSUP;
1679 	}
1680 out:
1681 	return error;
1682 }
1683 
1684 /***************************** proc_listcoalitions ***************************/
1685 int
proc_listcoalitions(int flavor,int type,user_addr_t buffer,uint32_t buffersize,int32_t * retval)1686 proc_listcoalitions(int flavor, int type, user_addr_t buffer,
1687     uint32_t buffersize, int32_t *retval)
1688 {
1689 #if CONFIG_COALITIONS
1690 	int error;
1691 	int coal_type;
1692 	size_t elem_size;
1693 	void *coalinfo = NULL;
1694 	size_t k_buffersize = 0;
1695 	size_t copyoutsize = 0;
1696 	size_t ncoals = 0;
1697 	size_t ncoals2 = 0;
1698 
1699 	switch (flavor) {
1700 	case LISTCOALITIONS_ALL_COALS:
1701 		elem_size = LISTCOALITIONS_ALL_COALS_SIZE;
1702 		coal_type = -1;
1703 		break;
1704 	case LISTCOALITIONS_SINGLE_TYPE:
1705 		elem_size = LISTCOALITIONS_SINGLE_TYPE_SIZE;
1706 		coal_type = type;
1707 		break;
1708 	default:
1709 		return EINVAL;
1710 	}
1711 
1712 	ncoals = coalitions_get_list(coal_type, NULL, 0);
1713 
1714 	if (ncoals == 0 || buffer == 0 || buffersize == 0) {
1715 		*retval = (int32_t)(ncoals * elem_size);
1716 		return 0;
1717 	}
1718 
1719 	if (os_mul_overflow(ncoals, elem_size, &k_buffersize)) {
1720 		return ENOMEM;
1721 	}
1722 
1723 	coalinfo = kalloc_data(k_buffersize, Z_WAITOK | Z_ZERO);
1724 	if (!coalinfo) {
1725 		return ENOMEM;
1726 	}
1727 
1728 	ncoals2 = coalitions_get_list(coal_type, coalinfo, ncoals);
1729 
1730 	copyoutsize = MIN(buffersize, MIN(ncoals2, ncoals) * elem_size);
1731 
1732 	if (!(error = copyout(coalinfo, buffer, copyoutsize))) {
1733 		*retval = (int32_t)copyoutsize;
1734 	}
1735 
1736 	kfree_data(coalinfo, k_buffersize);
1737 	return error;
1738 #else
1739 	/* no coalition support */
1740 	(void)flavor;
1741 	(void)type;
1742 	(void)buffer;
1743 	(void)buffersize;
1744 	(void)retval;
1745 	return ENOTSUP;
1746 #endif
1747 }
1748 
1749 
1750 /*************************** proc_can_use_forgeound_hw **************************/
1751 int
proc_can_use_foreground_hw(int pid,user_addr_t u_reason,uint32_t reasonsize,int32_t * retval)1752 proc_can_use_foreground_hw(int pid, user_addr_t u_reason, uint32_t reasonsize, int32_t *retval)
1753 {
1754 	proc_t p = PROC_NULL;
1755 	int error = 0;
1756 	uint32_t reason = PROC_FGHW_ERROR;
1757 	uint32_t isBG = 0;
1758 	task_t task = TASK_NULL;
1759 #if CONFIG_COALITIONS
1760 	coalition_t coal = COALITION_NULL;
1761 #endif
1762 
1763 	*retval = 0;
1764 
1765 	if (pid <= 0) {
1766 		error = EINVAL;
1767 		reason = PROC_FGHW_ERROR;
1768 		goto out;
1769 	}
1770 
1771 	p = proc_find(pid);
1772 	if (p == PROC_NULL) {
1773 		error = ESRCH;
1774 		reason = PROC_FGHW_ERROR;
1775 		goto out;
1776 	}
1777 
1778 #if CONFIG_COALITIONS
1779 	if (p != current_proc() &&
1780 	    !kauth_cred_issuser(kauth_cred_get())) {
1781 		error = EPERM;
1782 		reason = PROC_FGHW_ERROR;
1783 		goto out;
1784 	}
1785 
1786 	task = proc_task(p);
1787 	if (coalition_is_leader(task, task_get_coalition(task, COALITION_TYPE_JETSAM))) {
1788 		task_reference(task);
1789 	} else {
1790 		/* current task is not a coalition leader: find the leader */
1791 		task = coalition_get_leader(coal);
1792 	}
1793 
1794 	if (task != TASK_NULL) {
1795 		/*
1796 		 * If task is non-null, then it is the coalition leader of the
1797 		 * current process' coalition. This could be the same task as
1798 		 * the current_task, and that's OK.
1799 		 */
1800 		uint32_t flags = 0;
1801 		int role;
1802 
1803 		proc_get_darwinbgstate(task, &flags);
1804 		if ((flags & PROC_FLAG_APPLICATION) != PROC_FLAG_APPLICATION) {
1805 			/*
1806 			 * Coalition leader is not an application, continue
1807 			 * searching for other ways this task could gain
1808 			 * access to HW
1809 			 */
1810 			reason = PROC_FGHW_DAEMON_LEADER;
1811 			goto no_leader;
1812 		}
1813 
1814 		if (proc_get_effective_task_policy(task, TASK_POLICY_DARWIN_BG)) {
1815 			/*
1816 			 * If the leader of the current process' coalition has
1817 			 * been marked as DARWIN_BG, then it definitely should
1818 			 * not be using foreground hardware resources.
1819 			 */
1820 			reason = PROC_FGHW_LEADER_BACKGROUND;
1821 			goto out;
1822 		}
1823 
1824 		role = proc_get_effective_task_policy(task, TASK_POLICY_ROLE);
1825 		switch (role) {
1826 		case TASK_FOREGROUND_APPLICATION: /* DARWIN_ROLE_UI_FOCAL */
1827 		case TASK_BACKGROUND_APPLICATION: /* DARWIN_ROLE_UI */
1828 			/*
1829 			 * The leader of this coalition is a focal, UI app:
1830 			 * access granted
1831 			 * TODO: should extensions/plugins be allowed to use
1832 			 *       this hardware?
1833 			 */
1834 			*retval = 1;
1835 			reason = PROC_FGHW_OK;
1836 			goto out;
1837 		case TASK_DEFAULT_APPLICATION: /* DARWIN_ROLE_UI_NON_FOCAL */
1838 		case TASK_NONUI_APPLICATION: /* DARWIN_ROLE_NON_UI */
1839 		case TASK_THROTTLE_APPLICATION:
1840 		case TASK_UNSPECIFIED:
1841 		default:
1842 			/* non-focal, non-ui apps don't get access */
1843 			reason = PROC_FGHW_LEADER_NONUI;
1844 			goto out;
1845 		}
1846 	}
1847 
1848 no_leader:
1849 	if (task != TASK_NULL) {
1850 		task_deallocate(task);
1851 		task = TASK_NULL;
1852 	}
1853 #endif /* CONFIG_COALITIONS */
1854 
1855 	/*
1856 	 * There is no reasonable semantic to investigate the currently
1857 	 * adopted voucher of an arbitrary thread in a non-current process.
1858 	 * We return '0'
1859 	 */
1860 	if (p != current_proc()) {
1861 		error = EINVAL;
1862 		goto out;
1863 	}
1864 
1865 	/*
1866 	 * In the absence of coalitions, fall back to a voucher-based lookup
1867 	 * where a daemon can used foreground HW if it's operating on behalf
1868 	 * of a foreground application.
1869 	 * NOTE: this is equivalent to a call to
1870 	 *       proc_pidoriginatorinfo(PROC_PIDORIGINATOR_BGSTATE, &isBG, sizeof(isBG))
1871 	 */
1872 	isBG = 1;
1873 	error = proc_get_originatorbgstate(&isBG);
1874 	switch (error) {
1875 	case 0:
1876 		break;
1877 	case ESRCH:
1878 		reason = PROC_FGHW_NO_ORIGINATOR;
1879 		error = 0;
1880 		goto out;
1881 	case ENOATTR:
1882 		reason = PROC_FGHW_NO_VOUCHER_ATTR;
1883 		error = 0;
1884 		goto out;
1885 	case EINVAL:
1886 		reason = PROC_FGHW_DAEMON_NO_VOUCHER;
1887 		error = 0;
1888 		goto out;
1889 	default:
1890 		/* some other error occurred: report that to the caller */
1891 		reason = PROC_FGHW_VOUCHER_ERROR;
1892 		goto out;
1893 	}
1894 
1895 	if (isBG) {
1896 		reason = PROC_FGHW_ORIGINATOR_BACKGROUND;
1897 		error = 0;
1898 	} else {
1899 		/*
1900 		 * The process itself is either a foreground app, or has
1901 		 * adopted a voucher originating from an app that's still in
1902 		 * the foreground
1903 		 */
1904 		reason = PROC_FGHW_DAEMON_OK;
1905 		*retval = 1;
1906 	}
1907 
1908 out:
1909 	if (task != TASK_NULL) {
1910 		task_deallocate(task);
1911 	}
1912 	if (p != PROC_NULL) {
1913 		proc_rele(p);
1914 	}
1915 	if (reasonsize >= sizeof(reason) && u_reason != (user_addr_t)0) {
1916 		(void)copyout(&reason, u_reason, sizeof(reason));
1917 	}
1918 	return error;
1919 }
1920 
1921 #ifndef MIN_TO_SEC
1922 #define MIN_TO_SEC(x) ((x) * 60)
1923 #endif
1924 /**
1925  * Send a crash report for unpermitted proc_pidinfo calls on the kernel pid.
1926  * Throttles to one report every 10 minutes.
1927  */
1928 static void __attribute__((noinline))
PROC_UNPERMITTED_PIDINFO_FLAVOR(void)1929 PROC_UNPERMITTED_PIDINFO_FLAVOR(void)
1930 {
1931 	static clock_sec_t before = 0;
1932 	clock_sec_t     now;
1933 	clock_nsec_t    nsec;
1934 	mach_exception_data_type_t code[EXCEPTION_CODE_MAX] = {0};
1935 
1936 	clock_get_system_nanotime(&now, &nsec);
1937 
1938 	/**
1939 	 * This can race, and if it does, it means a crash report was very recently
1940 	 * sent in another thread, so return early.
1941 	 */
1942 	if (now < before) {
1943 		return;
1944 	}
1945 
1946 	/**
1947 	 * If 10 minutes have not passed since the last time we sent a crash report,
1948 	 * do nothing.
1949 	 */
1950 	if ((now - before) < MIN_TO_SEC(10)) {
1951 		return;
1952 	}
1953 
1954 	before = now;
1955 
1956 	/* We're rejecting the proc_info syscall */
1957 	EXC_GUARD_ENCODE_TYPE(code[0], GUARD_TYPE_REJECTED_SC);
1958 	code[1] = SYS_proc_info;
1959 	task_enqueue_exception_with_corpse(current_task(), EXC_GUARD, code, EXCEPTION_CODE_MAX, NULL, TRUE);
1960 }
1961 
1962 /********************************** proc_pidinfo ********************************/
1963 
1964 
1965 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)1966 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)
1967 {
1968 	struct proc * p = PROC_NULL;
1969 	int error = ENOTSUP;
1970 	int gotref = 0;
1971 	int findzomb = 0;
1972 	int shortversion = 0;
1973 	uint32_t size;
1974 	int zombie = 0;
1975 	bool thuniqueid = false;
1976 	int uniqidversion = 0;
1977 	bool check_same_user;
1978 	pid_t current_pid = proc_pid(current_proc());
1979 
1980 	/**
1981 	 * Before we move forward, we should check if an unpermitted operation is
1982 	 * attempted on the kernel task.
1983 	 */
1984 	if (pid == 0) {
1985 		switch (flavor) {
1986 		case PROC_PIDWORKQUEUEINFO:
1987 			/* kernel does not have workq info */
1988 			return EINVAL;
1989 		case PROC_PIDREGIONPATH:
1990 		case PROC_PIDREGIONINFO:
1991 		case PROC_PIDREGIONPATHINFO:
1992 		case PROC_PIDREGIONPATHINFO2:
1993 		case PROC_PIDREGIONPATHINFO3:
1994 			/* This operation is not permitted on the kernel */
1995 			if (current_pid != pid) {
1996 				PROC_UNPERMITTED_PIDINFO_FLAVOR();
1997 				return EPERM;
1998 			}
1999 			break;
2000 		}
2001 	}
2002 
2003 	switch (flavor) {
2004 	case PROC_PIDLISTFDS:
2005 		size = PROC_PIDLISTFD_SIZE;
2006 		if (buffer == USER_ADDR_NULL) {
2007 			size = 0;
2008 		}
2009 		break;
2010 	case PROC_PIDTBSDINFO:
2011 		size = PROC_PIDTBSDINFO_SIZE;
2012 		break;
2013 	case PROC_PIDTASKINFO:
2014 		size = PROC_PIDTASKINFO_SIZE;
2015 		break;
2016 	case PROC_PIDTASKALLINFO:
2017 		size = PROC_PIDTASKALLINFO_SIZE;
2018 		break;
2019 	case PROC_PIDTHREADINFO:
2020 		size = PROC_PIDTHREADINFO_SIZE;
2021 		break;
2022 	case PROC_PIDTHREADCOUNTS:
2023 		size = PROC_PIDTHREADCOUNTS_SIZE;
2024 		break;
2025 	case PROC_PIDLISTTHREADIDS:
2026 		size = PROC_PIDLISTTHREADIDS_SIZE;
2027 		break;
2028 	case PROC_PIDLISTTHREADS:
2029 		size = PROC_PIDLISTTHREADS_SIZE;
2030 		break;
2031 	case PROC_PIDREGIONINFO:
2032 		size = PROC_PIDREGIONINFO_SIZE;
2033 		break;
2034 	case PROC_PIDREGIONPATHINFO:
2035 		size = PROC_PIDREGIONPATHINFO_SIZE;
2036 		break;
2037 	case PROC_PIDVNODEPATHINFO:
2038 		size = PROC_PIDVNODEPATHINFO_SIZE;
2039 		break;
2040 	case PROC_PIDTHREADPATHINFO:
2041 		size = PROC_PIDTHREADPATHINFO_SIZE;
2042 		break;
2043 	case PROC_PIDPATHINFO:
2044 		size = MAXPATHLEN;
2045 		break;
2046 	case PROC_PIDWORKQUEUEINFO:
2047 		size = PROC_PIDWORKQUEUEINFO_SIZE;
2048 		break;
2049 	case PROC_PIDT_SHORTBSDINFO:
2050 		size = PROC_PIDT_SHORTBSDINFO_SIZE;
2051 		break;
2052 	case PROC_PIDLISTFILEPORTS:
2053 		size = PROC_PIDLISTFILEPORTS_SIZE;
2054 		if (buffer == (user_addr_t)0) {
2055 			size = 0;
2056 		}
2057 		break;
2058 	case PROC_PIDTHREADID64INFO:
2059 		size = PROC_PIDTHREADID64INFO_SIZE;
2060 		break;
2061 	case PROC_PIDUNIQIDENTIFIERINFO:
2062 		size = PROC_PIDUNIQIDENTIFIERINFO_SIZE;
2063 		break;
2064 	case PROC_PIDT_BSDINFOWITHUNIQID:
2065 		size = PROC_PIDT_BSDINFOWITHUNIQID_SIZE;
2066 		break;
2067 	case PROC_PIDARCHINFO:
2068 		size = PROC_PIDARCHINFO_SIZE;
2069 		break;
2070 	case PROC_PIDCOALITIONINFO:
2071 		size = PROC_PIDCOALITIONINFO_SIZE;
2072 		break;
2073 	case PROC_PIDNOTEEXIT:
2074 		/*
2075 		 * Set findzomb explicitly because arg passed
2076 		 * in is used as note exit status bits.
2077 		 */
2078 		size = PROC_PIDNOTEEXIT_SIZE;
2079 		findzomb = 1;
2080 		break;
2081 	case PROC_PIDEXITREASONINFO:
2082 		size = PROC_PIDEXITREASONINFO_SIZE;
2083 		findzomb = 1;
2084 		break;
2085 	case PROC_PIDEXITREASONBASICINFO:
2086 		size = PROC_PIDEXITREASONBASICINFOSIZE;
2087 		findzomb = 1;
2088 		break;
2089 	case PROC_PIDREGIONPATHINFO2:
2090 		size = PROC_PIDREGIONPATHINFO2_SIZE;
2091 		break;
2092 	case PROC_PIDREGIONPATHINFO3:
2093 		size = PROC_PIDREGIONPATHINFO3_SIZE;
2094 		break;
2095 	case PROC_PIDLISTUPTRS:
2096 		size = PROC_PIDLISTUPTRS_SIZE;
2097 		if (buffer == USER_ADDR_NULL) {
2098 			size = 0;
2099 		}
2100 		break;
2101 	case PROC_PIDLISTDYNKQUEUES:
2102 		size = PROC_PIDLISTDYNKQUEUES_SIZE;
2103 		if (buffer == USER_ADDR_NULL) {
2104 			size = 0;
2105 		}
2106 		break;
2107 	case PROC_PIDVMRTFAULTINFO:
2108 		size = sizeof(vm_rtfault_record_t);
2109 		if (buffer == USER_ADDR_NULL) {
2110 			size = 0;
2111 		}
2112 		break;
2113 	case PROC_PIDPLATFORMINFO:
2114 		size = PROC_PIDPLATFORMINFO_SIZE;
2115 		findzomb = 1;
2116 		break;
2117 	case PROC_PIDREGIONPATH:
2118 		size = PROC_PIDREGIONPATH_SIZE;
2119 		break;
2120 	case PROC_PIDIPCTABLEINFO:
2121 		size = PROC_PIDIPCTABLEINFO_SIZE;
2122 		break;
2123 	case PROC_PIDTHREADSCHEDINFO:
2124 		size = PROC_PIDTHREADSCHEDINFO_SIZE;
2125 		break;
2126 	default:
2127 		return EINVAL;
2128 	}
2129 
2130 	if (buffersize < size) {
2131 		return ENOMEM;
2132 	}
2133 
2134 	if ((flavor == PROC_PIDPATHINFO) && (buffersize > PROC_PIDPATHINFO_MAXSIZE)) {
2135 		return EOVERFLOW;
2136 	}
2137 
2138 	/* Check if we need to look for zombies */
2139 	if ((flavor == PROC_PIDTBSDINFO) || (flavor == PROC_PIDT_SHORTBSDINFO) || (flavor == PROC_PIDT_BSDINFOWITHUNIQID)
2140 	    || (flavor == PROC_PIDUNIQIDENTIFIERINFO)) {
2141 		if (arg) {
2142 			findzomb = 1;
2143 		}
2144 	}
2145 
2146 	if ((p = proc_find(pid)) == PROC_NULL) {
2147 		if (findzomb) {
2148 			p = proc_find_zombref(pid);
2149 		}
2150 		if (p == PROC_NULL) {
2151 			error = ESRCH;
2152 			goto out;
2153 		}
2154 		zombie = 1;
2155 	} else {
2156 		gotref = 1;
2157 	}
2158 
2159 	if ((flags & PIF_COMPARE_IDVERSION) && (ext_id != proc_pidversion(p))) {
2160 		error = ESRCH;
2161 		goto out;
2162 	}
2163 	if ((flags & PIF_COMPARE_UNIQUEID) && (ext_id != proc_uniqueid(p))) {
2164 		error = ESRCH;
2165 		goto out;
2166 	}
2167 
2168 	/* Certain operations don't require privileges */
2169 	switch (flavor) {
2170 	case PROC_PIDT_SHORTBSDINFO:
2171 	case PROC_PIDUNIQIDENTIFIERINFO:
2172 	case PROC_PIDPATHINFO:
2173 	case PROC_PIDCOALITIONINFO:
2174 	case PROC_PIDPLATFORMINFO:
2175 		check_same_user = NO_CHECK_SAME_USER;
2176 		break;
2177 	default:
2178 		check_same_user = CHECK_SAME_USER;
2179 		break;
2180 	}
2181 
2182 	/* Do we have permission to look into this? */
2183 	if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDINFO, flavor, check_same_user))) {
2184 		goto out;
2185 	}
2186 
2187 	switch (flavor) {
2188 	case PROC_PIDLISTFDS: {
2189 		error = proc_pidfdlist(p, buffer, buffersize, retval);
2190 	}
2191 	break;
2192 
2193 	case PROC_PIDUNIQIDENTIFIERINFO: {
2194 		struct proc_uniqidentifierinfo p_uniqidinfo;
2195 		bzero(&p_uniqidinfo, sizeof(p_uniqidinfo));
2196 		proc_piduniqidentifierinfo(p, &p_uniqidinfo);
2197 		error = copyout(&p_uniqidinfo, buffer, sizeof(struct proc_uniqidentifierinfo));
2198 		if (error == 0) {
2199 			*retval = sizeof(struct proc_uniqidentifierinfo);
2200 		}
2201 	}
2202 	break;
2203 
2204 	case PROC_PIDT_SHORTBSDINFO:
2205 		shortversion = 1;
2206 		OS_FALLTHROUGH;
2207 	case PROC_PIDT_BSDINFOWITHUNIQID:
2208 	case PROC_PIDTBSDINFO: {
2209 		struct proc_bsdinfo pbsd;
2210 		struct proc_bsdshortinfo pbsd_short;
2211 		struct proc_bsdinfowithuniqid pbsd_uniqid;
2212 
2213 		if (flavor == PROC_PIDT_BSDINFOWITHUNIQID) {
2214 			uniqidversion = 1;
2215 		}
2216 
2217 		if (shortversion != 0) {
2218 			error = proc_pidshortbsdinfo(p, &pbsd_short, zombie);
2219 		} else {
2220 			error = proc_pidbsdinfo(p, &pbsd, zombie);
2221 			if (uniqidversion != 0) {
2222 				bzero(&pbsd_uniqid, sizeof(pbsd_uniqid));
2223 				proc_piduniqidentifierinfo(p, &pbsd_uniqid.p_uniqidentifier);
2224 				pbsd_uniqid.pbsd = pbsd;
2225 			}
2226 		}
2227 
2228 		if (error == 0) {
2229 			if (shortversion != 0) {
2230 				error = copyout(&pbsd_short, buffer, sizeof(struct proc_bsdshortinfo));
2231 				if (error == 0) {
2232 					*retval = sizeof(struct proc_bsdshortinfo);
2233 				}
2234 			} else if (uniqidversion != 0) {
2235 				error = copyout(&pbsd_uniqid, buffer, sizeof(struct proc_bsdinfowithuniqid));
2236 				if (error == 0) {
2237 					*retval = sizeof(struct proc_bsdinfowithuniqid);
2238 				}
2239 			} else {
2240 				error = copyout(&pbsd, buffer, sizeof(struct proc_bsdinfo));
2241 				if (error == 0) {
2242 					*retval = sizeof(struct proc_bsdinfo);
2243 				}
2244 			}
2245 		}
2246 	}
2247 	break;
2248 
2249 	case PROC_PIDTASKINFO: {
2250 		struct proc_taskinfo ptinfo;
2251 
2252 		error =  proc_pidtaskinfo(p, &ptinfo);
2253 		if (error == 0) {
2254 			error = copyout(&ptinfo, buffer, sizeof(struct proc_taskinfo));
2255 			if (error == 0) {
2256 				*retval = sizeof(struct proc_taskinfo);
2257 			}
2258 		}
2259 	}
2260 	break;
2261 
2262 	case PROC_PIDTASKALLINFO: {
2263 		struct proc_taskallinfo pall;
2264 		bzero(&pall, sizeof(pall));
2265 		error = proc_pidbsdinfo(p, &pall.pbsd, 0);
2266 		error =  proc_pidtaskinfo(p, &pall.ptinfo);
2267 		if (error == 0) {
2268 			error = copyout(&pall, buffer, sizeof(struct proc_taskallinfo));
2269 			if (error == 0) {
2270 				*retval = sizeof(struct proc_taskallinfo);
2271 			}
2272 		}
2273 	}
2274 	break;
2275 
2276 	case PROC_PIDTHREADID64INFO:
2277 		thuniqueid = true;
2278 		OS_FALLTHROUGH;
2279 	case PROC_PIDTHREADINFO:{
2280 		struct proc_threadinfo pthinfo;
2281 
2282 		error  = proc_pidthreadinfo(p, arg, thuniqueid, &pthinfo);
2283 		if (error == 0) {
2284 			error = copyout(&pthinfo, buffer, sizeof(struct proc_threadinfo));
2285 			if (error == 0) {
2286 				*retval = sizeof(struct proc_threadinfo);
2287 			}
2288 		}
2289 	}
2290 	break;
2291 	case PROC_PIDTHREADCOUNTS: {
2292 		error = proc_pidthreadcounts(p, arg, buffer, buffersize, retval);
2293 	}
2294 	break;
2295 
2296 	case PROC_PIDLISTTHREADIDS:
2297 		thuniqueid = true;
2298 		OS_FALLTHROUGH;
2299 	case PROC_PIDLISTTHREADS:{
2300 		error =  proc_pidlistthreads(p, thuniqueid, buffer, buffersize, retval);
2301 	}
2302 	break;
2303 
2304 	case PROC_PIDREGIONINFO:{
2305 		error =  proc_pidregioninfo(p, arg, buffer, buffersize, retval);
2306 	}
2307 	break;
2308 
2309 
2310 	case PROC_PIDREGIONPATHINFO:{
2311 		error =  proc_pidregionpathinfo(p, arg, buffer, buffersize, retval);
2312 	}
2313 	break;
2314 
2315 	case PROC_PIDREGIONPATHINFO2:{
2316 		error =  proc_pidregionpathinfo2(p, arg, buffer, buffersize, retval);
2317 	}
2318 	break;
2319 
2320 	case PROC_PIDREGIONPATHINFO3:{
2321 		error =  proc_pidregionpathinfo3(p, arg, buffer, buffersize, retval);
2322 	}
2323 	break;
2324 
2325 	case PROC_PIDVNODEPATHINFO:{
2326 		error =  proc_pidvnodepathinfo(p, arg, buffer, buffersize, retval);
2327 	}
2328 	break;
2329 
2330 
2331 	case PROC_PIDTHREADPATHINFO:{
2332 		struct proc_threadwithpathinfo pinfo;
2333 
2334 		error  = proc_pidthreadpathinfo(p, arg, &pinfo);
2335 		if (error == 0) {
2336 			error = copyout((caddr_t)&pinfo, buffer, sizeof(struct proc_threadwithpathinfo));
2337 			if (error == 0) {
2338 				*retval = sizeof(struct proc_threadwithpathinfo);
2339 			}
2340 		}
2341 	}
2342 	break;
2343 
2344 	case PROC_PIDPATHINFO: {
2345 		error =  proc_pidpathinfo(p, arg, buffer, buffersize, retval);
2346 	}
2347 	break;
2348 
2349 
2350 	case PROC_PIDWORKQUEUEINFO:{
2351 		struct proc_workqueueinfo pwqinfo;
2352 
2353 		error  = proc_pidworkqueueinfo(p, &pwqinfo);
2354 		if (error == 0) {
2355 			error = copyout(&pwqinfo, buffer, sizeof(struct proc_workqueueinfo));
2356 			if (error == 0) {
2357 				*retval = sizeof(struct proc_workqueueinfo);
2358 			}
2359 		}
2360 	}
2361 	break;
2362 
2363 	case PROC_PIDLISTFILEPORTS: {
2364 		error = proc_pidfileportlist(p, buffer, buffersize, retval);
2365 	}
2366 	break;
2367 
2368 	case PROC_PIDARCHINFO: {
2369 		struct proc_archinfo pai;
2370 		bzero(&pai, sizeof(pai));
2371 		proc_archinfo(p, &pai);
2372 		error = copyout(&pai, buffer, sizeof(struct proc_archinfo));
2373 		if (error == 0) {
2374 			*retval = sizeof(struct proc_archinfo);
2375 		}
2376 	}
2377 	break;
2378 
2379 	case PROC_PIDCOALITIONINFO: {
2380 		struct proc_pidcoalitioninfo pci;
2381 		proc_pidcoalitioninfo(p, &pci);
2382 		error = copyout(&pci, buffer, sizeof(struct proc_pidcoalitioninfo));
2383 		if (error == 0) {
2384 			*retval = sizeof(struct proc_pidcoalitioninfo);
2385 		}
2386 	}
2387 	break;
2388 
2389 	case PROC_PIDNOTEEXIT: {
2390 		uint32_t data;
2391 		error = proc_pidnoteexit(p, arg, &data);
2392 		if (error == 0) {
2393 			error = copyout(&data, buffer, sizeof(data));
2394 			if (error == 0) {
2395 				*retval = sizeof(data);
2396 			}
2397 		}
2398 	}
2399 	break;
2400 
2401 	case PROC_PIDEXITREASONINFO: {
2402 		struct proc_exitreasoninfo eri;
2403 
2404 		error = copyin(buffer, &eri, sizeof(eri));
2405 		if (error != 0) {
2406 			break;
2407 		}
2408 
2409 		error = proc_pidexitreasoninfo(p, &eri, NULL);
2410 		if (error == 0) {
2411 			error = copyout(&eri, buffer, sizeof(eri));
2412 			if (error == 0) {
2413 				*retval =  sizeof(eri);
2414 			}
2415 		}
2416 	}
2417 	break;
2418 
2419 	case PROC_PIDEXITREASONBASICINFO: {
2420 		struct proc_exitreasonbasicinfo beri;
2421 
2422 		bzero(&beri, sizeof(struct proc_exitreasonbasicinfo));
2423 
2424 		error = proc_pidexitreasoninfo(p, NULL, &beri);
2425 		if (error == 0) {
2426 			error = copyout(&beri, buffer, sizeof(beri));
2427 			if (error == 0) {
2428 				*retval =  sizeof(beri);
2429 			}
2430 		}
2431 	}
2432 	break;
2433 
2434 	case PROC_PIDLISTUPTRS:
2435 		error = proc_pidlistuptrs(p, buffer, buffersize, retval);
2436 		break;
2437 
2438 	case PROC_PIDLISTDYNKQUEUES:
2439 		error = kevent_copyout_proc_dynkqids(p, buffer, buffersize, retval);
2440 		break;
2441 	case PROC_PIDVMRTFAULTINFO: {
2442 		/* This interface can only be employed on the current
2443 		 * process. We will eventually enforce an entitlement.
2444 		 */
2445 		*retval = 0;
2446 
2447 		if (p != current_proc()) {
2448 			error = EINVAL;
2449 			break;
2450 		}
2451 
2452 		size_t kbufsz = MIN(buffersize, vmrtfaultinfo_bufsz());
2453 		void *vmrtfbuf = kalloc_data(kbufsz, Z_WAITOK | Z_ZERO);
2454 
2455 		if (vmrtfbuf == NULL) {
2456 			error = ENOMEM;
2457 			break;
2458 		}
2459 
2460 		uint64_t effpid = get_current_unique_pid();
2461 		/* The VM may choose to provide more comprehensive records
2462 		 * for root-privileged users on internal configurations.
2463 		 */
2464 		boolean_t isroot = (suser(kauth_cred_get(), (u_short *)0) == 0);
2465 		size_t num_extracted = 0;
2466 		int vmf_residue = vmrtf_extract(effpid, isroot, kbufsz, vmrtfbuf, &num_extracted);
2467 		size_t vmfsz = num_extracted * sizeof(vm_rtfault_record_t);
2468 
2469 		*retval = (int32_t)MIN(num_extracted, INT32_MAX);
2470 
2471 		error = 0;
2472 		if (vmfsz) {
2473 			error = copyout(vmrtfbuf, buffer, vmfsz);
2474 		}
2475 
2476 		if (error == 0) {
2477 			if (vmf_residue) {
2478 				error = ENOMEM;
2479 			}
2480 		}
2481 		kfree_data(vmrtfbuf, kbufsz);
2482 	}
2483 	break;
2484 	case PROC_PIDPLATFORMINFO: {
2485 		proc_lock(p);
2486 		uint32_t platform = proc_platform(p);
2487 		proc_unlock(p);
2488 		error = copyout(&platform, buffer, sizeof(uint32_t));
2489 		if (error == 0) {
2490 			*retval = sizeof(uint32_t);
2491 		}
2492 	} break;
2493 	case PROC_PIDREGIONPATH: {
2494 		error = proc_pidregionpath(p, arg, buffer, buffersize, retval);
2495 	}
2496 	break;
2497 	case PROC_PIDIPCTABLEINFO: {
2498 		struct proc_ipctableinfo table_info;
2499 
2500 		error = proc_pidipctableinfo(p, &table_info);
2501 		if (error == 0) {
2502 			error = copyout(&table_info, buffer, sizeof(struct proc_ipctableinfo));
2503 			if (error == 0) {
2504 				*retval = sizeof(struct proc_ipctableinfo);
2505 			}
2506 		}
2507 	}
2508 	break;
2509 	case PROC_PIDTHREADSCHEDINFO: {
2510 		struct proc_threadschedinfo sched_info;
2511 
2512 		error = proc_pidthreadschedinfo(p, arg, &sched_info);
2513 		if (error == 0) {
2514 			error = copyout(&sched_info, buffer, sizeof(sched_info));
2515 			if (error == 0) {
2516 				*retval = sizeof(sched_info);
2517 			}
2518 		}
2519 	}
2520 	break;
2521 	default:
2522 		error = ENOTSUP;
2523 		break;
2524 	}
2525 
2526 out:
2527 	if (gotref) {
2528 		proc_rele(p);
2529 	} else if (zombie) {
2530 		proc_drop_zombref(p);
2531 	}
2532 	return error;
2533 }
2534 
2535 
2536 int
pid_vnodeinfo(vnode_t vp,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2537 pid_vnodeinfo(vnode_t vp, struct fileproc * fp, proc_t proc, user_addr_t  buffer, __unused uint32_t buffersize, int32_t * retval)
2538 {
2539 	struct vnode_fdinfo vfi;
2540 	uint32_t vid = vnode_vid(vp);
2541 	int error = 0;
2542 
2543 	if ((error = vnode_getwithvid(vp, vid)) != 0) {
2544 		return error;
2545 	}
2546 	bzero(&vfi, sizeof(struct vnode_fdinfo));
2547 	fill_fileinfo(fp, proc, &vfi.pfi);
2548 	error = fill_vnodeinfo(vp, &vfi.pvi, FALSE);
2549 	vnode_put(vp);
2550 	if (error == 0) {
2551 		error = copyout((caddr_t)&vfi, buffer, sizeof(struct vnode_fdinfo));
2552 		if (error == 0) {
2553 			*retval = sizeof(struct vnode_fdinfo);
2554 		}
2555 	}
2556 	return error;
2557 }
2558 
2559 int
pid_vnodeinfopath(vnode_t vp,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2560 pid_vnodeinfopath(vnode_t vp, struct fileproc * fp, proc_t proc, user_addr_t  buffer, __unused uint32_t buffersize, int32_t * retval)
2561 {
2562 	struct vnode_fdinfowithpath vfip;
2563 	uint32_t vid = vnode_vid(vp);
2564 	int count, error = 0;
2565 
2566 	if ((error = vnode_getwithvid(vp, vid)) != 0) {
2567 		return error;
2568 	}
2569 	bzero(&vfip, sizeof(struct vnode_fdinfowithpath));
2570 	fill_fileinfo(fp, proc, &vfip.pfi);
2571 	error = fill_vnodeinfo(vp, &vfip.pvip.vip_vi, TRUE);
2572 	if (error == 0) {
2573 		count = MAXPATHLEN;
2574 		vn_getpath(vp, &vfip.pvip.vip_path[0], &count);
2575 		vfip.pvip.vip_path[MAXPATHLEN - 1] = 0;
2576 		vnode_put(vp);
2577 		error = copyout((caddr_t)&vfip, buffer, sizeof(struct vnode_fdinfowithpath));
2578 		if (error == 0) {
2579 			*retval = sizeof(struct vnode_fdinfowithpath);
2580 		}
2581 	} else {
2582 		vnode_put(vp);
2583 	}
2584 	return error;
2585 }
2586 
2587 void
fill_fileinfo(struct fileproc * fp,proc_t proc,struct proc_fileinfo * fproc)2588 fill_fileinfo(struct fileproc * fp, proc_t proc, struct proc_fileinfo * fproc)
2589 {
2590 	fproc->fi_openflags = fp->fp_glob->fg_flag;
2591 	fproc->fi_status = 0;
2592 	fproc->fi_offset = fp->fp_glob->fg_offset;
2593 	fproc->fi_type = FILEGLOB_DTYPE(fp->fp_glob);
2594 	if (os_ref_get_count_raw(&fp->fp_glob->fg_count) > 1) {
2595 		fproc->fi_status |= PROC_FP_SHARED;
2596 	}
2597 	if (proc != PROC_NULL) {
2598 		if (fp->fp_flags & FP_CLOEXEC) {
2599 			fproc->fi_status |= PROC_FP_CLEXEC;
2600 		}
2601 		if (fp->fp_flags & FP_CLOFORK) {
2602 			fproc->fi_status |= PROC_FP_CLFORK;
2603 		}
2604 	}
2605 	if (fp->fp_guard_attrs) {
2606 		fproc->fi_status |= PROC_FP_GUARDED;
2607 		fproc->fi_guardflags = 0;
2608 		if (fp_isguarded(fp, GUARD_CLOSE)) {
2609 			fproc->fi_guardflags |= PROC_FI_GUARD_CLOSE;
2610 		}
2611 		if (fp_isguarded(fp, GUARD_DUP)) {
2612 			fproc->fi_guardflags |= PROC_FI_GUARD_DUP;
2613 		}
2614 		if (fp_isguarded(fp, GUARD_SOCKET_IPC)) {
2615 			fproc->fi_guardflags |= PROC_FI_GUARD_SOCKET_IPC;
2616 		}
2617 		if (fp_isguarded(fp, GUARD_FILEPORT)) {
2618 			fproc->fi_guardflags |= PROC_FI_GUARD_FILEPORT;
2619 		}
2620 	}
2621 }
2622 
2623 
2624 
2625 int
fill_vnodeinfo(vnode_t vp,struct vnode_info * vinfo,__unused boolean_t check_fsgetpath)2626 fill_vnodeinfo(vnode_t vp, struct vnode_info *vinfo, __unused boolean_t check_fsgetpath)
2627 {
2628 	vfs_context_t context;
2629 	struct stat64 sb;
2630 	int error = 0;
2631 
2632 	bzero(&sb, sizeof(struct stat64));
2633 	context = vfs_context_create((vfs_context_t)0);
2634 #if CONFIG_MACF
2635 	/* Called when vnode info is used by the caller to get vnode's path */
2636 	if (check_fsgetpath) {
2637 		error = mac_vnode_check_fsgetpath(context, vp);
2638 	}
2639 #endif
2640 	if (!error) {
2641 		error = vn_stat(vp, &sb, NULL, 1, 0, context);
2642 		munge_vinfo_stat(&sb, &vinfo->vi_stat);
2643 	}
2644 	(void)vfs_context_rele(context);
2645 	if (error != 0) {
2646 		goto out;
2647 	}
2648 
2649 	if (vp->v_mount != dead_mountp) {
2650 		vinfo->vi_fsid = vp->v_mount->mnt_vfsstat.f_fsid;
2651 	} else {
2652 		vinfo->vi_fsid.val[0] = 0;
2653 		vinfo->vi_fsid.val[1] = 0;
2654 	}
2655 	vinfo->vi_type = vp->v_type;
2656 out:
2657 	return error;
2658 }
2659 
2660 int
pid_socketinfo(socket_t so,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2661 pid_socketinfo(socket_t so, struct fileproc *fp, proc_t proc, user_addr_t  buffer, __unused uint32_t buffersize, int32_t * retval)
2662 {
2663 #if SOCKETS
2664 	struct socket_fdinfo s;
2665 	int error = 0;
2666 
2667 	bzero(&s, sizeof(struct socket_fdinfo));
2668 	fill_fileinfo(fp, proc, &s.pfi);
2669 	if ((error = fill_socketinfo(so, &s.psi)) == 0) {
2670 		if ((error = copyout(&s, buffer, sizeof(struct socket_fdinfo))) == 0) {
2671 			*retval = sizeof(struct socket_fdinfo);
2672 		}
2673 	}
2674 	return error;
2675 #else
2676 #pragma unused(so, fp, proc, fd, buffer)
2677 	*retval = 0;
2678 	return ENOTSUP;
2679 #endif
2680 }
2681 
2682 int
pid_pseminfo(struct psemnode * psem,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2683 pid_pseminfo(struct psemnode *psem, struct fileproc *fp, proc_t proc, user_addr_t  buffer, __unused uint32_t buffersize, int32_t * retval)
2684 {
2685 	struct psem_fdinfo pseminfo;
2686 	int error = 0;
2687 
2688 	bzero(&pseminfo, sizeof(struct psem_fdinfo));
2689 	fill_fileinfo(fp, proc, &pseminfo.pfi);
2690 
2691 	if ((error = fill_pseminfo(psem, &pseminfo.pseminfo)) == 0) {
2692 		if ((error = copyout(&pseminfo, buffer, sizeof(struct psem_fdinfo))) == 0) {
2693 			*retval = sizeof(struct psem_fdinfo);
2694 		}
2695 	}
2696 
2697 	return error;
2698 }
2699 
2700 int
pid_pshminfo(struct pshmnode * pshm,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2701 pid_pshminfo(struct pshmnode *pshm, struct fileproc *fp, proc_t proc, user_addr_t  buffer, __unused uint32_t buffersize, int32_t * retval)
2702 {
2703 	struct pshm_fdinfo pshminfo;
2704 	int error = 0;
2705 
2706 	bzero(&pshminfo, sizeof(struct pshm_fdinfo));
2707 	fill_fileinfo(fp, proc, &pshminfo.pfi);
2708 
2709 	if ((error = fill_pshminfo(pshm, &pshminfo.pshminfo)) == 0) {
2710 		if ((error = copyout(&pshminfo, buffer, sizeof(struct pshm_fdinfo))) == 0) {
2711 			*retval = sizeof(struct pshm_fdinfo);
2712 		}
2713 	}
2714 
2715 	return error;
2716 }
2717 
2718 int
pid_pipeinfo(struct pipe * p,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2719 pid_pipeinfo(struct pipe *  p, struct fileproc *fp, proc_t proc, user_addr_t  buffer, __unused uint32_t buffersize, int32_t * retval)
2720 {
2721 	struct pipe_fdinfo pipeinfo;
2722 	int error = 0;
2723 
2724 	bzero(&pipeinfo, sizeof(struct pipe_fdinfo));
2725 	fill_fileinfo(fp, proc, &pipeinfo.pfi);
2726 	if ((error = fill_pipeinfo(p, &pipeinfo.pipeinfo)) == 0) {
2727 		if ((error = copyout(&pipeinfo, buffer, sizeof(struct pipe_fdinfo))) == 0) {
2728 			*retval = sizeof(struct pipe_fdinfo);
2729 		}
2730 	}
2731 
2732 	return error;
2733 }
2734 
2735 int
pid_kqueueinfo(struct kqueue * kq,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2736 pid_kqueueinfo(struct kqueue * kq, struct fileproc *fp, proc_t proc, user_addr_t  buffer, __unused uint32_t buffersize, int32_t * retval)
2737 {
2738 	struct kqueue_fdinfo kqinfo;
2739 	int error = 0;
2740 
2741 	bzero(&kqinfo, sizeof(struct kqueue_fdinfo));
2742 
2743 	/* not all kq's are associated with a file (e.g. workqkq) */
2744 	if (fp) {
2745 		fill_fileinfo(fp, proc, &kqinfo.pfi);
2746 	}
2747 
2748 	if ((error = fill_kqueueinfo(kq, &kqinfo.kqueueinfo)) == 0) {
2749 		if ((error = copyout(&kqinfo, buffer, sizeof(struct kqueue_fdinfo))) == 0) {
2750 			*retval = sizeof(struct kqueue_fdinfo);
2751 		}
2752 	}
2753 
2754 	return error;
2755 }
2756 
2757 int
pid_channelinfo(struct kern_channel * chan,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2758 pid_channelinfo(struct kern_channel * chan, struct fileproc *fp, proc_t proc, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2759 {
2760 #if SKYWALK
2761 	struct channel_fdinfo channel_info;
2762 	int error = 0;
2763 
2764 	bzero(&channel_info, sizeof(struct channel_fdinfo));
2765 	fill_fileinfo(fp, proc, &channel_info.pfi);
2766 	if ((error = fill_channelinfo(chan, &channel_info.channelinfo)) == 0) {
2767 		if ((error = copyout(&channel_info, buffer, sizeof(struct channel_fdinfo))) == 0) {
2768 			*retval = sizeof(struct channel_fdinfo);
2769 		}
2770 	}
2771 	return error;
2772 #else
2773 #pragma unused(chan, fp, proc, fd, buffer)
2774 	*retval = 0;
2775 	return ENOTSUP;
2776 #endif
2777 }
2778 
2779 /************************** proc_pidfdinfo routine ***************************/
2780 int
proc_pidfdinfo(int pid,int flavor,int fd,user_addr_t buffer,uint32_t buffersize,int32_t * retval)2781 proc_pidfdinfo(int pid, int flavor, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
2782 {
2783 	proc_t p;
2784 	int error = ENOTSUP;
2785 	struct fileproc *fp = NULL;
2786 	uint32_t size;
2787 
2788 	switch (flavor) {
2789 	case PROC_PIDFDVNODEINFO:
2790 		size = PROC_PIDFDVNODEINFO_SIZE;
2791 		break;
2792 	case PROC_PIDFDVNODEPATHINFO:
2793 		size = PROC_PIDFDVNODEPATHINFO_SIZE;
2794 		break;
2795 	case PROC_PIDFDSOCKETINFO:
2796 		size = PROC_PIDFDSOCKETINFO_SIZE;
2797 		break;
2798 	case PROC_PIDFDPSEMINFO:
2799 		size = PROC_PIDFDPSEMINFO_SIZE;
2800 		break;
2801 	case PROC_PIDFDPSHMINFO:
2802 		size = PROC_PIDFDPSHMINFO_SIZE;
2803 		break;
2804 	case PROC_PIDFDPIPEINFO:
2805 		size = PROC_PIDFDPIPEINFO_SIZE;
2806 		break;
2807 	case PROC_PIDFDKQUEUEINFO:
2808 		size = PROC_PIDFDKQUEUEINFO_SIZE;
2809 		break;
2810 	case PROC_PIDFDKQUEUE_EXTINFO:
2811 		size = PROC_PIDFDKQUEUE_EXTINFO_SIZE;
2812 		if (buffer == (user_addr_t)0) {
2813 			size = 0;
2814 		}
2815 		break;
2816 	case PROC_PIDFDATALKINFO:
2817 		size = PROC_PIDFDATALKINFO_SIZE;
2818 		break;
2819 	case PROC_PIDFDCHANNELINFO:
2820 		size = PROC_PIDFDCHANNELINFO_SIZE;
2821 		break;
2822 
2823 	default:
2824 		return EINVAL;
2825 	}
2826 
2827 	if (buffersize < size) {
2828 		return ENOMEM;
2829 	}
2830 
2831 	if ((p = proc_find(pid)) == PROC_NULL) {
2832 		error = ESRCH;
2833 		goto out;
2834 	}
2835 
2836 	/* Do we have permission to look into this? */
2837 	if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDFDINFO, flavor, CHECK_SAME_USER))) {
2838 		goto out1;
2839 	}
2840 
2841 	switch (flavor) {
2842 	case PROC_PIDFDVNODEINFO: {
2843 		if ((error = fp_get_ftype(p, fd, DTYPE_VNODE, EBADF, &fp)) != 0) {
2844 			goto out1;
2845 		}
2846 		error = pid_vnodeinfo((vnode_t)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2847 	}
2848 	break;
2849 
2850 	case PROC_PIDFDVNODEPATHINFO: {
2851 		if ((error = fp_get_ftype(p, fd, DTYPE_VNODE, EBADF, &fp)) != 0) {
2852 			goto out1;
2853 		}
2854 		error = pid_vnodeinfopath((vnode_t)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2855 	}
2856 	break;
2857 
2858 	case PROC_PIDFDSOCKETINFO: {
2859 		if ((error = fp_get_ftype(p, fd, DTYPE_SOCKET, ENOTSOCK, &fp)) != 0) {
2860 			goto out1;
2861 		}
2862 		error = pid_socketinfo((socket_t)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2863 	}
2864 	break;
2865 
2866 	case PROC_PIDFDPSEMINFO: {
2867 		if ((error = fp_get_ftype(p, fd, DTYPE_PSXSEM, EBADF, &fp)) != 0) {
2868 			goto out1;
2869 		}
2870 		error = pid_pseminfo((struct psemnode *)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2871 	}
2872 	break;
2873 
2874 	case PROC_PIDFDPSHMINFO: {
2875 		if ((error = fp_get_ftype(p, fd, DTYPE_PSXSHM, EBADF, &fp)) != 0) {
2876 			goto out1;
2877 		}
2878 		error = pid_pshminfo((struct pshmnode *)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2879 	}
2880 	break;
2881 
2882 	case PROC_PIDFDPIPEINFO: {
2883 		if ((error = fp_get_ftype(p, fd, DTYPE_PIPE, EBADF, &fp)) != 0) {
2884 			goto out1;
2885 		}
2886 		error = pid_pipeinfo((struct pipe *)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2887 	}
2888 	break;
2889 
2890 	case PROC_PIDFDKQUEUEINFO: {
2891 		kqueue_t kqu;
2892 
2893 		if (fd == -1) {
2894 			if ((kqu.kqwq = p->p_fd.fd_wqkqueue) == NULL) {
2895 				/* wqkqueue is initialized on-demand */
2896 				error = 0;
2897 				break;
2898 			}
2899 		} else if ((error = fp_get_ftype(p, fd, DTYPE_KQUEUE, EBADF, &fp)) != 0) {
2900 			goto out1;
2901 		} else {
2902 			kqu.kq = (struct kqueue *)fp_get_data(fp);
2903 		}
2904 
2905 		error = pid_kqueueinfo(kqu.kq, fp, p, buffer, buffersize, retval);
2906 	}
2907 	break;
2908 
2909 	case PROC_PIDFDKQUEUE_EXTINFO: {
2910 		kqueue_t kqu;
2911 
2912 		if (fd == -1) {
2913 			if ((kqu.kqwq = p->p_fd.fd_wqkqueue) == NULL) {
2914 				/* wqkqueue is initialized on-demand */
2915 				error = 0;
2916 				break;
2917 			}
2918 		} else if ((error = fp_get_ftype(p, fd, DTYPE_KQUEUE, EBADF, &fp)) != 0) {
2919 			goto out1;
2920 		} else {
2921 			kqu.kq = (struct kqueue *)fp_get_data(fp);
2922 		}
2923 		error = pid_kqueue_extinfo(p, kqu.kq, buffer, buffersize, retval);
2924 	}
2925 	break;
2926 	case PROC_PIDFDCHANNELINFO: {
2927 		if ((error = fp_get_ftype(p, fd, DTYPE_CHANNEL, EBADF, &fp)) != 0) {
2928 			goto out1;
2929 		}
2930 		/* no need to be under the fdlock */
2931 		error = pid_channelinfo((struct kern_channel *)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2932 	}
2933 	break;
2934 
2935 	default: {
2936 		error = EINVAL;
2937 		goto out1;
2938 	}
2939 	}
2940 
2941 	if (fp) {
2942 		fp_drop(p, fd, fp, 0);
2943 	}
2944 out1:
2945 	proc_rele(p);
2946 out:
2947 	return error;
2948 }
2949 
2950 #define MAX_UPTRS 16392
2951 
2952 int
proc_pidlistuptrs(proc_t p,user_addr_t buffer,uint32_t buffersize,int32_t * retval)2953 proc_pidlistuptrs(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval)
2954 {
2955 	uint32_t count = 0;
2956 	int error = 0;
2957 	void *kbuf = NULL;
2958 	int32_t nuptrs = 0;
2959 
2960 	if (buffer == USER_ADDR_NULL || buffersize < sizeof(uint64_t)) {
2961 		buffersize = 0;
2962 	} else {
2963 		count = MIN(buffersize / sizeof(uint64_t), MAX_UPTRS);
2964 		buffersize = count * sizeof(uint64_t);
2965 		kbuf = kalloc_data(buffersize, Z_WAITOK);
2966 	}
2967 
2968 	nuptrs = kevent_proc_copy_uptrs(p, kbuf, buffersize);
2969 
2970 	if (kbuf) {
2971 		size_t copysize;
2972 		if (os_mul_overflow(nuptrs, sizeof(uint64_t), &copysize)) {
2973 			error = ERANGE;
2974 			goto out;
2975 		}
2976 		if (copysize > buffersize) {
2977 			copysize = buffersize;
2978 		}
2979 		error = copyout(kbuf, buffer, copysize);
2980 	}
2981 
2982 out:
2983 	*retval = nuptrs;
2984 
2985 	if (kbuf) {
2986 		kfree_data(kbuf, buffersize);
2987 		kbuf = NULL;
2988 	}
2989 
2990 	return error;
2991 }
2992 
2993 /*
2994  * Helper function for proc_pidfileportinfo
2995  */
2996 
2997 struct fileport_info_args {
2998 	int             fia_flavor;
2999 	user_addr_t     fia_buffer;
3000 	uint32_t        fia_buffersize;
3001 	int32_t         *fia_retval;
3002 };
3003 
3004 static kern_return_t
proc_fileport_info(__unused mach_port_name_t name,struct fileglob * fg,void * arg)3005 proc_fileport_info(__unused mach_port_name_t name,
3006     struct fileglob *fg, void *arg)
3007 {
3008 	struct fileport_info_args *fia = arg;
3009 	struct fileproc __fileproc, *fp = &__fileproc;
3010 	int error;
3011 
3012 	bzero(fp, sizeof(*fp));
3013 	fp->fp_glob = fg;
3014 
3015 	switch (fia->fia_flavor) {
3016 	case PROC_PIDFILEPORTVNODEPATHINFO: {
3017 		vnode_t vp;
3018 
3019 		if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
3020 			error = ENOTSUP;
3021 			break;
3022 		}
3023 		vp = (struct vnode *)fg_get_data(fg);
3024 		error = pid_vnodeinfopath(vp, fp, PROC_NULL,
3025 		    fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
3026 	}       break;
3027 
3028 	case PROC_PIDFILEPORTSOCKETINFO: {
3029 		socket_t so;
3030 
3031 		if (FILEGLOB_DTYPE(fg) != DTYPE_SOCKET) {
3032 			error = EOPNOTSUPP;
3033 			break;
3034 		}
3035 		so = (socket_t)fg_get_data(fg);
3036 		error = pid_socketinfo(so, fp, PROC_NULL,
3037 		    fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
3038 	}       break;
3039 
3040 	case PROC_PIDFILEPORTPSHMINFO: {
3041 		struct pshmnode *pshm;
3042 
3043 		if (FILEGLOB_DTYPE(fg) != DTYPE_PSXSHM) {
3044 			error = EBADF;          /* ick - mirror fp_getfpshm */
3045 			break;
3046 		}
3047 		pshm = (struct pshmnode *)fg_get_data(fg);
3048 		error = pid_pshminfo(pshm, fp, PROC_NULL,
3049 		    fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
3050 	}       break;
3051 
3052 	case PROC_PIDFILEPORTPIPEINFO: {
3053 		struct pipe *cpipe;
3054 
3055 		if (FILEGLOB_DTYPE(fg) != DTYPE_PIPE) {
3056 			error = EBADF;          /* ick - mirror fp_getfpipe */
3057 			break;
3058 		}
3059 		cpipe = (struct pipe *)fg_get_data(fg);
3060 		error = pid_pipeinfo(cpipe, fp, PROC_NULL,
3061 		    fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
3062 	}       break;
3063 
3064 	default:
3065 		error = EINVAL;
3066 		break;
3067 	}
3068 
3069 	return error;
3070 }
3071 
3072 /************************* proc_pidfileportinfo routine *********************/
3073 int
proc_pidfileportinfo(int pid,int flavor,mach_port_name_t name,user_addr_t buffer,uint32_t buffersize,int32_t * retval)3074 proc_pidfileportinfo(int pid, int flavor, mach_port_name_t name,
3075     user_addr_t buffer, uint32_t buffersize, int32_t *retval)
3076 {
3077 	proc_t p;
3078 	int error = ENOTSUP;
3079 	uint32_t size;
3080 	struct fileport_info_args fia;
3081 
3082 	/* fileport types are restricted by file_issendable() */
3083 
3084 	switch (flavor) {
3085 	case PROC_PIDFILEPORTVNODEPATHINFO:
3086 		size = PROC_PIDFILEPORTVNODEPATHINFO_SIZE;
3087 		break;
3088 	case PROC_PIDFILEPORTSOCKETINFO:
3089 		size = PROC_PIDFILEPORTSOCKETINFO_SIZE;
3090 		break;
3091 	case PROC_PIDFILEPORTPSHMINFO:
3092 		size = PROC_PIDFILEPORTPSHMINFO_SIZE;
3093 		break;
3094 	case PROC_PIDFILEPORTPIPEINFO:
3095 		size = PROC_PIDFILEPORTPIPEINFO_SIZE;
3096 		break;
3097 	default:
3098 		return EINVAL;
3099 	}
3100 
3101 	if (buffersize < size) {
3102 		return ENOMEM;
3103 	}
3104 	if ((p = proc_find(pid)) == PROC_NULL) {
3105 		error = ESRCH;
3106 		goto out;
3107 	}
3108 
3109 	/* Do we have permission to look into this? */
3110 	if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDFILEPORTINFO, flavor, CHECK_SAME_USER))) {
3111 		goto out1;
3112 	}
3113 
3114 	fia.fia_flavor = flavor;
3115 	fia.fia_buffer = buffer;
3116 	fia.fia_buffersize = buffersize;
3117 	fia.fia_retval = retval;
3118 
3119 	if (fileport_invoke(proc_task(p), name,
3120 	    proc_fileport_info, &fia, &error) != KERN_SUCCESS) {
3121 		error = EINVAL;
3122 	}
3123 out1:
3124 	proc_rele(p);
3125 out:
3126 	return error;
3127 }
3128 
3129 int
proc_security_policy(proc_t targetp,__unused int callnum,__unused int flavor,boolean_t check_same_user)3130 proc_security_policy(proc_t targetp, __unused int callnum, __unused int flavor, boolean_t check_same_user)
3131 {
3132 #if CONFIG_MACF
3133 	int error = 0;
3134 
3135 	if ((error = mac_proc_check_proc_info(current_proc(), targetp, callnum, flavor))) {
3136 		return error;
3137 	}
3138 #endif
3139 
3140 	/* The 'listpids' call doesn't have a target proc */
3141 	if (targetp == PROC_NULL) {
3142 		assert(callnum == PROC_INFO_CALL_LISTPIDS && check_same_user == NO_CHECK_SAME_USER);
3143 		return 0;
3144 	}
3145 
3146 	/*
3147 	 * Check for 'get information for processes owned by other users' privilege
3148 	 * root has this privilege by default
3149 	 */
3150 	if (check_same_user) {
3151 		kauth_cred_t my_cred = kauth_cred_get();
3152 		kauth_cred_t tg_cred;
3153 
3154 		smr_proc_task_enter();
3155 		tg_cred = proc_ucred_smr(targetp);
3156 		if (kauth_cred_getuid(my_cred) != kauth_cred_getuid(tg_cred)) {
3157 			error = EPERM;
3158 		}
3159 		tg_cred = NOCRED;
3160 		smr_proc_task_leave();
3161 
3162 		/*
3163 		 * If uid doesn't match, check if the caller is specially entitled
3164 		 * to bypass the requirement.
3165 		 */
3166 		if (error && priv_check_cred(my_cred, PRIV_GLOBAL_PROC_INFO, 0)) {
3167 			return EPERM;
3168 		}
3169 	}
3170 
3171 	return 0;
3172 }
3173 
3174 int
proc_kernmsgbuf(user_addr_t buffer,uint32_t buffersize,int32_t * retval)3175 proc_kernmsgbuf(user_addr_t buffer, uint32_t buffersize, int32_t * retval)
3176 {
3177 #if CONFIG_MACF
3178 	int error = 0;
3179 
3180 	if ((error = mac_system_check_info(kauth_cred_get(), "kern.msgbuf"))) {
3181 		return error;
3182 	}
3183 #endif
3184 
3185 	if (suser(kauth_cred_get(), (u_short *)0) == 0) {
3186 		return log_dmesg(buffer, buffersize, retval);
3187 	} else {
3188 		return EPERM;
3189 	}
3190 }
3191 
3192 /* ********* process control sets on self only */
3193 int
proc_setcontrol(int pid,int flavor,uint64_t arg,user_addr_t buffer,uint32_t buffersize,__unused int32_t * retval)3194 proc_setcontrol(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, __unused int32_t * retval)
3195 {
3196 	struct proc * pself = PROC_NULL;
3197 	int error = 0;
3198 	uint32_t pcontrol = (uint32_t)arg;
3199 	struct uthread *ut = NULL;
3200 	char name_buf[MAXTHREADNAMESIZE];
3201 
3202 	pself = current_proc();
3203 	if (pid != proc_getpid(pself)) {
3204 		return EINVAL;
3205 	}
3206 
3207 	/* Do we have permission to look into this? */
3208 	if ((error = proc_security_policy(pself, PROC_INFO_CALL_SETCONTROL, flavor, NO_CHECK_SAME_USER))) {
3209 		goto out;
3210 	}
3211 
3212 	switch (flavor) {
3213 	case PROC_SELFSET_PCONTROL: {
3214 		if (pcontrol > P_PCMAX) {
3215 			return EINVAL;
3216 		}
3217 		proc_lock(pself);
3218 		/* reset existing control setting while retaining action state */
3219 		pself->p_pcaction &= PROC_ACTION_MASK;
3220 		/* set new control state */
3221 		pself->p_pcaction |= pcontrol;
3222 		proc_unlock(pself);
3223 	}
3224 	break;
3225 
3226 	case PROC_SELFSET_THREADNAME: {
3227 		/*
3228 		 * This is a bit ugly, as it copies the name into the kernel, and then
3229 		 * invokes bsd_setthreadname again to copy it into the uthread name
3230 		 * buffer.  Hopefully this isn't such a hot codepath that an additional
3231 		 * MAXTHREADNAMESIZE copy is a big issue.
3232 		 */
3233 		if (buffersize > (MAXTHREADNAMESIZE - 1)) {
3234 			return ENAMETOOLONG;
3235 		}
3236 
3237 		ut = current_uthread();
3238 
3239 		bzero(name_buf, MAXTHREADNAMESIZE);
3240 		error = copyin(buffer, name_buf, buffersize);
3241 
3242 		if (!error) {
3243 			bsd_setthreadname(ut, thread_tid(current_thread()), name_buf);
3244 		}
3245 	}
3246 	break;
3247 
3248 	case PROC_SELFSET_VMRSRCOWNER: {
3249 		/* need to to be superuser */
3250 		if (suser(kauth_cred_get(), (u_short *)0) != 0) {
3251 			error = EPERM;
3252 			goto out;
3253 		}
3254 
3255 		proc_lock(pself);
3256 		/* reset existing control setting while retaining action state */
3257 		pself->p_lflag |= P_LVMRSRCOWNER;
3258 		proc_unlock(pself);
3259 	}
3260 	break;
3261 
3262 	case PROC_SELFSET_DELAYIDLESLEEP: {
3263 #if CONFIG_DELAY_IDLE_SLEEP
3264 		/* mark or clear the process property to delay idle sleep disk IO */
3265 		if (pcontrol != 0) {
3266 			OSBitOrAtomic(P_DELAYIDLESLEEP, &pself->p_flag);
3267 		} else {
3268 			OSBitAndAtomic(~((uint32_t)P_DELAYIDLESLEEP), &pself->p_flag);
3269 		}
3270 	}
3271 	break;
3272 #else
3273 		error = ENOTSUP;
3274 		goto out;
3275 	}
3276 #endif
3277 
3278 	default:
3279 		error = ENOTSUP;
3280 	}
3281 
3282 out:
3283 	return error;
3284 }
3285 
3286 #if CONFIG_MEMORYSTATUS
3287 
3288 int
proc_dirtycontrol(int pid,int flavor,uint64_t arg,int32_t * retval)3289 proc_dirtycontrol(int pid, int flavor, uint64_t arg, int32_t *retval)
3290 {
3291 	struct proc *target_p;
3292 	int error = 0;
3293 	uint32_t pcontrol = (uint32_t)arg;
3294 	kauth_cred_t my_cred;
3295 	boolean_t self = FALSE;
3296 	boolean_t child = FALSE;
3297 	boolean_t zombref = FALSE;
3298 	pid_t selfpid;
3299 
3300 	target_p = proc_find(pid);
3301 
3302 	if (target_p == PROC_NULL) {
3303 		if (flavor == PROC_DIRTYCONTROL_GET) {
3304 			target_p = proc_find_zombref(pid);
3305 			zombref = 1;
3306 		}
3307 
3308 		if (target_p == PROC_NULL) {
3309 			return ESRCH;
3310 		}
3311 	}
3312 
3313 	my_cred = kauth_cred_get();
3314 
3315 	/* Do we have permission to look into this? */
3316 	if ((error = proc_security_policy(target_p, PROC_INFO_CALL_DIRTYCONTROL, flavor, NO_CHECK_SAME_USER))) {
3317 		goto out;
3318 	}
3319 
3320 	selfpid = proc_selfpid();
3321 	if (pid == selfpid) {
3322 		self = TRUE;
3323 	} else if (target_p->p_ppid == selfpid) {
3324 		child = TRUE;
3325 	}
3326 
3327 	switch (flavor) {
3328 	case PROC_DIRTYCONTROL_TRACK: {
3329 		/* Only allow the process itself, its parent, or root */
3330 		if ((self == FALSE) && (child == FALSE) && kauth_cred_issuser(kauth_cred_get()) != TRUE) {
3331 			error = EPERM;
3332 			goto out;
3333 		}
3334 
3335 		error = memorystatus_dirty_track(target_p, pcontrol);
3336 	}
3337 	break;
3338 
3339 	case PROC_DIRTYCONTROL_SET: {
3340 		/* Check privileges; use cansignal() here since the process could be terminated */
3341 		if (!cansignal(current_proc(), my_cred, target_p, SIGKILL)) {
3342 			error = EPERM;
3343 			goto out;
3344 		}
3345 
3346 		error = memorystatus_dirty_set(target_p, self, pcontrol);
3347 	}
3348 	break;
3349 
3350 	case PROC_DIRTYCONTROL_GET: {
3351 		/* No permissions check - dirty state is freely available */
3352 		if (retval) {
3353 			*retval = memorystatus_dirty_get(target_p, FALSE);
3354 		} else {
3355 			error = EINVAL;
3356 		}
3357 	}
3358 	break;
3359 
3360 	case PROC_DIRTYCONTROL_CLEAR: {
3361 		/* Check privileges; use cansignal() here since the process could be terminated */
3362 		if (!cansignal(current_proc(), my_cred, target_p, SIGKILL)) {
3363 			error = EPERM;
3364 			goto out;
3365 		}
3366 
3367 		error = memorystatus_dirty_clear(target_p, pcontrol);
3368 	}
3369 	break;
3370 	}
3371 
3372 out:
3373 	if (zombref) {
3374 		proc_drop_zombref(target_p);
3375 	} else {
3376 		proc_rele(target_p);
3377 	}
3378 
3379 	return error;
3380 }
3381 #else
3382 
3383 int
proc_dirtycontrol(__unused int pid,__unused int flavor,__unused uint64_t arg,__unused int32_t * retval)3384 proc_dirtycontrol(__unused int pid, __unused int flavor, __unused uint64_t arg, __unused int32_t *retval)
3385 {
3386 	return ENOTSUP;
3387 }
3388 
3389 #endif /* CONFIG_MEMORYSTATUS */
3390 
3391 /*
3392  * proc_terminate_with_proc() provides support for sudden termination by proc_t.
3393  * SIGKILL is issued to tracked, clean processes; otherwise,
3394  * SIGTERM is sent.
3395  */
3396 static int
proc_terminate_with_proc(proc_t p,int32_t * retval)3397 proc_terminate_with_proc(proc_t p, int32_t *retval)
3398 {
3399 	kauth_cred_t uc = kauth_cred_get();
3400 	int sig;
3401 
3402 	/* Check privileges; if SIGKILL can be issued, then SIGTERM is also OK */
3403 	if (!cansignal(current_proc(), uc, p, SIGKILL)) {
3404 		return EPERM;
3405 	}
3406 
3407 	/* Not allowed to sudden terminate yourself */
3408 	if (p == current_proc()) {
3409 		return EPERM;
3410 	}
3411 
3412 #if CONFIG_MEMORYSTATUS
3413 	/* Determine requisite signal to issue */
3414 	sig = memorystatus_on_terminate(p);
3415 #else
3416 	sig = SIGTERM;
3417 #endif
3418 
3419 	proc_set_task_policy(proc_task(p), TASK_POLICY_ATTRIBUTE,
3420 	    TASK_POLICY_TERMINATED, TASK_POLICY_ENABLE);
3421 
3422 	psignal(p, sig);
3423 	*retval = sig;
3424 
3425 	return 0;
3426 }
3427 
3428 /*
3429  * proc_terminate() provides support for sudden termination by PID.
3430  * SIGKILL is issued to tracked, clean processes; otherwise,
3431  * SIGTERM is sent.
3432  */
3433 int
proc_terminate(int pid,int32_t * retval)3434 proc_terminate(int pid, int32_t *retval)
3435 {
3436 	int error = 0;
3437 	proc_t p;
3438 
3439 #if 0
3440 	/* XXX: Check if these are necessary */
3441 	AUDIT_ARG(pid, pid);
3442 #endif
3443 
3444 	if (pid <= 0 || retval == NULL) {
3445 		return EINVAL;
3446 	}
3447 
3448 	if ((p = proc_find(pid)) == NULL) {
3449 		return ESRCH;
3450 	}
3451 
3452 #if 0
3453 	/* XXX: Check if these are necessary */
3454 	AUDIT_ARG(process, p);
3455 #endif
3456 
3457 	error = proc_terminate_with_proc(p, retval);
3458 	proc_rele(p);
3459 	return error;
3460 }
3461 
3462 #define cryptexdrsrWriteEntitlement "com.apple.private.cryptexd-rsr-write"
3463 
3464 int proc_rsr_in_progress = 0;
3465 
3466 static int
3467 sysctl_proc_rsr_in_progress SYSCTL_HANDLER_ARGS
3468 {
3469 	int error = 0;
3470 
3471 	if (req->newptr != 0) {
3472 		/* Write entitlement is required for updating this sysctl */
3473 		if (!IOCurrentTaskHasEntitlement(cryptexdrsrWriteEntitlement)) {
3474 			return EPERM;
3475 		}
3476 	}
3477 	error = sysctl_handle_int(oidp, arg1, arg2, req);
3478 
3479 	return error;
3480 }
3481 
3482 SYSCTL_PROC(_kern, OID_AUTO, proc_rsr_in_progress,
3483     CTLTYPE_INT | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
3484     &proc_rsr_in_progress, 0,
3485     sysctl_proc_rsr_in_progress, "I", "");
3486 
3487 struct proc_terminate_all_rsr_struct {
3488 	int     ptss_sig;
3489 	int32_t *ptss_retval;
3490 };
3491 
3492 /**
3493  * @brief Wrapper for the majority of send signal methods. Validates signal number,
3494  * validates the target audit token, validates that current_proc() can send the signal.
3495  * Then invokes proc_terminate_with_proc if should_terminate is true, otherwise invokes
3496  * psignal with the signal.
3497  */
3498 static int
_proc_signal_send(audit_token_t target,int signum,bool should_terminate,int32_t * retval)3499 _proc_signal_send(audit_token_t target, int signum, bool should_terminate, int32_t *retval)
3500 {
3501 	int error = 0;
3502 	pid_t pid = 0;
3503 	proc_t target_proc = PROC_NULL;
3504 	kauth_cred_t uc = kauth_cred_get();
3505 
3506 	/* defined in bsd/kern/kern_prot.c */
3507 	extern int get_audit_token_pid(audit_token_t *audit_token);
3508 
3509 	/* Check that the signal number is valid */
3510 	if (!((signum > 0) && (signum < NSIG))) {
3511 		error = EINVAL;
3512 		goto out;
3513 	}
3514 
3515 	pid = get_audit_token_pid(&target);
3516 	if (pid <= 0) {
3517 		error = EINVAL;
3518 		goto out;
3519 	}
3520 
3521 	if ((target_proc = proc_find(pid)) == PROC_NULL) {
3522 		error = ESRCH;
3523 		goto out;
3524 	}
3525 
3526 	/* Check the target proc pidversion */
3527 	int pidversion = proc_pidversion(target_proc);
3528 	if (pidversion != target.val[7]) {
3529 		error = ESRCH;
3530 		goto out;
3531 	}
3532 
3533 	// Determine if the process should be immediately terminated
3534 	// proc_terminate_with_proc() invokes `cansignal()` internally and sets
3535 	// retval to the signal that was sent (either SIGTERM or SIGKILL).
3536 	if (should_terminate) {
3537 		error = proc_terminate_with_proc(target_proc, retval);
3538 		goto out;
3539 	}
3540 
3541 	/* Check the calling process privileges, proceed if it can signal the target process */
3542 	if (!cansignal(current_proc(), uc, target_proc, signum)) {
3543 		error = EPERM;
3544 		goto out;
3545 	}
3546 
3547 	/* Send the signal */
3548 	psignal(target_proc, signum);
3549 	*retval = 0;
3550 out:
3551 	if (target_proc != PROC_NULL) {
3552 		proc_rele(target_proc);
3553 	}
3554 	return error;
3555 }
3556 
3557 #define delegateSignalEntitlement "com.apple.private.delegate-signals"
3558 static int
proc_signal_delegate(user_addr_t buffer,size_t buffersize,int signum,int32_t * retval)3559 proc_signal_delegate(user_addr_t buffer, size_t buffersize, int signum, int32_t *retval)
3560 {
3561 	int error = 0;
3562 	struct proc_delegated_signal_info info = {0};
3563 
3564 	/* Enforce current proc is entitled to delegate signals */
3565 	if (!IOCurrentTaskHasEntitlement(delegateSignalEntitlement)) {
3566 		return EPERM;
3567 	}
3568 
3569 	if (buffer == USER_ADDR_NULL || buffersize != sizeof(struct proc_delegated_signal_info)) {
3570 		return EINVAL;
3571 	}
3572 
3573 	error = copyin(buffer, &info, sizeof(struct proc_delegated_signal_info));
3574 	if (error != 0) {
3575 		return error;
3576 	}
3577 
3578 #ifdef CONFIG_MACF
3579 	if ((error = mac_proc_check_delegated_signal(current_proc(), info.instigator, info.target, signum))) {
3580 		return error;
3581 	}
3582 #endif
3583 
3584 	/* Final signal checks on current_proc */
3585 	return _proc_signal_send(info.target, signum, false, retval);
3586 }
3587 
3588 static int
proc_terminate_delegate(user_addr_t buffer,size_t buffersize,int32_t * retval)3589 proc_terminate_delegate(user_addr_t buffer, size_t buffersize, int32_t *retval)
3590 {
3591 	int error = 0;
3592 	struct proc_delegated_signal_info info = {0};
3593 
3594 	/* Enforce current proc is entitled to delegate signals */
3595 	if (!IOCurrentTaskHasEntitlement(delegateSignalEntitlement)) {
3596 		return EPERM;
3597 	}
3598 
3599 	if (buffer == USER_ADDR_NULL || buffersize != sizeof(struct proc_delegated_signal_info)) {
3600 		return EINVAL;
3601 	}
3602 
3603 	error = copyin(buffer, &info, sizeof(struct proc_delegated_signal_info));
3604 	if (error != 0) {
3605 		return error;
3606 	}
3607 
3608 #ifdef CONFIG_MACF
3609 	if ((error = mac_proc_check_delegated_signal(current_proc(), info.instigator, info.target, SIGKILL))) {
3610 		return error;
3611 	}
3612 #endif
3613 
3614 	/* Final signal checks on current_proc */
3615 	return _proc_signal_send(info.target, SIGTERM, true, retval);
3616 }
3617 
3618 static int
proc_signal_with_audittoken(user_addr_t buffer,size_t buffersize,int signum,int32_t * retval)3619 proc_signal_with_audittoken(user_addr_t buffer, size_t buffersize, int signum, int32_t *retval)
3620 {
3621 	int error = 0;
3622 	audit_token_t target = INVALID_AUDIT_TOKEN_VALUE;
3623 
3624 	if (buffer == USER_ADDR_NULL || buffersize != sizeof(audit_token_t)) {
3625 		error = EINVAL;
3626 		goto out;
3627 	}
3628 
3629 	error = copyin(buffer, &target, sizeof(audit_token_t));
3630 	if (error != 0) {
3631 		goto out;
3632 	}
3633 
3634 	error = _proc_signal_send(target, signum, false, retval);
3635 out:
3636 	return error;
3637 }
3638 
3639 /*
3640  * proc_terminate_with_audittoken() provides support for sudden termination by audit token.
3641  * SIGKILL is issued to tracked, clean processes; otherwise,
3642  * SIGTERM is sent.
3643  */
3644 static int
proc_terminate_with_audittoken(user_addr_t buffer,size_t buffersize,int32_t * retval)3645 proc_terminate_with_audittoken(user_addr_t buffer, size_t buffersize, int32_t *retval)
3646 {
3647 	int error = 0;
3648 	audit_token_t target = INVALID_AUDIT_TOKEN_VALUE;
3649 
3650 	if (buffer == USER_ADDR_NULL || buffersize != sizeof(audit_token_t)) {
3651 		error = EINVAL;
3652 		goto out;
3653 	}
3654 
3655 	error = copyin(buffer, &target, sizeof(audit_token_t));
3656 	if (error != 0) {
3657 		goto out;
3658 	}
3659 
3660 	error = _proc_signal_send(target, SIGTERM, true, retval);
3661 out:
3662 	return error;
3663 }
3664 
3665 /*
3666  * proc_terminate_all_rsr() provides support for sudden termination of all
3667  * rsr processes. Based of user arguments, either a SIGKILL or SIGTERM is
3668  * sent to the process. EPERM would be returned if the current process
3669  * did not have privilege to send signal to a process that was marked as a
3670  * rsr process. Processes before that would have received the signal.
3671  */
3672 
3673 static int
proc_terminate_all_rsr(__unused int pid,__unused int flavor,int arg,int32_t * retval)3674 proc_terminate_all_rsr(__unused int pid, __unused int flavor, int arg, int32_t *retval)
3675 {
3676 	int error = 0;
3677 
3678 	if (arg != SIGKILL && arg != SIGTERM) {
3679 		return EINVAL;
3680 	}
3681 
3682 	if (retval == NULL) {
3683 		return EINVAL;
3684 	}
3685 
3686 	*retval = 0;
3687 	struct proc_terminate_all_rsr_struct callback_arg = {
3688 		.ptss_sig = arg, .ptss_retval = retval,
3689 	};
3690 	proc_iterate(PROC_ALLPROCLIST, proc_terminate_all_rsr_callback,
3691 	    (void *)&callback_arg, proc_terminate_all_rsr_filter, NULL);
3692 
3693 	if (*retval != 0) {
3694 		error = *retval;
3695 		*retval = 0;
3696 	} else {
3697 		*retval = arg;
3698 	}
3699 	return error;
3700 }
3701 
3702 static int
proc_terminate_all_rsr_filter(proc_t p,__unused void * arg)3703 proc_terminate_all_rsr_filter(proc_t p, __unused void *arg)
3704 {
3705 	return !!(p->p_ladvflag & P_RSR);
3706 }
3707 
3708 static int
proc_terminate_all_rsr_callback(proc_t p,void * arg)3709 proc_terminate_all_rsr_callback(proc_t p, void *arg)
3710 {
3711 	struct proc_terminate_all_rsr_struct *callback_arg = arg;
3712 	kauth_cred_t uc = kauth_cred_get();
3713 	int sig = callback_arg->ptss_sig;
3714 	int32_t *retval = callback_arg->ptss_retval;
3715 
3716 	/* Check privileges; if SIGKILL can be issued, then SIGTERM is also OK */
3717 	if (!cansignal(current_proc(), uc, p, SIGKILL)) {
3718 		*retval = EPERM;
3719 		return PROC_RETURNED_DONE;
3720 	}
3721 
3722 	proc_set_task_policy(proc_task(p), TASK_POLICY_ATTRIBUTE,
3723 	    TASK_POLICY_TERMINATED, TASK_POLICY_ENABLE);
3724 
3725 	psignal(p, sig);
3726 	return PROC_RETURNED;
3727 }
3728 
3729 /*
3730  * copy stat64 structure into vinfo_stat structure.
3731  */
3732 static void
munge_vinfo_stat(struct stat64 * sbp,struct vinfo_stat * vsbp)3733 munge_vinfo_stat(struct stat64 *sbp, struct vinfo_stat *vsbp)
3734 {
3735 	bzero(vsbp, sizeof(struct vinfo_stat));
3736 
3737 	vsbp->vst_dev = sbp->st_dev;
3738 	vsbp->vst_mode = sbp->st_mode;
3739 	vsbp->vst_nlink = sbp->st_nlink;
3740 	vsbp->vst_ino = sbp->st_ino;
3741 	vsbp->vst_uid = sbp->st_uid;
3742 	vsbp->vst_gid = sbp->st_gid;
3743 	vsbp->vst_atime = sbp->st_atimespec.tv_sec;
3744 	vsbp->vst_atimensec = sbp->st_atimespec.tv_nsec;
3745 	vsbp->vst_mtime = sbp->st_mtimespec.tv_sec;
3746 	vsbp->vst_mtimensec = sbp->st_mtimespec.tv_nsec;
3747 	vsbp->vst_ctime = sbp->st_ctimespec.tv_sec;
3748 	vsbp->vst_ctimensec = sbp->st_ctimespec.tv_nsec;
3749 	vsbp->vst_birthtime = sbp->st_birthtimespec.tv_sec;
3750 	vsbp->vst_birthtimensec = sbp->st_birthtimespec.tv_nsec;
3751 	vsbp->vst_size = sbp->st_size;
3752 	vsbp->vst_blocks = sbp->st_blocks;
3753 	vsbp->vst_blksize = sbp->st_blksize;
3754 	vsbp->vst_flags = sbp->st_flags;
3755 	vsbp->vst_gen = sbp->st_gen;
3756 	vsbp->vst_rdev = sbp->st_rdev;
3757 	vsbp->vst_qspare[0] = sbp->st_qspare[0];
3758 	vsbp->vst_qspare[1] = sbp->st_qspare[1];
3759 }
3760 
3761 int
proc_pid_rusage(int pid,int flavor,user_addr_t buffer,__unused int32_t * retval)3762 proc_pid_rusage(int pid, int flavor, user_addr_t buffer, __unused int32_t *retval)
3763 {
3764 	proc_t          p;
3765 	int             error;
3766 	int             zombie = 0;
3767 
3768 	if ((p = proc_find(pid)) == PROC_NULL) {
3769 		if ((p = proc_find_zombref(pid)) == PROC_NULL) {
3770 			return ESRCH;
3771 		}
3772 		zombie = 1;
3773 	}
3774 
3775 	/* Do we have permission to look into this? */
3776 	if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDRUSAGE, flavor, CHECK_SAME_USER))) {
3777 		goto out;
3778 	}
3779 
3780 	error = proc_get_rusage(p, flavor, buffer, zombie);
3781 
3782 out:
3783 	if (zombie) {
3784 		proc_drop_zombref(p);
3785 	} else {
3786 		proc_rele(p);
3787 	}
3788 
3789 	return error;
3790 }
3791 
3792 void
proc_archinfo(proc_t p,struct proc_archinfo * pai)3793 proc_archinfo(proc_t p, struct proc_archinfo *pai)
3794 {
3795 	proc_lock(p);
3796 	pai->p_cputype = p->p_cputype;
3797 	pai->p_cpusubtype = p->p_cpusubtype;
3798 	proc_unlock(p);
3799 }
3800 
3801 void
proc_pidcoalitioninfo(proc_t p,struct proc_pidcoalitioninfo * ppci)3802 proc_pidcoalitioninfo(proc_t p, struct proc_pidcoalitioninfo *ppci)
3803 {
3804 	bzero(ppci, sizeof(*ppci));
3805 	proc_coalitionids(p, ppci->coalition_id);
3806 }
3807 
3808 int
proc_pidexitreasoninfo(proc_t p,struct proc_exitreasoninfo * peri,struct proc_exitreasonbasicinfo * pberi)3809 proc_pidexitreasoninfo(proc_t p, struct proc_exitreasoninfo *peri, struct proc_exitreasonbasicinfo *pberi)
3810 {
3811 	uint32_t reason_data_size = 0;
3812 	int error = 0;
3813 	pid_t selfpid = proc_selfpid();
3814 
3815 	proc_lock(p);
3816 
3817 	/*
3818 	 * One (and only one) of peri and pberi must be non-NULL.
3819 	 */
3820 	assert((peri != NULL) || (pberi != NULL));
3821 	assert((peri == NULL) || (pberi == NULL));
3822 
3823 	/*
3824 	 * Allow access to the parent of the exiting
3825 	 * child or the parent debugger only.
3826 	 */
3827 	do {
3828 		if (p->p_ppid == selfpid) {
3829 			break;  /* parent => ok */
3830 		}
3831 		if ((p->p_lflag & P_LTRACED) != 0 &&
3832 		    (p->p_oppid == selfpid)) {
3833 			break;  /* parent-in-waiting => ok */
3834 		}
3835 		proc_unlock(p);
3836 		return EACCES;
3837 	} while (0);
3838 
3839 	if (p->p_exit_reason == OS_REASON_NULL) {
3840 		proc_unlock(p);
3841 		return ENOENT;
3842 	}
3843 
3844 	if (p->p_exit_reason->osr_kcd_buf != NULL) {
3845 		reason_data_size = (uint32_t)kcdata_memory_get_used_bytes(&p->p_exit_reason->osr_kcd_descriptor);
3846 	}
3847 
3848 	if (peri != NULL) {
3849 		peri->eri_namespace = p->p_exit_reason->osr_namespace;
3850 		peri->eri_code = p->p_exit_reason->osr_code;
3851 		peri->eri_flags = p->p_exit_reason->osr_flags;
3852 
3853 		if ((peri->eri_kcd_buf == 0) || (peri->eri_reason_buf_size < reason_data_size)) {
3854 			proc_unlock(p);
3855 			return ENOMEM;
3856 		}
3857 
3858 		peri->eri_reason_buf_size = reason_data_size;
3859 		if (reason_data_size != 0) {
3860 			error = copyout(p->p_exit_reason->osr_kcd_buf, (user_addr_t)peri->eri_kcd_buf, reason_data_size);
3861 		}
3862 	} else {
3863 		pberi->beri_namespace =  p->p_exit_reason->osr_namespace;
3864 		pberi->beri_code = p->p_exit_reason->osr_code;
3865 		pberi->beri_flags = p->p_exit_reason->osr_flags;
3866 		pberi->beri_reason_buf_size = reason_data_size;
3867 	}
3868 
3869 	proc_unlock(p);
3870 
3871 	return error;
3872 }
3873 
3874 /*
3875  * Wrapper to provide NOTE_EXIT_DETAIL and NOTE_EXITSTATUS
3876  * It mimics the data that is typically captured by the
3877  * EVFILT_PROC, NOTE_EXIT event mechanism.
3878  * See filt_proc() in kern_event.c.
3879  */
3880 int
proc_pidnoteexit(proc_t p,uint64_t flags,uint32_t * data)3881 proc_pidnoteexit(proc_t p, uint64_t flags, uint32_t *data)
3882 {
3883 	uint32_t exit_data = 0;
3884 	uint32_t exit_flags = (uint32_t)flags;
3885 
3886 	proc_lock(p);
3887 
3888 	/*
3889 	 * Allow access to the parent of the exiting
3890 	 * child or the parent debugger only.
3891 	 */
3892 	do {
3893 		pid_t selfpid = proc_selfpid();
3894 
3895 		if (p->p_ppid == selfpid) {
3896 			break;  /* parent => ok */
3897 		}
3898 		if ((p->p_lflag & P_LTRACED) != 0 &&
3899 		    (p->p_oppid == selfpid)) {
3900 			break;  /* parent-in-waiting => ok */
3901 		}
3902 		proc_unlock(p);
3903 		return EACCES;
3904 	} while (0);
3905 
3906 	if ((exit_flags & NOTE_EXITSTATUS) != 0) {
3907 		/* The signal and exit status */
3908 		exit_data |= (p->p_xstat & NOTE_PDATAMASK);
3909 	}
3910 
3911 	if ((exit_flags & NOTE_EXIT_DETAIL) != 0) {
3912 		/* The exit detail */
3913 		if ((p->p_lflag & P_LTERM_DECRYPTFAIL) != 0) {
3914 			exit_data |= NOTE_EXIT_DECRYPTFAIL;
3915 		}
3916 
3917 		if ((p->p_lflag & P_LTERM_JETSAM) != 0) {
3918 			exit_data |= NOTE_EXIT_MEMORY;
3919 
3920 			switch (p->p_lflag & P_JETSAM_MASK) {
3921 			case P_JETSAM_VMPAGESHORTAGE:
3922 				exit_data |= NOTE_EXIT_MEMORY_VMPAGESHORTAGE;
3923 				break;
3924 			case P_JETSAM_VMTHRASHING:
3925 				exit_data |= NOTE_EXIT_MEMORY_VMTHRASHING;
3926 				break;
3927 			case P_JETSAM_FCTHRASHING:
3928 				exit_data |= NOTE_EXIT_MEMORY_FCTHRASHING;
3929 				break;
3930 			case P_JETSAM_VNODE:
3931 				exit_data |= NOTE_EXIT_MEMORY_VNODE;
3932 				break;
3933 			case P_JETSAM_HIWAT:
3934 				exit_data |= NOTE_EXIT_MEMORY_HIWAT;
3935 				break;
3936 			case P_JETSAM_PID:
3937 				exit_data |= NOTE_EXIT_MEMORY_PID;
3938 				break;
3939 			case P_JETSAM_IDLEEXIT:
3940 				exit_data |= NOTE_EXIT_MEMORY_IDLE;
3941 				break;
3942 			}
3943 		}
3944 
3945 		if ((proc_getcsflags(p) & CS_KILLED) != 0) {
3946 			exit_data |= NOTE_EXIT_CSERROR;
3947 		}
3948 	}
3949 
3950 	proc_unlock(p);
3951 
3952 	*data = exit_data;
3953 
3954 	return 0;
3955 }
3956 
3957 int
proc_piddynkqueueinfo(int pid,int flavor,kqueue_id_t kq_id,user_addr_t ubuf,uint32_t bufsize,int32_t * retval)3958 proc_piddynkqueueinfo(int pid, int flavor, kqueue_id_t kq_id,
3959     user_addr_t ubuf, uint32_t bufsize, int32_t *retval)
3960 {
3961 	proc_t p;
3962 	int err;
3963 
3964 	if (ubuf == USER_ADDR_NULL) {
3965 		return EFAULT;
3966 	}
3967 
3968 	p = proc_find(pid);
3969 	if (p == PROC_NULL) {
3970 		return ESRCH;
3971 	}
3972 
3973 	err = proc_security_policy(p, PROC_INFO_CALL_PIDDYNKQUEUEINFO, 0, CHECK_SAME_USER);
3974 	if (err) {
3975 		goto out;
3976 	}
3977 
3978 	switch (flavor) {
3979 	case PROC_PIDDYNKQUEUE_INFO:
3980 		err = kevent_copyout_dynkqinfo(p, kq_id, ubuf, bufsize, retval);
3981 		break;
3982 	case PROC_PIDDYNKQUEUE_EXTINFO:
3983 		err = kevent_copyout_dynkqextinfo(p, kq_id, ubuf, bufsize, retval);
3984 		break;
3985 	default:
3986 		err = ENOTSUP;
3987 		break;
3988 	}
3989 
3990 out:
3991 	proc_rele(p);
3992 
3993 	return err;
3994 }
3995 
3996 #if CONFIG_PROC_UDATA_STORAGE
3997 int
proc_udata_info(int pid,int flavor,user_addr_t buffer,uint32_t bufsize,int32_t * retval)3998 proc_udata_info(int pid, int flavor, user_addr_t buffer, uint32_t bufsize, int32_t *retval)
3999 {
4000 	int err = 0;
4001 	proc_t p;
4002 
4003 	p = proc_find(pid);
4004 	if (p == PROC_NULL) {
4005 		return ESRCH;
4006 	}
4007 
4008 	/*
4009 	 * Only support calls against oneself for the moment.
4010 	 */
4011 	if (proc_getpid(p) != proc_selfpid()) {
4012 		err = EACCES;
4013 		goto out;
4014 	}
4015 
4016 	if (bufsize != sizeof(p->p_user_data)) {
4017 		err = EINVAL;
4018 		goto out;
4019 	}
4020 
4021 	switch (flavor) {
4022 	case PROC_UDATA_INFO_SET:
4023 		err = copyin(buffer, &p->p_user_data, sizeof(p->p_user_data));
4024 		break;
4025 	case PROC_UDATA_INFO_GET:
4026 		err = copyout(&p->p_user_data, buffer, sizeof(p->p_user_data));
4027 		break;
4028 	default:
4029 		err = ENOTSUP;
4030 		break;
4031 	}
4032 
4033 out:
4034 	proc_rele(p);
4035 
4036 	if (err == 0) {
4037 		*retval = 0;
4038 	}
4039 
4040 	return err;
4041 }
4042 #endif /* CONFIG_PROC_UDATA_STORAGE */
4043 
4044 
4045 int
proc_set_dyld_images(int pid,user_addr_t buffer,uint32_t buffersize,int32_t * retval)4046 proc_set_dyld_images(int pid, user_addr_t buffer, uint32_t buffersize, int32_t *retval)
4047 {
4048 	struct proc * pself = PROC_NULL;
4049 	task_t        task  = TASK_NULL;
4050 
4051 	pself = current_proc();
4052 	if (pid != proc_getpid(pself)) {
4053 		*retval = -1;
4054 		return EINVAL;
4055 	}
4056 
4057 	if (buffer == 0) {
4058 		*retval = -1;
4059 		return EINVAL;
4060 	}
4061 
4062 	task = proc_task(pself);
4063 	if (task != TASK_NULL) {
4064 		/* don't need to copyin the buffer. just setting the buffer range in the task struct */
4065 		if (task_set_dyld_info(task, buffer, buffersize, false)) {
4066 			*retval = -1;
4067 			return EINVAL;
4068 		}
4069 	}
4070 
4071 	*retval = 0;
4072 	return 0;
4073 }
4074