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