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