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