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