2 * Copyright (c) 2005-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
43 #include <sys/ioctl.h>
44 #include <sys/namei.h>
46 #include <sys/disklabel.h>
48 #include <sys/reason.h>
49 #include <sys/sysctl.h>
51 #include <sys/aio_kern.h>
52 #include <sys/kern_memorystatus.h>
54 #include <security/audit/audit.h>
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>
64 #include <vm/vm_kern.h>
65 #include <vm/vm_map.h>
66 #include <mach/host_info.h>
67 #include <mach/task_info.h>
68 #include <mach/thread_info.h>
69 #include <mach/vm_region.h>
70 #include <mach/vm_types.h>
72 #include <sys/mount_internal.h>
73 #include <sys/proc_info.h>
74 #include <sys/bsdtask_info.h>
75 #include <sys/kdebug.h>
76 #include <sys/sysproto.h>
77 #include <sys/msgbuf.h>
80 #include <sys/guarded.h>
82 #include <machine/machine_routines.h>
84 #include <kern/ipc_misc.h>
86 #include <vm/vm_protos.h>
88 /* Needed by proc_pidnoteexit(), proc_pidlistuptrs() */
89 #include <sys/event.h>
90 #include <sys/codesign.h>
92 /* Needed by proc_listcoalitions() */
93 #ifdef CONFIG_COALITIONS
94 #include <sys/coalition.h>
98 #include <security/mac_framework.h>
107 uint64_t get_dispatchqueue_offset_from_proc(void *);
108 uint64_t get_dispatchqueue_serialno_offset_from_proc(void *);
109 uint64_t get_dispatchqueue_label_offset_from_proc(void *p
);
110 uint64_t get_return_to_kernel_offset_from_proc(void *p
);
111 int proc_info_internal(int callnum
, int pid
, uint32_t flags
, uint64_t ext_id
, int flavor
, uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
114 * TODO: Replace the noinline attribute below. Currently, it serves
115 * to avoid stack bloat caused by inlining multiple functions that
116 * have large stack footprints; when the functions are independent
117 * of each other (will not both be called in any given call to the
118 * caller), this only serves to bloat the stack, as we allocate
119 * space for both functions, despite the fact that we only need a
120 * fraction of that space.
122 * Long term, these functions should not be allocating everything on
123 * the stack, and should move large allocations (the huge structs
124 * that proc info deals in) to the heap, or eliminate them if
127 * The functions that most desperately need to improve stack usage
128 * (starting with the worst offenders):
129 * proc_pidvnodepathinfo
131 * proc_pidregionpathinfo
137 * proc_pidoriginatorinfo
140 /* protos for proc_info calls */
141 static int __attribute__ ((noinline
)) proc_listpids(uint32_t type
, uint32_t tyoneinfo
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
142 static int __attribute__ ((noinline
)) proc_pidinfo(int pid
, uint32_t flags
, uint64_t ext_id
, int flavor
, uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
143 static int __attribute__ ((noinline
)) proc_pidfdinfo(int pid
, int flavor
, int fd
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
144 static int __attribute__ ((noinline
)) proc_kernmsgbuf(user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
145 static int __attribute__ ((noinline
)) proc_setcontrol(int pid
, int flavor
, uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
146 static int __attribute__ ((noinline
)) proc_pidfileportinfo(int pid
, int flavor
, mach_port_name_t name
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
147 static int __attribute__ ((noinline
)) proc_dirtycontrol(int pid
, int flavor
, uint64_t arg
, int32_t * retval
);
148 static int __attribute__ ((noinline
)) proc_terminate(int pid
, int32_t * retval
);
149 static int __attribute__ ((noinline
)) proc_pid_rusage(int pid
, int flavor
, user_addr_t buffer
, int32_t * retval
);
150 static int __attribute__ ((noinline
)) proc_pidoriginatorinfo(int pid
, int flavor
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
151 static int __attribute__ ((noinline
)) proc_listcoalitions(int flavor
, int coaltype
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
152 static int __attribute__ ((noinline
)) proc_can_use_foreground_hw(int pid
, user_addr_t reason
, uint32_t resonsize
, int32_t *retval
);
154 /* protos for procpidinfo calls */
155 static int __attribute__ ((noinline
)) proc_pidfdlist(proc_t p
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
156 static int __attribute__ ((noinline
)) proc_pidbsdinfo(proc_t p
, struct proc_bsdinfo
*pbsd
, int zombie
);
157 static int __attribute__ ((noinline
)) proc_pidshortbsdinfo(proc_t p
, struct proc_bsdshortinfo
*pbsd_shortp
, int zombie
);
158 static int __attribute__ ((noinline
)) proc_pidtaskinfo(proc_t p
, struct proc_taskinfo
*ptinfo
);
159 static int __attribute__ ((noinline
)) proc_pidthreadinfo(proc_t p
, uint64_t arg
, bool thuniqueid
, struct proc_threadinfo
*pthinfo
);
160 static int __attribute__ ((noinline
)) proc_pidthreadpathinfo(proc_t p
, uint64_t arg
, struct proc_threadwithpathinfo
*pinfo
);
161 static int __attribute__ ((noinline
)) proc_pidlistthreads(proc_t p
, bool thuniqueid
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
162 static int __attribute__ ((noinline
)) proc_pidregioninfo(proc_t p
, uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
163 static int __attribute__ ((noinline
)) proc_pidregionpathinfo(proc_t p
, uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
164 static int __attribute__ ((noinline
)) proc_pidregionpathinfo2(proc_t p
, uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
165 static int __attribute__ ((noinline
)) proc_pidregionpathinfo3(proc_t p
, uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
166 static int __attribute__ ((noinline
)) proc_pidvnodepathinfo(proc_t p
, uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
167 static int __attribute__ ((noinline
)) proc_pidpathinfo(proc_t p
, uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
168 static int __attribute__ ((noinline
)) proc_pidworkqueueinfo(proc_t p
, struct proc_workqueueinfo
*pwqinfo
);
169 static int __attribute__ ((noinline
)) proc_pidfileportlist(proc_t p
, user_addr_t buffer
, size_t buffersize
, int32_t *retval
);
170 extern void __attribute__ ((noinline
)) proc_piduniqidentifierinfo(proc_t p
, struct proc_uniqidentifierinfo
*p_uniqidinfo
);
171 static void __attribute__ ((noinline
)) proc_archinfo(proc_t p
, struct proc_archinfo
*pai
);
172 static void __attribute__ ((noinline
)) proc_pidcoalitioninfo(proc_t p
, struct proc_pidcoalitioninfo
*pci
);
173 static int __attribute__ ((noinline
)) proc_pidnoteexit(proc_t p
, uint64_t arg
, uint32_t *data
);
174 static int __attribute__ ((noinline
)) proc_pidexitreasoninfo(proc_t p
, struct proc_exitreasoninfo
*peri
, struct proc_exitreasonbasicinfo
*pberi
);
175 static int __attribute__ ((noinline
)) proc_pidoriginatorpid_uuid(uuid_t uuid
, uint32_t buffersize
, pid_t
*pid
);
176 static int __attribute__ ((noinline
)) proc_pidlistuptrs(proc_t p
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
177 static int __attribute__ ((noinline
)) proc_piddynkqueueinfo(pid_t pid
, int flavor
, kqueue_id_t id
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
178 static int __attribute__ ((noinline
)) proc_pidregionpath(proc_t p
, uint64_t arg
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t *retval
);
179 static int __attribute__ ((noinline
)) proc_pidipctableinfo(proc_t p
, struct proc_ipctableinfo
*table_info
);
181 #if CONFIG_PROC_UDATA_STORAGE
182 int __attribute__ ((noinline
)) proc_udata_info(pid_t pid
, int flavor
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
);
185 /* protos for proc_pidfdinfo calls */
186 static int __attribute__ ((noinline
)) pid_vnodeinfo(vnode_t vp
, struct fileproc
* fp
, proc_t proc
, int fd
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
187 static int __attribute__ ((noinline
)) pid_vnodeinfopath(vnode_t vp
, struct fileproc
* fp
, proc_t proc
, int fd
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
188 static int __attribute__ ((noinline
)) pid_socketinfo(socket_t so
, struct fileproc
*fp
, proc_t proc
, int fd
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
189 static int __attribute__ ((noinline
)) pid_pseminfo(struct psemnode
* psem
, struct fileproc
* fp
, proc_t proc
, int fd
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
190 static int __attribute__ ((noinline
)) pid_pshminfo(struct pshmnode
* pshm
, struct fileproc
* fp
, proc_t proc
, int fd
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
191 static int __attribute__ ((noinline
)) pid_pipeinfo(struct pipe
* p
, struct fileproc
* fp
, proc_t proc
, int fd
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
192 static int __attribute__ ((noinline
)) pid_kqueueinfo(struct kqueue
* kq
, struct fileproc
* fp
, proc_t proc
, int fd
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
);
195 /* protos for misc */
197 static int fill_vnodeinfo(vnode_t vp
, struct vnode_info
*vinfo
, boolean_t check_fsgetpath
);
198 static void fill_fileinfo(struct fileproc
*fp
, proc_t proc
, int fd
, struct proc_fileinfo
* finfo
);
199 static int proc_security_policy(proc_t targetp
, int callnum
, int flavor
, boolean_t check_same_user
);
200 static void munge_vinfo_stat(struct stat64
*sbp
, struct vinfo_stat
*vsbp
);
201 static int proc_piduuidinfo(pid_t pid
, uuid_t uuid_buf
, uint32_t buffersize
);
203 extern int proc_pidpathinfo_internal(proc_t p
, __unused
uint64_t arg
, char *buf
, uint32_t buffersize
, __unused
int32_t *retval
);
204 extern int cansignal(struct proc
*, kauth_cred_t
, struct proc
*, int);
205 extern int proc_get_rusage(proc_t proc
, int flavor
, user_addr_t buffer
, int is_zombie
);
207 #define CHECK_SAME_USER TRUE
208 #define NO_CHECK_SAME_USER FALSE
211 get_dispatchqueue_offset_from_proc(void *p
)
214 proc_t pself
= (proc_t
)p
;
215 return pself
->p_dispatchqueue_offset
;
222 get_dispatchqueue_serialno_offset_from_proc(void *p
)
225 proc_t pself
= (proc_t
)p
;
226 return pself
->p_dispatchqueue_serialno_offset
;
233 get_dispatchqueue_label_offset_from_proc(void *p
)
236 proc_t pself
= (proc_t
)p
;
237 return pself
->p_dispatchqueue_label_offset
;
244 get_return_to_kernel_offset_from_proc(void *p
)
247 proc_t pself
= (proc_t
)p
;
248 return pself
->p_return_to_kernel_offset
;
254 /***************************** proc_info ********************/
257 proc_info(__unused
struct proc
*p
, struct proc_info_args
* uap
, int32_t *retval
)
259 return proc_info_internal(uap
->callnum
, uap
->pid
, 0, 0, uap
->flavor
, uap
->arg
, uap
->buffer
, uap
->buffersize
, retval
);
263 proc_info_extended_id(__unused
struct proc
*p
, struct proc_info_extended_id_args
*uap
, int32_t *retval
)
265 uint32_t flags
= uap
->flags
;
267 if ((flags
& (PIF_COMPARE_IDVERSION
| PIF_COMPARE_UNIQUEID
)) == (PIF_COMPARE_IDVERSION
| PIF_COMPARE_UNIQUEID
)) {
271 return proc_info_internal(uap
->callnum
, uap
->pid
, flags
, uap
->ext_id
, uap
->flavor
, uap
->arg
, uap
->buffer
, uap
->buffersize
, retval
);
275 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
)
278 case PROC_INFO_CALL_LISTPIDS
:
279 /* pid contains type and flavor contains typeinfo */
280 return proc_listpids(pid
, flavor
, buffer
, buffersize
, retval
);
281 case PROC_INFO_CALL_PIDINFO
:
282 return proc_pidinfo(pid
, flags
, ext_id
, flavor
, arg
, buffer
, buffersize
, retval
);
283 case PROC_INFO_CALL_PIDFDINFO
:
284 return proc_pidfdinfo(pid
, flavor
, (int)arg
, buffer
, buffersize
, retval
);
285 case PROC_INFO_CALL_KERNMSGBUF
:
286 return proc_kernmsgbuf(buffer
, buffersize
, retval
);
287 case PROC_INFO_CALL_SETCONTROL
:
288 return proc_setcontrol(pid
, flavor
, arg
, buffer
, buffersize
, retval
);
289 case PROC_INFO_CALL_PIDFILEPORTINFO
:
290 return proc_pidfileportinfo(pid
, flavor
, (mach_port_name_t
)arg
, buffer
, buffersize
, retval
);
291 case PROC_INFO_CALL_TERMINATE
:
292 return proc_terminate(pid
, retval
);
293 case PROC_INFO_CALL_DIRTYCONTROL
:
294 return proc_dirtycontrol(pid
, flavor
, arg
, retval
);
295 case PROC_INFO_CALL_PIDRUSAGE
:
296 return proc_pid_rusage(pid
, flavor
, buffer
, retval
);
297 case PROC_INFO_CALL_PIDORIGINATORINFO
:
298 return proc_pidoriginatorinfo(pid
, flavor
, buffer
, buffersize
, retval
);
299 case PROC_INFO_CALL_LISTCOALITIONS
:
300 return proc_listcoalitions(pid
/* flavor */, flavor
/* coaltype */, buffer
,
302 case PROC_INFO_CALL_CANUSEFGHW
:
303 return proc_can_use_foreground_hw(pid
, buffer
, buffersize
, retval
);
304 case PROC_INFO_CALL_PIDDYNKQUEUEINFO
:
305 return proc_piddynkqueueinfo(pid
, flavor
, (kqueue_id_t
)arg
, buffer
, buffersize
, retval
);
306 #if CONFIG_PROC_UDATA_STORAGE
307 case PROC_INFO_CALL_UDATA_INFO
:
308 return proc_udata_info(pid
, flavor
, buffer
, buffersize
, retval
);
309 #endif /* CONFIG_PROC_UDATA_STORAGE */
317 /******************* proc_listpids routine ****************/
319 proc_listpids(uint32_t type
, uint32_t typeinfo
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
)
321 uint32_t numprocs
= 0;
330 struct proclist
*current_list
;
332 /* Do we have permission to look into this? */
333 if ((error
= proc_security_policy(PROC_NULL
, PROC_INFO_CALL_LISTPIDS
, type
, NO_CHECK_SAME_USER
))) {
337 /* if the buffer is null, return num of procs */
338 if (buffer
== (user_addr_t
)0) {
339 *retval
= ((nprocs
+ 20) * sizeof(int));
343 if (buffersize
< sizeof(int)) {
346 wantpids
= buffersize
/ sizeof(int);
347 if ((nprocs
+ 20) > 0) {
348 numprocs
= (uint32_t)(nprocs
+ 20);
350 if (numprocs
> wantpids
) {
354 kbuf
= kheap_alloc(KHEAP_TEMP
, numprocs
* sizeof(int),
364 current_list
= &allproc
;
366 LIST_FOREACH(p
, current_list
, p_list
) {
370 if (p
->p_pgrpid
!= (pid_t
)typeinfo
) {
375 if ((p
->p_ppid
!= (pid_t
)typeinfo
) && (((p
->p_lflag
& P_LTRACED
) == 0) || (p
->p_oppid
!= (pid_t
)typeinfo
))) {
384 /* racy but list lock is held */
385 if ((p
->p_flag
& P_CONTROLT
) == 0 ||
386 (p
->p_pgrp
== NULL
) || (p
->p_pgrp
->pg_session
== NULL
) ||
387 (tp
= SESSION_TP(p
->p_pgrp
->pg_session
)) == TTY_NULL
||
388 tp
->t_dev
!= (dev_t
)typeinfo
) {
393 if (p
->p_ucred
== NULL
) {
396 kauth_cred_t my_cred
;
399 my_cred
= kauth_cred_proc_ref(p
);
400 uid
= kauth_cred_getuid(my_cred
);
401 kauth_cred_unref(&my_cred
);
402 if (uid
!= (uid_t
)typeinfo
) {
408 if (p
->p_ucred
== NULL
) {
411 kauth_cred_t my_cred
;
414 my_cred
= kauth_cred_proc_ref(p
);
415 uid
= kauth_cred_getruid(my_cred
);
416 kauth_cred_unref(&my_cred
);
417 if (uid
!= (uid_t
)typeinfo
) {
423 if (p
->p_kdebug
== 0) {
442 if ((n
< numprocs
) && (current_list
== &allproc
)) {
443 current_list
= &zombproc
;
450 error
= copyout((caddr_t
)ptr
, buffer
, n
* sizeof(int));
452 *retval
= (n
* sizeof(int));
454 kheap_free(KHEAP_TEMP
, kbuf
, numprocs
* sizeof(int));
460 /********************************** proc_pidfdlist routines ********************************/
463 proc_fdlist_internal(proc_t p
, struct proc_fdinfo
*pfd
, size_t numfds
)
471 if (count
>= numfds
) {
474 file_type_t fdtype
= FILEGLOB_DTYPE(fp
->fp_glob
);
475 pfd
[count
].proc_fd
= fdt_foreach_fd();
476 pfd
[count
].proc_fdtype
= (fdtype
!= DTYPE_ATALK
) ?
477 fdtype
: PROX_FDTYPE_ATALK
;
486 proc_pidfdlist(proc_t p
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
)
494 if (p
->p_fd
->fd_nfiles
> 0) {
495 numfds
= (uint32_t)p
->p_fd
->fd_nfiles
;
498 if (buffer
== (user_addr_t
) 0) {
500 *retval
= (numfds
* sizeof(struct proc_fdinfo
));
504 /* buffersize is big enough atleast for one struct */
505 needfds
= buffersize
/ sizeof(struct proc_fdinfo
);
507 if (numfds
> needfds
) {
511 kbuf
= kheap_alloc(KHEAP_TEMP
, numfds
* sizeof(struct proc_fdinfo
),
517 /* cannot overflow due to count <= numfds */
518 count
= (uint32_t)proc_fdlist_internal(p
, (struct proc_fdinfo
*)kbuf
, (size_t)numfds
);
520 error
= copyout(kbuf
, buffer
, count
* sizeof(struct proc_fdinfo
));
521 kheap_free(KHEAP_TEMP
, kbuf
, numfds
* sizeof(struct proc_fdinfo
));
523 *retval
= count
* sizeof(struct proc_fdinfo
);
529 * KPI variant of proc_pidfdlist.
531 * Caller is responsible for adding margin to *count when calling this in
532 * circumstances where file descriptors can appear/disappear between the
533 * two calls to this function.
536 proc_fdlist(proc_t p
, struct proc_fdinfo
*buf
, size_t *count
)
538 if (p
== NULL
|| count
== NULL
) {
544 *count
= (size_t)max(min(p
->p_fd
->fd_lastfile
+ 1, p
->p_fd
->fd_nfiles
), 0);
549 *count
= proc_fdlist_internal(p
, buf
, *count
);
554 * Helper functions for proc_pidfileportlist.
557 proc_fileport_count(__unused mach_port_name_t name
,
558 __unused
struct fileglob
*fg
, void *arg
)
560 size_t *counter
= arg
;
566 struct fileport_fdtype_args
{
567 struct proc_fileportinfo
*ffa_pfi
;
568 struct proc_fileportinfo
*ffa_pfi_end
;
572 proc_fileport_fdtype(mach_port_name_t name
, struct fileglob
*fg
, void *arg
)
574 struct fileport_fdtype_args
*ffa
= arg
;
576 if (ffa
->ffa_pfi
!= ffa
->ffa_pfi_end
) {
577 file_type_t fdtype
= FILEGLOB_DTYPE(fg
);
579 ffa
->ffa_pfi
->proc_fdtype
= (fdtype
!= DTYPE_ATALK
) ?
580 fdtype
: PROX_FDTYPE_ATALK
;
581 ffa
->ffa_pfi
->proc_fileport
= name
;
583 return 0; /* keep walking */
585 return -1; /* stop the walk! */
590 proc_pidfileportlist(proc_t p
,
591 user_addr_t buffer
, size_t buffersize
, int32_t *retval
)
595 struct proc_fileportinfo
*pfi
;
596 size_t needfileports
, numfileports
;
597 struct fileport_fdtype_args ffa
;
600 needfileports
= buffersize
/ sizeof(*pfi
);
601 if ((user_addr_t
)0 == buffer
|| needfileports
> (size_t)maxfilesperproc
) {
603 * Either (i) the user is asking for a fileport count,
604 * or (ii) the number of fileports they're asking for is
605 * larger than the maximum number of open files (!); count
606 * them to bound subsequent heap allocations.
609 switch (fileport_walk(p
->task
,
610 proc_fileport_count
, &numfileports
)) {
613 case KERN_RESOURCE_SHORTAGE
:
615 case KERN_INVALID_TASK
:
621 if (numfileports
== 0) {
622 *retval
= 0; /* none at all, bail */
625 if ((user_addr_t
)0 == buffer
) {
626 numfileports
+= 20; /* accelerate convergence */
627 *retval
= (int32_t)MIN(numfileports
* sizeof(*pfi
), INT32_MAX
);
630 if (needfileports
> numfileports
) {
631 needfileports
= numfileports
;
635 assert(buffersize
>= PROC_PIDLISTFILEPORTS_SIZE
);
637 kbufsize
= needfileports
* sizeof(*pfi
);
638 pfi
= kbuf
= kheap_alloc(KHEAP_TEMP
, kbufsize
, Z_WAITOK
| Z_ZERO
);
644 ffa
.ffa_pfi_end
= pfi
+ needfileports
;
646 switch (fileport_walk(p
->task
, proc_fileport_fdtype
, &ffa
)) {
650 if ((numfileports
= (size_t)(pfi
- (typeof(pfi
))kbuf
)) == 0) {
653 if (numfileports
> needfileports
) {
654 panic("more fileports returned than requested");
656 error
= copyout(kbuf
, buffer
, numfileports
* sizeof(*pfi
));
658 case KERN_RESOURCE_SHORTAGE
:
661 case KERN_INVALID_TASK
:
668 kheap_free(KHEAP_TEMP
, kbuf
, kbufsize
);
670 *retval
= (int32_t)MIN(numfileports
* sizeof(*pfi
), INT32_MAX
);
676 proc_pidbsdinfo(proc_t p
, struct proc_bsdinfo
* pbsd
, int zombie
)
679 struct session
*sessionp
= NULL
;
681 kauth_cred_t my_cred
;
684 sessionp
= proc_session(p
);
686 my_cred
= kauth_cred_proc_ref(p
);
687 bzero(pbsd
, sizeof(struct proc_bsdinfo
));
688 pbsd
->pbi_status
= p
->p_stat
;
689 pbsd
->pbi_xstatus
= p
->p_xstat
;
690 pbsd
->pbi_pid
= p
->p_pid
;
691 pbsd
->pbi_ppid
= p
->p_ppid
;
692 pbsd
->pbi_uid
= kauth_cred_getuid(my_cred
);
693 pbsd
->pbi_gid
= kauth_cred_getgid(my_cred
);
694 pbsd
->pbi_ruid
= kauth_cred_getruid(my_cred
);
695 pbsd
->pbi_rgid
= kauth_cred_getrgid(my_cred
);
696 pbsd
->pbi_svuid
= kauth_cred_getsvuid(my_cred
);
697 pbsd
->pbi_svgid
= kauth_cred_getsvgid(my_cred
);
698 kauth_cred_unref(&my_cred
);
700 pbsd
->pbi_nice
= p
->p_nice
;
701 pbsd
->pbi_start_tvsec
= p
->p_start
.tv_sec
;
702 pbsd
->pbi_start_tvusec
= p
->p_start
.tv_usec
;
703 bcopy(&p
->p_comm
, &pbsd
->pbi_comm
[0], MAXCOMLEN
);
704 pbsd
->pbi_comm
[MAXCOMLEN
- 1] = '\0';
705 bcopy(&p
->p_name
, &pbsd
->pbi_name
[0], 2 * MAXCOMLEN
);
706 pbsd
->pbi_name
[(2 * MAXCOMLEN
) - 1] = '\0';
709 if ((p
->p_flag
& P_SYSTEM
) == P_SYSTEM
) {
710 pbsd
->pbi_flags
|= PROC_FLAG_SYSTEM
;
712 if ((p
->p_lflag
& P_LTRACED
) == P_LTRACED
) {
713 pbsd
->pbi_flags
|= PROC_FLAG_TRACED
;
715 if ((p
->p_lflag
& P_LEXIT
) == P_LEXIT
) {
716 pbsd
->pbi_flags
|= PROC_FLAG_INEXIT
;
718 if ((p
->p_lflag
& P_LPPWAIT
) == P_LPPWAIT
) {
719 pbsd
->pbi_flags
|= PROC_FLAG_PPWAIT
;
721 if ((p
->p_flag
& P_LP64
) == P_LP64
) {
722 pbsd
->pbi_flags
|= PROC_FLAG_LP64
;
724 if ((p
->p_flag
& P_CONTROLT
) == P_CONTROLT
) {
725 pbsd
->pbi_flags
|= PROC_FLAG_CONTROLT
;
727 if ((p
->p_flag
& P_THCWD
) == P_THCWD
) {
728 pbsd
->pbi_flags
|= PROC_FLAG_THCWD
;
730 if ((p
->p_flag
& P_SUGID
) == P_SUGID
) {
731 pbsd
->pbi_flags
|= PROC_FLAG_PSUGID
;
733 if ((p
->p_flag
& P_EXEC
) == P_EXEC
) {
734 pbsd
->pbi_flags
|= PROC_FLAG_EXEC
;
737 if (sessionp
!= SESSION_NULL
) {
738 if (SESS_LEADER(p
, sessionp
)) {
739 pbsd
->pbi_flags
|= PROC_FLAG_SLEADER
;
741 if (sessionp
->s_ttyvp
) {
742 pbsd
->pbi_flags
|= PROC_FLAG_CTTY
;
746 #if CONFIG_DELAY_IDLE_SLEEP
747 if ((p
->p_flag
& P_DELAYIDLESLEEP
) == P_DELAYIDLESLEEP
) {
748 pbsd
->pbi_flags
|= PROC_FLAG_DELAYIDLESLEEP
;
750 #endif /* CONFIG_DELAY_IDLE_SLEEP */
752 switch (PROC_CONTROL_STATE(p
)) {
754 pbsd
->pbi_flags
|= PROC_FLAG_PC_THROTTLE
;
757 pbsd
->pbi_flags
|= PROC_FLAG_PC_SUSP
;
760 pbsd
->pbi_flags
|= PROC_FLAG_PC_KILL
;
765 switch (PROC_ACTION_STATE(p
)) {
767 pbsd
->pbi_flags
|= PROC_FLAG_PA_THROTTLE
;
770 pbsd
->pbi_flags
|= PROC_FLAG_PA_SUSP
;
775 /* if process is a zombie skip bg state */
776 if ((zombie
== 0) && (p
->p_stat
!= SZOMB
) && (p
->task
!= TASK_NULL
)) {
777 proc_get_darwinbgstate(p
->task
, &pbsd
->pbi_flags
);
781 pbsd
->pbi_nfiles
= p
->p_fd
->fd_nfiles
;
784 pbsd
->e_tdev
= NODEV
;
785 if (pg
!= PGRP_NULL
) {
786 pbsd
->pbi_pgid
= p
->p_pgrpid
;
787 pbsd
->pbi_pjobc
= pg
->pg_jobc
;
788 if ((p
->p_flag
& P_CONTROLT
) && (sessionp
!= SESSION_NULL
) && (tp
= SESSION_TP(sessionp
))) {
789 pbsd
->e_tdev
= tp
->t_dev
;
790 pbsd
->e_tpgid
= sessionp
->s_ttypgrpid
;
793 if (sessionp
!= SESSION_NULL
) {
794 session_rele(sessionp
);
796 if (pg
!= PGRP_NULL
) {
805 proc_pidshortbsdinfo(proc_t p
, struct proc_bsdshortinfo
* pbsd_shortp
, int zombie
)
807 bzero(pbsd_shortp
, sizeof(struct proc_bsdshortinfo
));
808 pbsd_shortp
->pbsi_pid
= p
->p_pid
;
809 pbsd_shortp
->pbsi_ppid
= p
->p_ppid
;
810 pbsd_shortp
->pbsi_pgid
= p
->p_pgrpid
;
811 pbsd_shortp
->pbsi_status
= p
->p_stat
;
812 bcopy(&p
->p_comm
, &pbsd_shortp
->pbsi_comm
[0], MAXCOMLEN
);
813 pbsd_shortp
->pbsi_comm
[MAXCOMLEN
- 1] = '\0';
815 pbsd_shortp
->pbsi_flags
= 0;
816 if ((p
->p_flag
& P_SYSTEM
) == P_SYSTEM
) {
817 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_SYSTEM
;
819 if ((p
->p_lflag
& P_LTRACED
) == P_LTRACED
) {
820 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_TRACED
;
822 if ((p
->p_lflag
& P_LEXIT
) == P_LEXIT
) {
823 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_INEXIT
;
825 if ((p
->p_lflag
& P_LPPWAIT
) == P_LPPWAIT
) {
826 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_PPWAIT
;
828 if ((p
->p_flag
& P_LP64
) == P_LP64
) {
829 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_LP64
;
831 if ((p
->p_flag
& P_CONTROLT
) == P_CONTROLT
) {
832 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_CONTROLT
;
834 if ((p
->p_flag
& P_THCWD
) == P_THCWD
) {
835 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_THCWD
;
837 if ((p
->p_flag
& P_SUGID
) == P_SUGID
) {
838 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_PSUGID
;
840 if ((p
->p_flag
& P_EXEC
) == P_EXEC
) {
841 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_EXEC
;
843 #if CONFIG_DELAY_IDLE_SLEEP
844 if ((p
->p_flag
& P_DELAYIDLESLEEP
) == P_DELAYIDLESLEEP
) {
845 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_DELAYIDLESLEEP
;
847 #endif /* CONFIG_DELAY_IDLE_SLEEP */
849 switch (PROC_CONTROL_STATE(p
)) {
851 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_PC_THROTTLE
;
854 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_PC_SUSP
;
857 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_PC_KILL
;
862 switch (PROC_ACTION_STATE(p
)) {
864 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_PA_THROTTLE
;
867 pbsd_shortp
->pbsi_flags
|= PROC_FLAG_PA_SUSP
;
872 /* if process is a zombie skip bg state */
873 if ((zombie
== 0) && (p
->p_stat
!= SZOMB
) && (p
->task
!= TASK_NULL
)) {
874 proc_get_darwinbgstate(p
->task
, &pbsd_shortp
->pbsi_flags
);
877 pbsd_shortp
->pbsi_uid
= p
->p_uid
;
878 pbsd_shortp
->pbsi_gid
= p
->p_gid
;
879 pbsd_shortp
->pbsi_ruid
= p
->p_ruid
;
880 pbsd_shortp
->pbsi_rgid
= p
->p_rgid
;
881 pbsd_shortp
->pbsi_svuid
= p
->p_svuid
;
882 pbsd_shortp
->pbsi_svgid
= p
->p_svgid
;
888 proc_pidtaskinfo(proc_t p
, struct proc_taskinfo
* ptinfo
)
894 bzero(ptinfo
, sizeof(struct proc_taskinfo
));
895 fill_taskprocinfo(task
, (struct proc_taskinfo_internal
*)ptinfo
);
903 proc_pidthreadinfo(proc_t p
, uint64_t arg
, bool thuniqueid
, struct proc_threadinfo
*pthinfo
)
906 uint64_t threadaddr
= (uint64_t)arg
;
908 bzero(pthinfo
, sizeof(struct proc_threadinfo
));
910 error
= fill_taskthreadinfo(p
->task
, threadaddr
, thuniqueid
, (struct proc_threadinfo_internal
*)pthinfo
, NULL
, NULL
);
919 bsd_hasthreadname(void *uth
)
921 struct uthread
*ut
= (struct uthread
*)uth
;
923 /* This doesn't check for the empty string; do we care? */
932 bsd_getthreadname(void *uth
, char *buffer
)
934 struct uthread
*ut
= (struct uthread
*)uth
;
936 bcopy(ut
->pth_name
, buffer
, MAXTHREADNAMESIZE
);
943 * This is known to race with regards to the contents of the thread name; concurrent
944 * callers may result in a garbled name.
947 bsd_setthreadname(void *uth
, const char *name
)
949 struct uthread
*ut
= (struct uthread
*)uth
;
950 char * name_buf
= NULL
;
953 /* If there is no existing thread name, allocate a buffer for one. */
954 name_buf
= kalloc(MAXTHREADNAMESIZE
);
956 bzero(name_buf
, MAXTHREADNAMESIZE
);
958 /* Someone could conceivably have named the thread at the same time we did. */
959 if (!OSCompareAndSwapPtr(NULL
, name_buf
, &ut
->pth_name
)) {
960 kfree(name_buf
, MAXTHREADNAMESIZE
);
963 kernel_debug_string_simple(TRACE_STRING_THREADNAME_PREV
, ut
->pth_name
);
966 strncpy(ut
->pth_name
, name
, MAXTHREADNAMESIZE
- 1);
967 kernel_debug_string_simple(TRACE_STRING_THREADNAME
, ut
->pth_name
);
971 bsd_copythreadname(void *dst_uth
, void *src_uth
)
973 struct uthread
*dst_ut
= (struct uthread
*)dst_uth
;
974 struct uthread
*src_ut
= (struct uthread
*)src_uth
;
976 if (src_ut
->pth_name
== NULL
) {
980 if (dst_ut
->pth_name
== NULL
) {
981 dst_ut
->pth_name
= (char *)kalloc(MAXTHREADNAMESIZE
);
982 if (dst_ut
->pth_name
== NULL
) {
987 bcopy(src_ut
->pth_name
, dst_ut
->pth_name
, MAXTHREADNAMESIZE
);
992 bsd_threadcdir(void * uth
, void *vptr
, int *vidp
)
994 struct uthread
* ut
= (struct uthread
*)uth
;
996 vnode_t
*vpp
= (vnode_t
*)vptr
;
1011 proc_pidthreadpathinfo(proc_t p
, uint64_t arg
, struct proc_threadwithpathinfo
*pinfo
)
1013 vnode_t vp
= NULLVP
;
1016 uint64_t threadaddr
= (uint64_t)arg
;
1019 bzero(pinfo
, sizeof(struct proc_threadwithpathinfo
));
1021 error
= fill_taskthreadinfo(p
->task
, threadaddr
, 0, (struct proc_threadinfo_internal
*)&pinfo
->pt
, (void *)&vp
, &vid
);
1026 if ((vp
!= NULLVP
) && ((vnode_getwithvid(vp
, vid
)) == 0)) {
1027 error
= fill_vnodeinfo(vp
, &pinfo
->pvip
.vip_vi
, FALSE
);
1030 vn_getpath(vp
, &pinfo
->pvip
.vip_path
[0], &count
);
1031 pinfo
->pvip
.vip_path
[MAXPATHLEN
- 1] = 0;
1041 proc_pidlistthreads(proc_t p
, bool thuniqueid
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
)
1047 uint32_t numthreads
= 0;
1049 int num
= get_numthreads(p
->task
) + 10;
1051 numthreads
= (uint32_t)num
;
1054 count
= buffersize
/ (sizeof(uint64_t));
1056 if (numthreads
> count
) {
1060 kbuf
= kheap_alloc(KHEAP_TEMP
,
1061 numthreads
* sizeof(uint64_t), Z_WAITOK
| Z_ZERO
);
1066 ret
= fill_taskthreadlist(p
->task
, kbuf
, numthreads
, thuniqueid
);
1068 error
= copyout(kbuf
, buffer
, ret
);
1069 kheap_free(KHEAP_TEMP
, kbuf
, numthreads
* sizeof(uint64_t));
1078 proc_pidregioninfo(proc_t p
, uint64_t arg
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t *retval
)
1080 struct proc_regioninfo preginfo
;
1083 bzero(&preginfo
, sizeof(struct proc_regioninfo
));
1084 ret
= fill_procregioninfo( p
->task
, arg
, (struct proc_regioninfo_internal
*)&preginfo
, (uintptr_t *)0, (uint32_t *)0);
1088 error
= copyout(&preginfo
, buffer
, sizeof(struct proc_regioninfo
));
1090 *retval
= sizeof(struct proc_regioninfo
);
1097 proc_pidregionpathinfo(proc_t p
, uint64_t arg
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t *retval
)
1099 struct proc_regionwithpathinfo preginfo
;
1101 uintptr_t vnodeaddr
= 0;
1102 uint32_t vnodeid
= 0;
1106 bzero(&preginfo
, sizeof(struct proc_regionwithpathinfo
));
1108 ret
= fill_procregioninfo( p
->task
, arg
, (struct proc_regioninfo_internal
*)&preginfo
.prp_prinfo
, (uintptr_t *)&vnodeaddr
, (uint32_t *)&vnodeid
);
1113 vp
= (vnode_t
)vnodeaddr
;
1114 if ((vnode_getwithvid(vp
, vnodeid
)) == 0) {
1115 /* FILL THE VNODEINFO */
1116 error
= fill_vnodeinfo(vp
, &preginfo
.prp_vip
.vip_vi
, FALSE
);
1118 vn_getpath(vp
, &preginfo
.prp_vip
.vip_path
[0], &count
);
1119 /* Always make sure it is null terminated */
1120 preginfo
.prp_vip
.vip_path
[MAXPATHLEN
- 1] = 0;
1124 error
= copyout(&preginfo
, buffer
, sizeof(struct proc_regionwithpathinfo
));
1126 *retval
= sizeof(struct proc_regionwithpathinfo
);
1132 proc_pidregionpathinfo2(proc_t p
, uint64_t arg
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t *retval
)
1134 struct proc_regionwithpathinfo preginfo
;
1136 uintptr_t vnodeaddr
= 0;
1137 uint32_t vnodeid
= 0;
1141 bzero(&preginfo
, sizeof(struct proc_regionwithpathinfo
));
1143 ret
= fill_procregioninfo_onlymappedvnodes( p
->task
, arg
, (struct proc_regioninfo_internal
*)&preginfo
.prp_prinfo
, (uintptr_t *)&vnodeaddr
, (uint32_t *)&vnodeid
);
1151 vp
= (vnode_t
)vnodeaddr
;
1152 if ((vnode_getwithvid(vp
, vnodeid
)) == 0) {
1153 /* FILL THE VNODEINFO */
1154 error
= fill_vnodeinfo(vp
, &preginfo
.prp_vip
.vip_vi
, FALSE
);
1156 vn_getpath(vp
, &preginfo
.prp_vip
.vip_path
[0], &count
);
1157 /* Always make sure it is null terminated */
1158 preginfo
.prp_vip
.vip_path
[MAXPATHLEN
- 1] = 0;
1164 error
= copyout(&preginfo
, buffer
, sizeof(struct proc_regionwithpathinfo
));
1166 *retval
= sizeof(struct proc_regionwithpathinfo
);
1172 proc_pidregionpath(proc_t p
, uint64_t arg
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t *retval
)
1174 struct proc_regionpath path
= {};
1176 uintptr_t vnodeaddr
= 0;
1177 uint32_t vnodeid
= 0;
1180 ret
= find_region_details(p
->task
, (vm_map_offset_t
) arg
,
1181 (uintptr_t *)&vnodeaddr
, (uint32_t *)&vnodeid
,
1182 &path
.prpo_addr
, &path
.prpo_regionlength
);
1190 vp
= (vnode_t
)vnodeaddr
;
1191 if ((vnode_getwithvid(vp
, vnodeid
)) == 0) {
1192 int count
= MAXPATHLEN
;
1193 vn_getpath(vp
, &path
.prpo_path
[0], &count
);
1194 /* Always make sure it is null terminated */
1195 path
.prpo_path
[MAXPATHLEN
- 1] = 0;
1201 error
= copyout(&path
, buffer
, sizeof(struct proc_regionpath
));
1203 *retval
= sizeof(struct proc_regionpath
);
1209 proc_pidregionpathinfo3(proc_t p
, uint64_t arg
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t *retval
)
1211 struct proc_regionwithpathinfo preginfo
;
1213 uintptr_t vnodeaddr
;
1219 /* Loop while looking for vnodes that match dev_t filter */
1221 bzero(&preginfo
, sizeof(struct proc_regionwithpathinfo
));
1225 ret
= fill_procregioninfo_onlymappedvnodes( p
->task
, addr
, (struct proc_regioninfo_internal
*)&preginfo
.prp_prinfo
, (uintptr_t *)&vnodeaddr
, (uint32_t *)&vnodeid
);
1233 vp
= (vnode_t
)vnodeaddr
;
1234 if ((vnode_getwithvid(vp
, vnodeid
)) == 0) {
1235 /* Check if the vnode matches the filter, otherwise loop looking for the next memory region backed by a vnode */
1236 struct vnode_attr va
;
1238 memset(&va
, 0, sizeof(va
));
1240 VATTR_WANTED(&va
, va_fsid
);
1241 VATTR_WANTED(&va
, va_fsid64
);
1243 ret
= vnode_getattr(vp
, &va
, vfs_context_current());
1249 if (vnode_get_va_fsid(&va
) == arg
) {
1250 /* FILL THE VNODEINFO */
1251 error
= fill_vnodeinfo(vp
, &preginfo
.prp_vip
.vip_vi
, FALSE
);
1253 vn_getpath(vp
, &preginfo
.prp_vip
.vip_path
[0], &count
);
1254 /* Always make sure it is null terminated */
1255 preginfo
.prp_vip
.vip_path
[MAXPATHLEN
- 1] = 0;
1264 addr
= preginfo
.prp_prinfo
.pri_address
+ preginfo
.prp_prinfo
.pri_size
;
1267 error
= copyout(&preginfo
, buffer
, sizeof(struct proc_regionwithpathinfo
));
1269 *retval
= sizeof(struct proc_regionwithpathinfo
);
1275 * Path is relative to current process directory; may different from current
1279 proc_pidvnodepathinfo(proc_t p
, __unused
uint64_t arg
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t *retval
)
1281 struct proc_vnodepathinfo pvninfo
;
1283 vnode_t vncdirvp
= NULLVP
;
1284 uint32_t vncdirid
= 0;
1285 vnode_t vnrdirvp
= NULLVP
;
1286 uint32_t vnrdirid
= 0;
1289 bzero(&pvninfo
, sizeof(struct proc_vnodepathinfo
));
1292 if (p
->p_fd
->fd_cdir
) {
1293 vncdirvp
= p
->p_fd
->fd_cdir
;
1294 vncdirid
= p
->p_fd
->fd_cdir
->v_id
;
1296 if (p
->p_fd
->fd_rdir
) {
1297 vnrdirvp
= p
->p_fd
->fd_rdir
;
1298 vnrdirid
= p
->p_fd
->fd_rdir
->v_id
;
1302 if (vncdirvp
!= NULLVP
) {
1303 if ((error
= vnode_getwithvid(vncdirvp
, vncdirid
)) == 0) {
1304 /* FILL THE VNODEINFO */
1305 error
= fill_vnodeinfo(vncdirvp
, &pvninfo
.pvi_cdir
.vip_vi
, TRUE
);
1308 vn_getpath(vncdirvp
, &pvninfo
.pvi_cdir
.vip_path
[0], &count
);
1309 pvninfo
.pvi_cdir
.vip_path
[MAXPATHLEN
- 1] = 0;
1311 vnode_put(vncdirvp
);
1317 if ((error
== 0) && (vnrdirvp
!= NULLVP
)) {
1318 if ((error
= vnode_getwithvid(vnrdirvp
, vnrdirid
)) == 0) {
1319 /* FILL THE VNODEINFO */
1320 error
= fill_vnodeinfo(vnrdirvp
, &pvninfo
.pvi_rdir
.vip_vi
, TRUE
);
1323 vn_getpath(vnrdirvp
, &pvninfo
.pvi_rdir
.vip_path
[0], &count
);
1324 pvninfo
.pvi_rdir
.vip_path
[MAXPATHLEN
- 1] = 0;
1326 vnode_put(vnrdirvp
);
1332 error
= copyout(&pvninfo
, buffer
, sizeof(struct proc_vnodepathinfo
));
1334 *retval
= sizeof(struct proc_vnodepathinfo
);
1342 proc_pidpathinfo(proc_t p
, __unused
uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, __unused
int32_t *retval
)
1346 int len
= buffersize
;
1351 if (tvp
== NULLVP
) {
1355 buf
= kheap_alloc(KHEAP_TEMP
, buffersize
, Z_WAITOK
| Z_ZERO
);
1360 error
= proc_pidpathinfo_internal(p
, arg
, buf
, buffersize
, retval
);
1362 error
= copyout(buf
, buffer
, len
);
1364 kheap_free(KHEAP_TEMP
, buf
, buffersize
);
1369 proc_pidpathinfo_internal(proc_t p
, __unused
uint64_t arg
, char *buf
, uint32_t buffersize
, __unused
int32_t *retval
)
1373 vnode_t nvp
= NULLVP
;
1374 int len
= buffersize
;
1378 if (tvp
== NULLVP
) {
1382 vid
= vnode_vid(tvp
);
1383 error
= vnode_getwithvid(tvp
, vid
);
1385 error
= vn_getpath_fsenter(tvp
, buf
, &len
);
1388 error
= vnode_lookup(buf
, 0, &nvp
, vfs_context_current());
1389 if ((error
== 0) && (nvp
!= NULLVP
)) {
1399 proc_pidworkqueueinfo(proc_t p
, struct proc_workqueueinfo
*pwqinfo
)
1403 bzero(pwqinfo
, sizeof(struct proc_workqueueinfo
));
1405 error
= fill_procworkqueue(p
, pwqinfo
);
1415 proc_piduniqidentifierinfo(proc_t p
, struct proc_uniqidentifierinfo
*p_uniqidinfo
)
1417 p_uniqidinfo
->p_uniqueid
= proc_uniqueid(p
);
1418 proc_getexecutableuuid(p
, (unsigned char *)&p_uniqidinfo
->p_uuid
, sizeof(p_uniqidinfo
->p_uuid
));
1419 p_uniqidinfo
->p_puniqueid
= proc_puniqueid(p
);
1420 p_uniqidinfo
->p_idversion
= proc_pidversion(p
);
1421 p_uniqidinfo
->p_reserve2
= 0;
1422 p_uniqidinfo
->p_reserve3
= 0;
1423 p_uniqidinfo
->p_reserve4
= 0;
1428 proc_piduuidinfo(pid_t pid
, uuid_t uuid_buf
, uint32_t buffersize
)
1430 struct proc
* p
= PROC_NULL
;
1433 if (buffersize
< sizeof(uuid_t
)) {
1437 if ((p
= proc_find(pid
)) == PROC_NULL
) {
1438 p
= proc_find_zombref(pid
);
1441 if (p
== PROC_NULL
) {
1445 proc_getexecutableuuid(p
, (unsigned char *)uuid_buf
, buffersize
);
1448 proc_drop_zombref(p
);
1457 * Function to get the uuid and pid of the originator of the voucher.
1460 proc_pidoriginatorpid_uuid(uuid_t uuid
, uint32_t buffersize
, pid_t
*pid
)
1462 pid_t originator_pid
;
1467 * Get the current voucher origin pid. The pid returned here
1468 * might not be valid or may have been recycled.
1470 kr
= thread_get_current_voucher_origin_pid(&originator_pid
);
1471 /* If errors, convert errors to appropriate format */
1473 if (kr
== KERN_INVALID_TASK
) {
1475 } else if (kr
== KERN_INVALID_VALUE
) {
1483 *pid
= originator_pid
;
1484 error
= proc_piduuidinfo(originator_pid
, uuid
, buffersize
);
1489 * Function to get the uuid of the originator of the voucher.
1492 proc_pidoriginatoruuid(uuid_t uuid
, uint32_t buffersize
)
1494 pid_t originator_pid
;
1495 return proc_pidoriginatorpid_uuid(uuid
, buffersize
, &originator_pid
);
1499 * Function to get the task ipc table size.
1502 proc_pidipctableinfo(proc_t p
, struct proc_ipctableinfo
*table_info
)
1509 bzero(table_info
, sizeof(struct proc_ipctableinfo
));
1510 error
= fill_taskipctableinfo(task
, &(table_info
->table_size
), &(table_info
->table_free
));
1519 /***************************** proc_pidoriginatorinfo ***************************/
1522 proc_pidoriginatorinfo(int pid
, int flavor
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
)
1524 int error
= ENOTSUP
;
1528 case PROC_PIDORIGINATOR_UUID
:
1529 size
= PROC_PIDORIGINATOR_UUID_SIZE
;
1531 case PROC_PIDORIGINATOR_BGSTATE
:
1532 size
= PROC_PIDORIGINATOR_BGSTATE_SIZE
;
1534 case PROC_PIDORIGINATOR_PID_UUID
:
1535 size
= PROC_PIDORIGINATOR_PID_UUID_SIZE
;
1541 if (buffersize
< size
) {
1545 if (pid
!= 0 && pid
!= proc_selfpid()) {
1550 case PROC_PIDORIGINATOR_UUID
: {
1553 error
= proc_pidoriginatoruuid(uuid
, sizeof(uuid
));
1558 error
= copyout(uuid
, buffer
, size
);
1565 case PROC_PIDORIGINATOR_PID_UUID
: {
1566 struct proc_originatorinfo originator_info
;
1567 bzero(&originator_info
, sizeof(originator_info
));
1569 error
= proc_pidoriginatorpid_uuid(originator_info
.originator_uuid
,
1570 sizeof(uuid_t
), &originator_info
.originator_pid
);
1575 error
= copyout(&originator_info
, buffer
, size
);
1582 case PROC_PIDORIGINATOR_BGSTATE
: {
1583 uint32_t is_backgrounded
= 0;
1584 error
= proc_get_originatorbgstate(&is_backgrounded
);
1589 error
= copyout(&is_backgrounded
, buffer
, size
);
1603 /***************************** proc_listcoalitions ***************************/
1605 proc_listcoalitions(int flavor
, int type
, user_addr_t buffer
,
1606 uint32_t buffersize
, int32_t *retval
)
1608 #if CONFIG_COALITIONS
1609 int error
= ENOTSUP
;
1612 void *coalinfo
= NULL
;
1613 uint32_t k_buffersize
= 0, copyout_sz
= 0;
1614 int ncoals
= 0, ncoals_
= 0;
1616 /* struct procinfo_coalinfo; */
1619 case LISTCOALITIONS_ALL_COALS
:
1620 elem_size
= LISTCOALITIONS_ALL_COALS_SIZE
;
1623 case LISTCOALITIONS_SINGLE_TYPE
:
1624 elem_size
= LISTCOALITIONS_SINGLE_TYPE_SIZE
;
1631 /* find the total number of coalitions */
1632 ncoals
= coalitions_get_list(coal_type
, NULL
, 0);
1634 if (ncoals
== 0 || buffer
== 0 || buffersize
== 0) {
1636 * user just wants buffer size
1637 * or there are no coalitions
1640 *retval
= (int)(ncoals
* elem_size
);
1644 k_buffersize
= ncoals
* elem_size
;
1645 coalinfo
= kheap_alloc(KHEAP_TEMP
, k_buffersize
, Z_WAITOK
| Z_ZERO
);
1652 case LISTCOALITIONS_ALL_COALS
:
1653 case LISTCOALITIONS_SINGLE_TYPE
:
1654 ncoals_
= coalitions_get_list(coal_type
, coalinfo
, ncoals
);
1657 panic("memory corruption?!");
1661 /* all the coalitions disappeared... weird but valid */
1668 * Some coalitions may have disappeared between our initial check,
1669 * and the the actual list acquisition.
1670 * Only copy out what we really need.
1672 copyout_sz
= k_buffersize
;
1673 if (ncoals_
< ncoals
) {
1674 copyout_sz
= ncoals_
* elem_size
;
1678 * copy the list up to user space
1679 * (we're guaranteed to have a non-null pointer/size here)
1681 error
= copyout(coalinfo
, buffer
,
1682 copyout_sz
< buffersize
? copyout_sz
: buffersize
);
1685 *retval
= (int)copyout_sz
;
1690 kheap_free(KHEAP_TEMP
, coalinfo
, k_buffersize
);
1695 /* no coalition support */
1706 /*************************** proc_can_use_forgeound_hw **************************/
1708 proc_can_use_foreground_hw(int pid
, user_addr_t u_reason
, uint32_t reasonsize
, int32_t *retval
)
1710 proc_t p
= PROC_NULL
;
1712 uint32_t reason
= PROC_FGHW_ERROR
;
1714 task_t task
= TASK_NULL
;
1715 #if CONFIG_COALITIONS
1716 coalition_t coal
= COALITION_NULL
;
1723 reason
= PROC_FGHW_ERROR
;
1728 if (p
== PROC_NULL
) {
1730 reason
= PROC_FGHW_ERROR
;
1734 #if CONFIG_COALITIONS
1735 if (p
!= current_proc() &&
1736 !kauth_cred_issuser(kauth_cred_get())) {
1738 reason
= PROC_FGHW_ERROR
;
1743 if (coalition_is_leader(task
, task_get_coalition(task
, COALITION_TYPE_JETSAM
))) {
1744 task_reference(task
);
1746 /* current task is not a coalition leader: find the leader */
1747 task
= coalition_get_leader(coal
);
1750 if (task
!= TASK_NULL
) {
1752 * If task is non-null, then it is the coalition leader of the
1753 * current process' coalition. This could be the same task as
1754 * the current_task, and that's OK.
1759 proc_get_darwinbgstate(task
, &flags
);
1760 if ((flags
& PROC_FLAG_APPLICATION
) != PROC_FLAG_APPLICATION
) {
1762 * Coalition leader is not an application, continue
1763 * searching for other ways this task could gain
1766 reason
= PROC_FGHW_DAEMON_LEADER
;
1770 if (proc_get_effective_task_policy(task
, TASK_POLICY_DARWIN_BG
)) {
1772 * If the leader of the current process' coalition has
1773 * been marked as DARWIN_BG, then it definitely should
1774 * not be using foreground hardware resources.
1776 reason
= PROC_FGHW_LEADER_BACKGROUND
;
1780 role
= proc_get_effective_task_policy(task
, TASK_POLICY_ROLE
);
1782 case TASK_FOREGROUND_APPLICATION
: /* DARWIN_ROLE_UI_FOCAL */
1783 case TASK_BACKGROUND_APPLICATION
: /* DARWIN_ROLE_UI */
1785 * The leader of this coalition is a focal, UI app:
1787 * TODO: should extensions/plugins be allowed to use
1791 reason
= PROC_FGHW_OK
;
1793 case TASK_DEFAULT_APPLICATION
: /* DARWIN_ROLE_UI_NON_FOCAL */
1794 case TASK_NONUI_APPLICATION
: /* DARWIN_ROLE_NON_UI */
1795 case TASK_THROTTLE_APPLICATION
:
1796 case TASK_UNSPECIFIED
:
1798 /* non-focal, non-ui apps don't get access */
1799 reason
= PROC_FGHW_LEADER_NONUI
;
1805 if (task
!= TASK_NULL
) {
1806 task_deallocate(task
);
1809 #endif /* CONFIG_COALITIONS */
1812 * There is no reasonable semantic to investigate the currently
1813 * adopted voucher of an arbitrary thread in a non-current process.
1816 if (p
!= current_proc()) {
1822 * In the absence of coalitions, fall back to a voucher-based lookup
1823 * where a daemon can used foreground HW if it's operating on behalf
1824 * of a foreground application.
1825 * NOTE: this is equivalent to a call to
1826 * proc_pidoriginatorinfo(PROC_PIDORIGINATOR_BGSTATE, &isBG, sizeof(isBG))
1829 error
= proc_get_originatorbgstate(&isBG
);
1834 reason
= PROC_FGHW_NO_ORIGINATOR
;
1838 reason
= PROC_FGHW_NO_VOUCHER_ATTR
;
1842 reason
= PROC_FGHW_DAEMON_NO_VOUCHER
;
1846 /* some other error occurred: report that to the caller */
1847 reason
= PROC_FGHW_VOUCHER_ERROR
;
1852 reason
= PROC_FGHW_ORIGINATOR_BACKGROUND
;
1856 * The process itself is either a foreground app, or has
1857 * adopted a voucher originating from an app that's still in
1860 reason
= PROC_FGHW_DAEMON_OK
;
1865 if (task
!= TASK_NULL
) {
1866 task_deallocate(task
);
1868 if (p
!= PROC_NULL
) {
1871 if (reasonsize
>= sizeof(reason
) && u_reason
!= (user_addr_t
)0) {
1872 (void)copyout(&reason
, u_reason
, sizeof(reason
));
1878 /********************************** proc_pidinfo ********************************/
1882 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
)
1884 struct proc
* p
= PROC_NULL
;
1885 int error
= ENOTSUP
;
1888 int shortversion
= 0;
1891 bool thuniqueid
= false;
1892 int uniqidversion
= 0;
1893 bool check_same_user
;
1896 case PROC_PIDLISTFDS
:
1897 size
= PROC_PIDLISTFD_SIZE
;
1898 if (buffer
== USER_ADDR_NULL
) {
1902 case PROC_PIDTBSDINFO
:
1903 size
= PROC_PIDTBSDINFO_SIZE
;
1905 case PROC_PIDTASKINFO
:
1906 size
= PROC_PIDTASKINFO_SIZE
;
1908 case PROC_PIDTASKALLINFO
:
1909 size
= PROC_PIDTASKALLINFO_SIZE
;
1911 case PROC_PIDTHREADINFO
:
1912 size
= PROC_PIDTHREADINFO_SIZE
;
1914 case PROC_PIDLISTTHREADIDS
:
1915 size
= PROC_PIDLISTTHREADIDS_SIZE
;
1917 case PROC_PIDLISTTHREADS
:
1918 size
= PROC_PIDLISTTHREADS_SIZE
;
1920 case PROC_PIDREGIONINFO
:
1921 size
= PROC_PIDREGIONINFO_SIZE
;
1923 case PROC_PIDREGIONPATHINFO
:
1924 size
= PROC_PIDREGIONPATHINFO_SIZE
;
1926 case PROC_PIDVNODEPATHINFO
:
1927 size
= PROC_PIDVNODEPATHINFO_SIZE
;
1929 case PROC_PIDTHREADPATHINFO
:
1930 size
= PROC_PIDTHREADPATHINFO_SIZE
;
1932 case PROC_PIDPATHINFO
:
1935 case PROC_PIDWORKQUEUEINFO
:
1936 /* kernel does not have workq info */
1940 size
= PROC_PIDWORKQUEUEINFO_SIZE
;
1943 case PROC_PIDT_SHORTBSDINFO
:
1944 size
= PROC_PIDT_SHORTBSDINFO_SIZE
;
1946 case PROC_PIDLISTFILEPORTS
:
1947 size
= PROC_PIDLISTFILEPORTS_SIZE
;
1948 if (buffer
== (user_addr_t
)0) {
1952 case PROC_PIDTHREADID64INFO
:
1953 size
= PROC_PIDTHREADID64INFO_SIZE
;
1955 case PROC_PIDUNIQIDENTIFIERINFO
:
1956 size
= PROC_PIDUNIQIDENTIFIERINFO_SIZE
;
1958 case PROC_PIDT_BSDINFOWITHUNIQID
:
1959 size
= PROC_PIDT_BSDINFOWITHUNIQID_SIZE
;
1961 case PROC_PIDARCHINFO
:
1962 size
= PROC_PIDARCHINFO_SIZE
;
1964 case PROC_PIDCOALITIONINFO
:
1965 size
= PROC_PIDCOALITIONINFO_SIZE
;
1967 case PROC_PIDNOTEEXIT
:
1969 * Set findzomb explicitly because arg passed
1970 * in is used as note exit status bits.
1972 size
= PROC_PIDNOTEEXIT_SIZE
;
1975 case PROC_PIDEXITREASONINFO
:
1976 size
= PROC_PIDEXITREASONINFO_SIZE
;
1979 case PROC_PIDEXITREASONBASICINFO
:
1980 size
= PROC_PIDEXITREASONBASICINFOSIZE
;
1983 case PROC_PIDREGIONPATHINFO2
:
1984 size
= PROC_PIDREGIONPATHINFO2_SIZE
;
1986 case PROC_PIDREGIONPATHINFO3
:
1987 size
= PROC_PIDREGIONPATHINFO3_SIZE
;
1989 case PROC_PIDLISTUPTRS
:
1990 size
= PROC_PIDLISTUPTRS_SIZE
;
1991 if (buffer
== USER_ADDR_NULL
) {
1995 case PROC_PIDLISTDYNKQUEUES
:
1996 size
= PROC_PIDLISTDYNKQUEUES_SIZE
;
1997 if (buffer
== USER_ADDR_NULL
) {
2001 case PROC_PIDVMRTFAULTINFO
:
2002 size
= sizeof(vm_rtfault_record_t
);
2003 if (buffer
== USER_ADDR_NULL
) {
2007 case PROC_PIDPLATFORMINFO
:
2008 size
= PROC_PIDPLATFORMINFO_SIZE
;
2011 case PROC_PIDREGIONPATH
:
2012 size
= PROC_PIDREGIONPATH_SIZE
;
2014 case PROC_PIDIPCTABLEINFO
:
2015 size
= PROC_PIDIPCTABLEINFO_SIZE
;
2021 if (buffersize
< size
) {
2025 if ((flavor
== PROC_PIDPATHINFO
) && (buffersize
> PROC_PIDPATHINFO_MAXSIZE
)) {
2029 /* Check if we need to look for zombies */
2030 if ((flavor
== PROC_PIDTBSDINFO
) || (flavor
== PROC_PIDT_SHORTBSDINFO
) || (flavor
== PROC_PIDT_BSDINFOWITHUNIQID
)
2031 || (flavor
== PROC_PIDUNIQIDENTIFIERINFO
)) {
2037 if ((p
= proc_find(pid
)) == PROC_NULL
) {
2039 p
= proc_find_zombref(pid
);
2041 if (p
== PROC_NULL
) {
2050 if ((flags
& PIF_COMPARE_IDVERSION
) && (ext_id
!= p
->p_idversion
)) {
2054 if ((flags
& PIF_COMPARE_UNIQUEID
) && (ext_id
!= p
->p_uniqueid
)) {
2059 /* Certain operations don't require privileges */
2061 case PROC_PIDT_SHORTBSDINFO
:
2062 case PROC_PIDUNIQIDENTIFIERINFO
:
2063 case PROC_PIDPATHINFO
:
2064 case PROC_PIDCOALITIONINFO
:
2065 case PROC_PIDPLATFORMINFO
:
2066 check_same_user
= NO_CHECK_SAME_USER
;
2069 check_same_user
= CHECK_SAME_USER
;
2073 /* Do we have permission to look into this? */
2074 if ((error
= proc_security_policy(p
, PROC_INFO_CALL_PIDINFO
, flavor
, check_same_user
))) {
2079 case PROC_PIDLISTFDS
: {
2080 error
= proc_pidfdlist(p
, buffer
, buffersize
, retval
);
2084 case PROC_PIDUNIQIDENTIFIERINFO
: {
2085 struct proc_uniqidentifierinfo p_uniqidinfo
;
2086 bzero(&p_uniqidinfo
, sizeof(p_uniqidinfo
));
2087 proc_piduniqidentifierinfo(p
, &p_uniqidinfo
);
2088 error
= copyout(&p_uniqidinfo
, buffer
, sizeof(struct proc_uniqidentifierinfo
));
2090 *retval
= sizeof(struct proc_uniqidentifierinfo
);
2095 case PROC_PIDT_SHORTBSDINFO
:
2098 case PROC_PIDT_BSDINFOWITHUNIQID
:
2099 case PROC_PIDTBSDINFO
: {
2100 struct proc_bsdinfo pbsd
;
2101 struct proc_bsdshortinfo pbsd_short
;
2102 struct proc_bsdinfowithuniqid pbsd_uniqid
;
2104 if (flavor
== PROC_PIDT_BSDINFOWITHUNIQID
) {
2108 if (shortversion
!= 0) {
2109 error
= proc_pidshortbsdinfo(p
, &pbsd_short
, zombie
);
2111 error
= proc_pidbsdinfo(p
, &pbsd
, zombie
);
2112 if (uniqidversion
!= 0) {
2113 bzero(&pbsd_uniqid
, sizeof(pbsd_uniqid
));
2114 proc_piduniqidentifierinfo(p
, &pbsd_uniqid
.p_uniqidentifier
);
2115 pbsd_uniqid
.pbsd
= pbsd
;
2120 if (shortversion
!= 0) {
2121 error
= copyout(&pbsd_short
, buffer
, sizeof(struct proc_bsdshortinfo
));
2123 *retval
= sizeof(struct proc_bsdshortinfo
);
2125 } else if (uniqidversion
!= 0) {
2126 error
= copyout(&pbsd_uniqid
, buffer
, sizeof(struct proc_bsdinfowithuniqid
));
2128 *retval
= sizeof(struct proc_bsdinfowithuniqid
);
2131 error
= copyout(&pbsd
, buffer
, sizeof(struct proc_bsdinfo
));
2133 *retval
= sizeof(struct proc_bsdinfo
);
2140 case PROC_PIDTASKINFO
: {
2141 struct proc_taskinfo ptinfo
;
2143 error
= proc_pidtaskinfo(p
, &ptinfo
);
2145 error
= copyout(&ptinfo
, buffer
, sizeof(struct proc_taskinfo
));
2147 *retval
= sizeof(struct proc_taskinfo
);
2153 case PROC_PIDTASKALLINFO
: {
2154 struct proc_taskallinfo pall
;
2155 bzero(&pall
, sizeof(pall
));
2156 error
= proc_pidbsdinfo(p
, &pall
.pbsd
, 0);
2157 error
= proc_pidtaskinfo(p
, &pall
.ptinfo
);
2159 error
= copyout(&pall
, buffer
, sizeof(struct proc_taskallinfo
));
2161 *retval
= sizeof(struct proc_taskallinfo
);
2167 case PROC_PIDTHREADID64INFO
:
2170 case PROC_PIDTHREADINFO
:{
2171 struct proc_threadinfo pthinfo
;
2173 error
= proc_pidthreadinfo(p
, arg
, thuniqueid
, &pthinfo
);
2175 error
= copyout(&pthinfo
, buffer
, sizeof(struct proc_threadinfo
));
2177 *retval
= sizeof(struct proc_threadinfo
);
2183 case PROC_PIDLISTTHREADIDS
:
2186 case PROC_PIDLISTTHREADS
:{
2187 error
= proc_pidlistthreads(p
, thuniqueid
, buffer
, buffersize
, retval
);
2191 case PROC_PIDREGIONINFO
:{
2192 error
= proc_pidregioninfo(p
, arg
, buffer
, buffersize
, retval
);
2197 case PROC_PIDREGIONPATHINFO
:{
2198 error
= proc_pidregionpathinfo(p
, arg
, buffer
, buffersize
, retval
);
2202 case PROC_PIDREGIONPATHINFO2
:{
2203 error
= proc_pidregionpathinfo2(p
, arg
, buffer
, buffersize
, retval
);
2207 case PROC_PIDREGIONPATHINFO3
:{
2208 error
= proc_pidregionpathinfo3(p
, arg
, buffer
, buffersize
, retval
);
2212 case PROC_PIDVNODEPATHINFO
:{
2213 error
= proc_pidvnodepathinfo(p
, arg
, buffer
, buffersize
, retval
);
2218 case PROC_PIDTHREADPATHINFO
:{
2219 struct proc_threadwithpathinfo pinfo
;
2221 error
= proc_pidthreadpathinfo(p
, arg
, &pinfo
);
2223 error
= copyout((caddr_t
)&pinfo
, buffer
, sizeof(struct proc_threadwithpathinfo
));
2225 *retval
= sizeof(struct proc_threadwithpathinfo
);
2231 case PROC_PIDPATHINFO
: {
2232 error
= proc_pidpathinfo(p
, arg
, buffer
, buffersize
, retval
);
2237 case PROC_PIDWORKQUEUEINFO
:{
2238 struct proc_workqueueinfo pwqinfo
;
2240 error
= proc_pidworkqueueinfo(p
, &pwqinfo
);
2242 error
= copyout(&pwqinfo
, buffer
, sizeof(struct proc_workqueueinfo
));
2244 *retval
= sizeof(struct proc_workqueueinfo
);
2250 case PROC_PIDLISTFILEPORTS
: {
2251 error
= proc_pidfileportlist(p
, buffer
, buffersize
, retval
);
2255 case PROC_PIDARCHINFO
: {
2256 struct proc_archinfo pai
;
2257 bzero(&pai
, sizeof(pai
));
2258 proc_archinfo(p
, &pai
);
2259 error
= copyout(&pai
, buffer
, sizeof(struct proc_archinfo
));
2261 *retval
= sizeof(struct proc_archinfo
);
2266 case PROC_PIDCOALITIONINFO
: {
2267 struct proc_pidcoalitioninfo pci
;
2268 proc_pidcoalitioninfo(p
, &pci
);
2269 error
= copyout(&pci
, buffer
, sizeof(struct proc_pidcoalitioninfo
));
2271 *retval
= sizeof(struct proc_pidcoalitioninfo
);
2276 case PROC_PIDNOTEEXIT
: {
2278 error
= proc_pidnoteexit(p
, arg
, &data
);
2280 error
= copyout(&data
, buffer
, sizeof(data
));
2282 *retval
= sizeof(data
);
2288 case PROC_PIDEXITREASONINFO
: {
2289 struct proc_exitreasoninfo eri
;
2291 error
= copyin(buffer
, &eri
, sizeof(eri
));
2296 error
= proc_pidexitreasoninfo(p
, &eri
, NULL
);
2298 error
= copyout(&eri
, buffer
, sizeof(eri
));
2300 *retval
= sizeof(eri
);
2306 case PROC_PIDEXITREASONBASICINFO
: {
2307 struct proc_exitreasonbasicinfo beri
;
2309 bzero(&beri
, sizeof(struct proc_exitreasonbasicinfo
));
2311 error
= proc_pidexitreasoninfo(p
, NULL
, &beri
);
2313 error
= copyout(&beri
, buffer
, sizeof(beri
));
2315 *retval
= sizeof(beri
);
2321 case PROC_PIDLISTUPTRS
:
2322 error
= proc_pidlistuptrs(p
, buffer
, buffersize
, retval
);
2325 case PROC_PIDLISTDYNKQUEUES
:
2326 error
= kevent_copyout_proc_dynkqids(p
, buffer
, buffersize
, retval
);
2328 case PROC_PIDVMRTFAULTINFO
: {
2329 /* This interface can only be employed on the current
2330 * process. We will eventually enforce an entitlement.
2334 if (p
!= current_proc()) {
2339 size_t kbufsz
= MIN(buffersize
, vmrtfaultinfo_bufsz());
2340 void *vmrtfbuf
= kheap_alloc(KHEAP_TEMP
, kbufsz
, Z_WAITOK
| Z_ZERO
);
2342 if (vmrtfbuf
== NULL
) {
2347 uint64_t effpid
= get_current_unique_pid();
2348 /* The VM may choose to provide more comprehensive records
2349 * for root-privileged users on internal configurations.
2351 boolean_t isroot
= (suser(kauth_cred_get(), (u_short
*)0) == 0);
2352 size_t num_extracted
= 0;
2353 int vmf_residue
= vmrtf_extract(effpid
, isroot
, kbufsz
, vmrtfbuf
, &num_extracted
);
2354 size_t vmfsz
= num_extracted
* sizeof(vm_rtfault_record_t
);
2356 *retval
= (int32_t)MIN(num_extracted
, INT32_MAX
);
2360 error
= copyout(vmrtfbuf
, buffer
, vmfsz
);
2368 kheap_free(KHEAP_TEMP
, vmrtfbuf
, kbufsz
);
2371 case PROC_PIDPLATFORMINFO
: {
2373 uint32_t platform
= p
->p_platform
;
2375 error
= copyout(&platform
, buffer
, sizeof(uint32_t));
2377 *retval
= sizeof(uint32_t);
2380 case PROC_PIDREGIONPATH
: {
2381 error
= proc_pidregionpath(p
, arg
, buffer
, buffersize
, retval
);
2384 case PROC_PIDIPCTABLEINFO
: {
2385 struct proc_ipctableinfo table_info
;
2387 error
= proc_pidipctableinfo(p
, &table_info
);
2389 error
= copyout(&table_info
, buffer
, sizeof(struct proc_ipctableinfo
));
2391 *retval
= sizeof(struct proc_ipctableinfo
);
2404 } else if (zombie
) {
2405 proc_drop_zombref(p
);
2412 pid_vnodeinfo(vnode_t vp
, struct fileproc
* fp
, proc_t proc
, int fd
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t * retval
)
2414 struct vnode_fdinfo vfi
;
2415 uint32_t vid
= vnode_vid(vp
);
2418 if ((error
= vnode_getwithvid(vp
, vid
)) != 0) {
2421 bzero(&vfi
, sizeof(struct vnode_fdinfo
));
2422 fill_fileinfo(fp
, proc
, fd
, &vfi
.pfi
);
2423 error
= fill_vnodeinfo(vp
, &vfi
.pvi
, FALSE
);
2426 error
= copyout((caddr_t
)&vfi
, buffer
, sizeof(struct vnode_fdinfo
));
2428 *retval
= sizeof(struct vnode_fdinfo
);
2435 pid_vnodeinfopath(vnode_t vp
, struct fileproc
* fp
, proc_t proc
, int fd
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t * retval
)
2437 struct vnode_fdinfowithpath vfip
;
2438 uint32_t vid
= vnode_vid(vp
);
2439 int count
, error
= 0;
2441 if ((error
= vnode_getwithvid(vp
, vid
)) != 0) {
2444 bzero(&vfip
, sizeof(struct vnode_fdinfowithpath
));
2445 fill_fileinfo(fp
, proc
, fd
, &vfip
.pfi
);
2446 error
= fill_vnodeinfo(vp
, &vfip
.pvip
.vip_vi
, TRUE
);
2449 vn_getpath(vp
, &vfip
.pvip
.vip_path
[0], &count
);
2450 vfip
.pvip
.vip_path
[MAXPATHLEN
- 1] = 0;
2452 error
= copyout((caddr_t
)&vfip
, buffer
, sizeof(struct vnode_fdinfowithpath
));
2454 *retval
= sizeof(struct vnode_fdinfowithpath
);
2463 fill_fileinfo(struct fileproc
* fp
, proc_t proc
, int fd
, struct proc_fileinfo
* fproc
)
2465 fproc
->fi_openflags
= fp
->fp_glob
->fg_flag
;
2466 fproc
->fi_status
= 0;
2467 fproc
->fi_offset
= fp
->fp_glob
->fg_offset
;
2468 fproc
->fi_type
= FILEGLOB_DTYPE(fp
->fp_glob
);
2469 if (os_ref_get_count_raw(&fp
->fp_glob
->fg_count
) > 1) {
2470 fproc
->fi_status
|= PROC_FP_SHARED
;
2472 if (proc
!= PROC_NULL
) {
2473 if ((FDFLAGS_GET(proc
, fd
) & UF_EXCLOSE
) != 0) {
2474 fproc
->fi_status
|= PROC_FP_CLEXEC
;
2476 if ((FDFLAGS_GET(proc
, fd
) & UF_FORKCLOSE
) != 0) {
2477 fproc
->fi_status
|= PROC_FP_CLFORK
;
2480 if (fp_isguarded(fp
, 0)) {
2481 fproc
->fi_status
|= PROC_FP_GUARDED
;
2482 fproc
->fi_guardflags
= 0;
2483 if (fp_isguarded(fp
, GUARD_CLOSE
)) {
2484 fproc
->fi_guardflags
|= PROC_FI_GUARD_CLOSE
;
2486 if (fp_isguarded(fp
, GUARD_DUP
)) {
2487 fproc
->fi_guardflags
|= PROC_FI_GUARD_DUP
;
2489 if (fp_isguarded(fp
, GUARD_SOCKET_IPC
)) {
2490 fproc
->fi_guardflags
|= PROC_FI_GUARD_SOCKET_IPC
;
2492 if (fp_isguarded(fp
, GUARD_FILEPORT
)) {
2493 fproc
->fi_guardflags
|= PROC_FI_GUARD_FILEPORT
;
2501 fill_vnodeinfo(vnode_t vp
, struct vnode_info
*vinfo
, __unused boolean_t check_fsgetpath
)
2503 vfs_context_t context
;
2507 bzero(&sb
, sizeof(struct stat64
));
2508 context
= vfs_context_create((vfs_context_t
)0);
2510 /* Called when vnode info is used by the caller to get vnode's path */
2511 if (check_fsgetpath
) {
2512 error
= mac_vnode_check_fsgetpath(context
, vp
);
2516 error
= vn_stat(vp
, &sb
, NULL
, 1, 0, context
);
2517 munge_vinfo_stat(&sb
, &vinfo
->vi_stat
);
2519 (void)vfs_context_rele(context
);
2524 if (vp
->v_mount
!= dead_mountp
) {
2525 vinfo
->vi_fsid
= vp
->v_mount
->mnt_vfsstat
.f_fsid
;
2527 vinfo
->vi_fsid
.val
[0] = 0;
2528 vinfo
->vi_fsid
.val
[1] = 0;
2530 vinfo
->vi_type
= vp
->v_type
;
2536 pid_socketinfo(socket_t so
, struct fileproc
*fp
, proc_t proc
, int fd
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t * retval
)
2539 struct socket_fdinfo s
;
2542 bzero(&s
, sizeof(struct socket_fdinfo
));
2543 fill_fileinfo(fp
, proc
, fd
, &s
.pfi
);
2544 if ((error
= fill_socketinfo(so
, &s
.psi
)) == 0) {
2545 if ((error
= copyout(&s
, buffer
, sizeof(struct socket_fdinfo
))) == 0) {
2546 *retval
= sizeof(struct socket_fdinfo
);
2551 #pragma unused(so, fp, proc, fd, buffer)
2558 pid_pseminfo(struct psemnode
*psem
, struct fileproc
*fp
, proc_t proc
, int fd
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t * retval
)
2560 struct psem_fdinfo pseminfo
;
2563 bzero(&pseminfo
, sizeof(struct psem_fdinfo
));
2564 fill_fileinfo(fp
, proc
, fd
, &pseminfo
.pfi
);
2566 if ((error
= fill_pseminfo(psem
, &pseminfo
.pseminfo
)) == 0) {
2567 if ((error
= copyout(&pseminfo
, buffer
, sizeof(struct psem_fdinfo
))) == 0) {
2568 *retval
= sizeof(struct psem_fdinfo
);
2576 pid_pshminfo(struct pshmnode
*pshm
, struct fileproc
*fp
, proc_t proc
, int fd
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t * retval
)
2578 struct pshm_fdinfo pshminfo
;
2581 bzero(&pshminfo
, sizeof(struct pshm_fdinfo
));
2582 fill_fileinfo(fp
, proc
, fd
, &pshminfo
.pfi
);
2584 if ((error
= fill_pshminfo(pshm
, &pshminfo
.pshminfo
)) == 0) {
2585 if ((error
= copyout(&pshminfo
, buffer
, sizeof(struct pshm_fdinfo
))) == 0) {
2586 *retval
= sizeof(struct pshm_fdinfo
);
2594 pid_pipeinfo(struct pipe
* p
, struct fileproc
*fp
, proc_t proc
, int fd
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t * retval
)
2596 struct pipe_fdinfo pipeinfo
;
2599 bzero(&pipeinfo
, sizeof(struct pipe_fdinfo
));
2600 fill_fileinfo(fp
, proc
, fd
, &pipeinfo
.pfi
);
2601 if ((error
= fill_pipeinfo(p
, &pipeinfo
.pipeinfo
)) == 0) {
2602 if ((error
= copyout(&pipeinfo
, buffer
, sizeof(struct pipe_fdinfo
))) == 0) {
2603 *retval
= sizeof(struct pipe_fdinfo
);
2611 pid_kqueueinfo(struct kqueue
* kq
, struct fileproc
*fp
, proc_t proc
, int fd
, user_addr_t buffer
, __unused
uint32_t buffersize
, int32_t * retval
)
2613 struct kqueue_fdinfo kqinfo
;
2616 bzero(&kqinfo
, sizeof(struct kqueue_fdinfo
));
2618 /* not all kq's are associated with a file (e.g. workqkq) */
2621 fill_fileinfo(fp
, proc
, fd
, &kqinfo
.pfi
);
2624 if ((error
= fill_kqueueinfo(kq
, &kqinfo
.kqueueinfo
)) == 0) {
2625 if ((error
= copyout(&kqinfo
, buffer
, sizeof(struct kqueue_fdinfo
))) == 0) {
2626 *retval
= sizeof(struct kqueue_fdinfo
);
2634 /************************** proc_pidfdinfo routine ***************************/
2636 proc_pidfdinfo(int pid
, int flavor
, int fd
, user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
)
2639 int error
= ENOTSUP
;
2640 struct fileproc
*fp
= NULL
;
2644 case PROC_PIDFDVNODEINFO
:
2645 size
= PROC_PIDFDVNODEINFO_SIZE
;
2647 case PROC_PIDFDVNODEPATHINFO
:
2648 size
= PROC_PIDFDVNODEPATHINFO_SIZE
;
2650 case PROC_PIDFDSOCKETINFO
:
2651 size
= PROC_PIDFDSOCKETINFO_SIZE
;
2653 case PROC_PIDFDPSEMINFO
:
2654 size
= PROC_PIDFDPSEMINFO_SIZE
;
2656 case PROC_PIDFDPSHMINFO
:
2657 size
= PROC_PIDFDPSHMINFO_SIZE
;
2659 case PROC_PIDFDPIPEINFO
:
2660 size
= PROC_PIDFDPIPEINFO_SIZE
;
2662 case PROC_PIDFDKQUEUEINFO
:
2663 size
= PROC_PIDFDKQUEUEINFO_SIZE
;
2665 case PROC_PIDFDKQUEUE_EXTINFO
:
2666 size
= PROC_PIDFDKQUEUE_EXTINFO_SIZE
;
2667 if (buffer
== (user_addr_t
)0) {
2671 case PROC_PIDFDATALKINFO
:
2672 size
= PROC_PIDFDATALKINFO_SIZE
;
2679 if (buffersize
< size
) {
2683 if ((p
= proc_find(pid
)) == PROC_NULL
) {
2688 /* Do we have permission to look into this? */
2689 if ((error
= proc_security_policy(p
, PROC_INFO_CALL_PIDFDINFO
, flavor
, CHECK_SAME_USER
))) {
2694 case PROC_PIDFDVNODEINFO
: {
2695 if ((error
= fp_get_ftype(p
, fd
, DTYPE_VNODE
, EBADF
, &fp
)) != 0) {
2698 error
= pid_vnodeinfo(fp
->fp_glob
->fg_data
, fp
, p
, fd
, buffer
, buffersize
, retval
);
2702 case PROC_PIDFDVNODEPATHINFO
: {
2703 if ((error
= fp_get_ftype(p
, fd
, DTYPE_VNODE
, EBADF
, &fp
)) != 0) {
2706 error
= pid_vnodeinfopath(fp
->fp_glob
->fg_data
, fp
, p
, fd
, buffer
, buffersize
, retval
);
2710 case PROC_PIDFDSOCKETINFO
: {
2711 if ((error
= fp_get_ftype(p
, fd
, DTYPE_SOCKET
, ENOTSOCK
, &fp
)) != 0) {
2714 error
= pid_socketinfo(fp
->fp_glob
->fg_data
, fp
, p
, fd
, buffer
, buffersize
, retval
);
2718 case PROC_PIDFDPSEMINFO
: {
2719 if ((error
= fp_get_ftype(p
, fd
, DTYPE_PSXSEM
, EBADF
, &fp
)) != 0) {
2722 error
= pid_pseminfo(fp
->fp_glob
->fg_data
, fp
, p
, fd
, buffer
, buffersize
, retval
);
2726 case PROC_PIDFDPSHMINFO
: {
2727 if ((error
= fp_get_ftype(p
, fd
, DTYPE_PSXSHM
, EBADF
, &fp
)) != 0) {
2730 error
= pid_pshminfo(fp
->fp_glob
->fg_data
, fp
, p
, fd
, buffer
, buffersize
, retval
);
2734 case PROC_PIDFDPIPEINFO
: {
2735 if ((error
= fp_get_ftype(p
, fd
, DTYPE_PIPE
, EBADF
, &fp
)) != 0) {
2738 error
= pid_pipeinfo(fp
->fp_glob
->fg_data
, fp
, p
, fd
, buffer
, buffersize
, retval
);
2742 case PROC_PIDFDKQUEUEINFO
: {
2746 if ((kqu
.kqwq
= p
->p_fd
->fd_wqkqueue
) == NULL
) {
2747 /* wqkqueue is initialized on-demand */
2751 } else if ((error
= fp_get_ftype(p
, fd
, DTYPE_KQUEUE
, EBADF
, &fp
)) != 0) {
2754 kqu
.kq
= fp
->fp_glob
->fg_data
;
2757 error
= pid_kqueueinfo(kqu
.kq
, fp
, p
, fd
, buffer
, buffersize
, retval
);
2761 case PROC_PIDFDKQUEUE_EXTINFO
: {
2765 if ((kqu
.kqwq
= p
->p_fd
->fd_wqkqueue
) == NULL
) {
2766 /* wqkqueue is initialized on-demand */
2770 } else if ((error
= fp_get_ftype(p
, fd
, DTYPE_KQUEUE
, EBADF
, &fp
)) != 0) {
2773 kqu
.kq
= fp
->fp_glob
->fg_data
;
2775 error
= pid_kqueue_extinfo(p
, kqu
.kq
, buffer
, buffersize
, retval
);
2786 fp_drop(p
, fd
, fp
, 0);
2794 #define MAX_UPTRS 16392
2797 proc_pidlistuptrs(proc_t p
, user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
)
2804 if (buffer
== USER_ADDR_NULL
|| buffersize
< sizeof(uint64_t)) {
2807 count
= MIN(buffersize
/ sizeof(uint64_t), MAX_UPTRS
);
2808 buffersize
= count
* sizeof(uint64_t);
2809 kbuf
= kheap_alloc(KHEAP_TEMP
, buffersize
, Z_WAITOK
);
2812 nuptrs
= kevent_proc_copy_uptrs(p
, kbuf
, buffersize
);
2816 if (os_mul_overflow(nuptrs
, sizeof(uint64_t), ©size
)) {
2820 if (copysize
> buffersize
) {
2821 copysize
= buffersize
;
2823 error
= copyout(kbuf
, buffer
, copysize
);
2830 kheap_free(KHEAP_TEMP
, kbuf
, buffersize
);
2838 * Helper function for proc_pidfileportinfo
2841 struct fileport_info_args
{
2843 user_addr_t fia_buffer
;
2844 uint32_t fia_buffersize
;
2845 int32_t *fia_retval
;
2848 static kern_return_t
2849 proc_fileport_info(__unused mach_port_name_t name
,
2850 struct fileglob
*fg
, void *arg
)
2852 struct fileport_info_args
*fia
= arg
;
2853 struct fileproc __fileproc
, *fp
= &__fileproc
;
2856 bzero(fp
, sizeof(*fp
));
2859 switch (fia
->fia_flavor
) {
2860 case PROC_PIDFILEPORTVNODEPATHINFO
: {
2863 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
2867 vp
= (struct vnode
*)fg
->fg_data
;
2868 error
= pid_vnodeinfopath(vp
, fp
, PROC_NULL
, 0,
2869 fia
->fia_buffer
, fia
->fia_buffersize
, fia
->fia_retval
);
2872 case PROC_PIDFILEPORTSOCKETINFO
: {
2875 if (FILEGLOB_DTYPE(fg
) != DTYPE_SOCKET
) {
2879 so
= (socket_t
)fg
->fg_data
;
2880 error
= pid_socketinfo(so
, fp
, PROC_NULL
, 0,
2881 fia
->fia_buffer
, fia
->fia_buffersize
, fia
->fia_retval
);
2884 case PROC_PIDFILEPORTPSHMINFO
: {
2885 struct pshmnode
*pshm
;
2887 if (FILEGLOB_DTYPE(fg
) != DTYPE_PSXSHM
) {
2888 error
= EBADF
; /* ick - mirror fp_getfpshm */
2891 pshm
= (struct pshmnode
*)fg
->fg_data
;
2892 error
= pid_pshminfo(pshm
, fp
, PROC_NULL
, 0,
2893 fia
->fia_buffer
, fia
->fia_buffersize
, fia
->fia_retval
);
2896 case PROC_PIDFILEPORTPIPEINFO
: {
2899 if (FILEGLOB_DTYPE(fg
) != DTYPE_PIPE
) {
2900 error
= EBADF
; /* ick - mirror fp_getfpipe */
2903 cpipe
= (struct pipe
*)fg
->fg_data
;
2904 error
= pid_pipeinfo(cpipe
, fp
, PROC_NULL
, 0,
2905 fia
->fia_buffer
, fia
->fia_buffersize
, fia
->fia_retval
);
2916 /************************* proc_pidfileportinfo routine *********************/
2918 proc_pidfileportinfo(int pid
, int flavor
, mach_port_name_t name
,
2919 user_addr_t buffer
, uint32_t buffersize
, int32_t *retval
)
2922 int error
= ENOTSUP
;
2924 struct fileport_info_args fia
;
2926 /* fileport types are restricted by file_issendable() */
2929 case PROC_PIDFILEPORTVNODEPATHINFO
:
2930 size
= PROC_PIDFILEPORTVNODEPATHINFO_SIZE
;
2932 case PROC_PIDFILEPORTSOCKETINFO
:
2933 size
= PROC_PIDFILEPORTSOCKETINFO_SIZE
;
2935 case PROC_PIDFILEPORTPSHMINFO
:
2936 size
= PROC_PIDFILEPORTPSHMINFO_SIZE
;
2938 case PROC_PIDFILEPORTPIPEINFO
:
2939 size
= PROC_PIDFILEPORTPIPEINFO_SIZE
;
2945 if (buffersize
< size
) {
2948 if ((p
= proc_find(pid
)) == PROC_NULL
) {
2953 /* Do we have permission to look into this? */
2954 if ((error
= proc_security_policy(p
, PROC_INFO_CALL_PIDFILEPORTINFO
, flavor
, CHECK_SAME_USER
))) {
2958 fia
.fia_flavor
= flavor
;
2959 fia
.fia_buffer
= buffer
;
2960 fia
.fia_buffersize
= buffersize
;
2961 fia
.fia_retval
= retval
;
2963 if (fileport_invoke(p
->task
, name
,
2964 proc_fileport_info
, &fia
, &error
) != KERN_SUCCESS
) {
2974 proc_security_policy(proc_t targetp
, __unused
int callnum
, __unused
int flavor
, boolean_t check_same_user
)
2979 if ((error
= mac_proc_check_proc_info(current_proc(), targetp
, callnum
, flavor
))) {
2984 /* The 'listpids' call doesn't have a target proc */
2985 if (targetp
== PROC_NULL
) {
2986 assert(callnum
== PROC_INFO_CALL_LISTPIDS
&& check_same_user
== NO_CHECK_SAME_USER
);
2991 * Check for 'get information for processes owned by other users' privilege
2992 * root has this privilege by default
2994 if (priv_check_cred(kauth_cred_get(), PRIV_GLOBAL_PROC_INFO
, 0) == 0) {
2995 check_same_user
= FALSE
;
2998 if (check_same_user
) {
2999 kauth_cred_t target_cred
;
3002 target_cred
= kauth_cred_proc_ref(targetp
);
3003 target_uid
= kauth_cred_getuid(target_cred
);
3004 kauth_cred_unref(&target_cred
);
3006 if (kauth_getuid() != target_uid
) {
3015 proc_kernmsgbuf(user_addr_t buffer
, uint32_t buffersize
, int32_t * retval
)
3020 if ((error
= mac_system_check_info(kauth_cred_get(), "kern.msgbuf"))) {
3025 if (suser(kauth_cred_get(), (u_short
*)0) == 0) {
3026 return log_dmesg(buffer
, buffersize
, retval
);
3032 /* ********* process control sets on self only */
3034 proc_setcontrol(int pid
, int flavor
, uint64_t arg
, user_addr_t buffer
, uint32_t buffersize
, __unused
int32_t * retval
)
3036 struct proc
* pself
= PROC_NULL
;
3038 uint32_t pcontrol
= (uint32_t)arg
;
3039 struct uthread
*ut
= NULL
;
3040 char name_buf
[MAXTHREADNAMESIZE
];
3042 pself
= current_proc();
3043 if (pid
!= pself
->p_pid
) {
3047 /* Do we have permission to look into this? */
3048 if ((error
= proc_security_policy(pself
, PROC_INFO_CALL_SETCONTROL
, flavor
, NO_CHECK_SAME_USER
))) {
3053 case PROC_SELFSET_PCONTROL
: {
3054 if (pcontrol
> P_PCMAX
) {
3058 /* reset existing control setting while retaining action state */
3059 pself
->p_pcaction
&= PROC_ACTION_MASK
;
3060 /* set new control state */
3061 pself
->p_pcaction
|= pcontrol
;
3066 case PROC_SELFSET_THREADNAME
: {
3068 * This is a bit ugly, as it copies the name into the kernel, and then
3069 * invokes bsd_setthreadname again to copy it into the uthread name
3070 * buffer. Hopefully this isn't such a hot codepath that an additional
3071 * MAXTHREADNAMESIZE copy is a big issue.
3073 if (buffersize
> (MAXTHREADNAMESIZE
- 1)) {
3074 return ENAMETOOLONG
;
3077 ut
= current_uthread();
3079 bzero(name_buf
, MAXTHREADNAMESIZE
);
3080 error
= copyin(buffer
, name_buf
, buffersize
);
3083 bsd_setthreadname(ut
, name_buf
);
3088 case PROC_SELFSET_VMRSRCOWNER
: {
3089 /* need to to be superuser */
3090 if (suser(kauth_cred_get(), (u_short
*)0) != 0) {
3096 /* reset existing control setting while retaining action state */
3097 pself
->p_lflag
|= P_LVMRSRCOWNER
;
3102 case PROC_SELFSET_DELAYIDLESLEEP
: {
3103 #if CONFIG_DELAY_IDLE_SLEEP
3104 /* mark or clear the process property to delay idle sleep disk IO */
3105 if (pcontrol
!= 0) {
3106 OSBitOrAtomic(P_DELAYIDLESLEEP
, &pself
->p_flag
);
3108 OSBitAndAtomic(~((uint32_t)P_DELAYIDLESLEEP
), &pself
->p_flag
);
3126 #if CONFIG_MEMORYSTATUS
3129 proc_dirtycontrol(int pid
, int flavor
, uint64_t arg
, int32_t *retval
)
3131 struct proc
*target_p
;
3133 uint32_t pcontrol
= (uint32_t)arg
;
3134 kauth_cred_t my_cred
, target_cred
;
3135 boolean_t self
= FALSE
;
3136 boolean_t child
= FALSE
;
3137 boolean_t zombref
= FALSE
;
3140 target_p
= proc_find(pid
);
3142 if (target_p
== PROC_NULL
) {
3143 if (flavor
== PROC_DIRTYCONTROL_GET
) {
3144 target_p
= proc_find_zombref(pid
);
3148 if (target_p
== PROC_NULL
) {
3153 my_cred
= kauth_cred_get();
3154 target_cred
= kauth_cred_proc_ref(target_p
);
3156 /* Do we have permission to look into this? */
3157 if ((error
= proc_security_policy(target_p
, PROC_INFO_CALL_DIRTYCONTROL
, flavor
, NO_CHECK_SAME_USER
))) {
3161 selfpid
= proc_selfpid();
3162 if (pid
== selfpid
) {
3164 } else if (target_p
->p_ppid
== selfpid
) {
3169 case PROC_DIRTYCONTROL_TRACK
: {
3170 /* Only allow the process itself, its parent, or root */
3171 if ((self
== FALSE
) && (child
== FALSE
) && kauth_cred_issuser(kauth_cred_get()) != TRUE
) {
3176 error
= memorystatus_dirty_track(target_p
, pcontrol
);
3180 case PROC_DIRTYCONTROL_SET
: {
3181 /* Check privileges; use cansignal() here since the process could be terminated */
3182 if (!cansignal(current_proc(), my_cred
, target_p
, SIGKILL
)) {
3187 error
= memorystatus_dirty_set(target_p
, self
, pcontrol
);
3191 case PROC_DIRTYCONTROL_GET
: {
3192 /* No permissions check - dirty state is freely available */
3194 *retval
= memorystatus_dirty_get(target_p
, FALSE
);
3201 case PROC_DIRTYCONTROL_CLEAR
: {
3202 /* Check privileges; use cansignal() here since the process could be terminated */
3203 if (!cansignal(current_proc(), my_cred
, target_p
, SIGKILL
)) {
3208 error
= memorystatus_dirty_clear(target_p
, pcontrol
);
3215 proc_drop_zombref(target_p
);
3217 proc_rele(target_p
);
3220 kauth_cred_unref(&target_cred
);
3227 proc_dirtycontrol(__unused
int pid
, __unused
int flavor
, __unused
uint64_t arg
, __unused
int32_t *retval
)
3232 #endif /* CONFIG_MEMORYSTATUS */
3235 * proc_terminate() provides support for sudden termination.
3236 * SIGKILL is issued to tracked, clean processes; otherwise,
3241 proc_terminate(int pid
, int32_t *retval
)
3245 kauth_cred_t uc
= kauth_cred_get();
3249 /* XXX: Check if these are necessary */
3250 AUDIT_ARG(pid
, pid
);
3251 AUDIT_ARG(signum
, sig
);
3254 if (pid
<= 0 || retval
== NULL
) {
3258 if ((p
= proc_find(pid
)) == NULL
) {
3263 /* XXX: Check if these are necessary */
3264 AUDIT_ARG(process
, p
);
3267 /* Check privileges; if SIGKILL can be issued, then SIGTERM is also OK */
3268 if (!cansignal(current_proc(), uc
, p
, SIGKILL
)) {
3273 /* Not allowed to sudden terminate yourself */
3274 if (p
== current_proc()) {
3279 #if CONFIG_MEMORYSTATUS
3280 /* Determine requisite signal to issue */
3281 sig
= memorystatus_on_terminate(p
);
3286 proc_set_task_policy(p
->task
, TASK_POLICY_ATTRIBUTE
,
3287 TASK_POLICY_TERMINATED
, TASK_POLICY_ENABLE
);
3299 * copy stat64 structure into vinfo_stat structure.
3302 munge_vinfo_stat(struct stat64
*sbp
, struct vinfo_stat
*vsbp
)
3304 bzero(vsbp
, sizeof(struct vinfo_stat
));
3306 vsbp
->vst_dev
= sbp
->st_dev
;
3307 vsbp
->vst_mode
= sbp
->st_mode
;
3308 vsbp
->vst_nlink
= sbp
->st_nlink
;
3309 vsbp
->vst_ino
= sbp
->st_ino
;
3310 vsbp
->vst_uid
= sbp
->st_uid
;
3311 vsbp
->vst_gid
= sbp
->st_gid
;
3312 vsbp
->vst_atime
= sbp
->st_atimespec
.tv_sec
;
3313 vsbp
->vst_atimensec
= sbp
->st_atimespec
.tv_nsec
;
3314 vsbp
->vst_mtime
= sbp
->st_mtimespec
.tv_sec
;
3315 vsbp
->vst_mtimensec
= sbp
->st_mtimespec
.tv_nsec
;
3316 vsbp
->vst_ctime
= sbp
->st_ctimespec
.tv_sec
;
3317 vsbp
->vst_ctimensec
= sbp
->st_ctimespec
.tv_nsec
;
3318 vsbp
->vst_birthtime
= sbp
->st_birthtimespec
.tv_sec
;
3319 vsbp
->vst_birthtimensec
= sbp
->st_birthtimespec
.tv_nsec
;
3320 vsbp
->vst_size
= sbp
->st_size
;
3321 vsbp
->vst_blocks
= sbp
->st_blocks
;
3322 vsbp
->vst_blksize
= sbp
->st_blksize
;
3323 vsbp
->vst_flags
= sbp
->st_flags
;
3324 vsbp
->vst_gen
= sbp
->st_gen
;
3325 vsbp
->vst_rdev
= sbp
->st_rdev
;
3326 vsbp
->vst_qspare
[0] = sbp
->st_qspare
[0];
3327 vsbp
->vst_qspare
[1] = sbp
->st_qspare
[1];
3331 proc_pid_rusage(int pid
, int flavor
, user_addr_t buffer
, __unused
int32_t *retval
)
3337 if ((p
= proc_find(pid
)) == PROC_NULL
) {
3338 if ((p
= proc_find_zombref(pid
)) == PROC_NULL
) {
3344 /* Do we have permission to look into this? */
3345 if ((error
= proc_security_policy(p
, PROC_INFO_CALL_PIDRUSAGE
, flavor
, CHECK_SAME_USER
))) {
3349 error
= proc_get_rusage(p
, flavor
, buffer
, zombie
);
3353 proc_drop_zombref(p
);
3362 proc_archinfo(proc_t p
, struct proc_archinfo
*pai
)
3366 pai
->p_cputype
= p
->p_cputype
;
3367 pai
->p_cpusubtype
= p
->p_cpusubtype
;
3373 proc_pidcoalitioninfo(proc_t p
, struct proc_pidcoalitioninfo
*ppci
)
3375 bzero(ppci
, sizeof(*ppci
));
3376 proc_coalitionids(p
, ppci
->coalition_id
);
3380 proc_pidexitreasoninfo(proc_t p
, struct proc_exitreasoninfo
*peri
, struct proc_exitreasonbasicinfo
*pberi
)
3382 uint32_t reason_data_size
= 0;
3384 pid_t selfpid
= proc_selfpid();
3389 * One (and only one) of peri and pberi must be non-NULL.
3391 assert((peri
!= NULL
) || (pberi
!= NULL
));
3392 assert((peri
== NULL
) || (pberi
== NULL
));
3395 * Allow access to the parent of the exiting
3396 * child or the parent debugger only.
3399 if (p
->p_ppid
== selfpid
) {
3400 break; /* parent => ok */
3402 if ((p
->p_lflag
& P_LTRACED
) != 0 &&
3403 (p
->p_oppid
== selfpid
)) {
3404 break; /* parent-in-waiting => ok */
3410 if (p
->p_exit_reason
== OS_REASON_NULL
) {
3415 if (p
->p_exit_reason
->osr_kcd_buf
!= NULL
) {
3416 reason_data_size
= (uint32_t)kcdata_memory_get_used_bytes(&p
->p_exit_reason
->osr_kcd_descriptor
);
3420 peri
->eri_namespace
= p
->p_exit_reason
->osr_namespace
;
3421 peri
->eri_code
= p
->p_exit_reason
->osr_code
;
3422 peri
->eri_flags
= p
->p_exit_reason
->osr_flags
;
3424 if ((peri
->eri_kcd_buf
== 0) || (peri
->eri_reason_buf_size
< reason_data_size
)) {
3429 peri
->eri_reason_buf_size
= reason_data_size
;
3430 if (reason_data_size
!= 0) {
3431 error
= copyout(p
->p_exit_reason
->osr_kcd_buf
, (user_addr_t
)peri
->eri_kcd_buf
, reason_data_size
);
3434 pberi
->beri_namespace
= p
->p_exit_reason
->osr_namespace
;
3435 pberi
->beri_code
= p
->p_exit_reason
->osr_code
;
3436 pberi
->beri_flags
= p
->p_exit_reason
->osr_flags
;
3437 pberi
->beri_reason_buf_size
= reason_data_size
;
3446 * Wrapper to provide NOTE_EXIT_DETAIL and NOTE_EXITSTATUS
3447 * It mimics the data that is typically captured by the
3448 * EVFILT_PROC, NOTE_EXIT event mechanism.
3449 * See filt_proc() in kern_event.c.
3452 proc_pidnoteexit(proc_t p
, uint64_t flags
, uint32_t *data
)
3454 uint32_t exit_data
= 0;
3455 uint32_t exit_flags
= (uint32_t)flags
;
3460 * Allow access to the parent of the exiting
3461 * child or the parent debugger only.
3464 pid_t selfpid
= proc_selfpid();
3466 if (p
->p_ppid
== selfpid
) {
3467 break; /* parent => ok */
3469 if ((p
->p_lflag
& P_LTRACED
) != 0 &&
3470 (p
->p_oppid
== selfpid
)) {
3471 break; /* parent-in-waiting => ok */
3477 if ((exit_flags
& NOTE_EXITSTATUS
) != 0) {
3478 /* The signal and exit status */
3479 exit_data
|= (p
->p_xstat
& NOTE_PDATAMASK
);
3482 if ((exit_flags
& NOTE_EXIT_DETAIL
) != 0) {
3483 /* The exit detail */
3484 if ((p
->p_lflag
& P_LTERM_DECRYPTFAIL
) != 0) {
3485 exit_data
|= NOTE_EXIT_DECRYPTFAIL
;
3488 if ((p
->p_lflag
& P_LTERM_JETSAM
) != 0) {
3489 exit_data
|= NOTE_EXIT_MEMORY
;
3491 switch (p
->p_lflag
& P_JETSAM_MASK
) {
3492 case P_JETSAM_VMPAGESHORTAGE
:
3493 exit_data
|= NOTE_EXIT_MEMORY_VMPAGESHORTAGE
;
3495 case P_JETSAM_VMTHRASHING
:
3496 exit_data
|= NOTE_EXIT_MEMORY_VMTHRASHING
;
3498 case P_JETSAM_FCTHRASHING
:
3499 exit_data
|= NOTE_EXIT_MEMORY_FCTHRASHING
;
3501 case P_JETSAM_VNODE
:
3502 exit_data
|= NOTE_EXIT_MEMORY_VNODE
;
3504 case P_JETSAM_HIWAT
:
3505 exit_data
|= NOTE_EXIT_MEMORY_HIWAT
;
3508 exit_data
|= NOTE_EXIT_MEMORY_PID
;
3510 case P_JETSAM_IDLEEXIT
:
3511 exit_data
|= NOTE_EXIT_MEMORY_IDLE
;
3516 if ((p
->p_csflags
& CS_KILLED
) != 0) {
3517 exit_data
|= NOTE_EXIT_CSERROR
;
3529 proc_piddynkqueueinfo(int pid
, int flavor
, kqueue_id_t kq_id
,
3530 user_addr_t ubuf
, uint32_t bufsize
, int32_t *retval
)
3535 if (ubuf
== USER_ADDR_NULL
) {
3540 if (p
== PROC_NULL
) {
3544 err
= proc_security_policy(p
, PROC_INFO_CALL_PIDDYNKQUEUEINFO
, 0, CHECK_SAME_USER
);
3550 case PROC_PIDDYNKQUEUE_INFO
:
3551 err
= kevent_copyout_dynkqinfo(p
, kq_id
, ubuf
, bufsize
, retval
);
3553 case PROC_PIDDYNKQUEUE_EXTINFO
:
3554 err
= kevent_copyout_dynkqextinfo(p
, kq_id
, ubuf
, bufsize
, retval
);
3567 #if CONFIG_PROC_UDATA_STORAGE
3569 proc_udata_info(int pid
, int flavor
, user_addr_t buffer
, uint32_t bufsize
, int32_t *retval
)
3575 if (p
== PROC_NULL
) {
3580 * Only support calls against oneself for the moment.
3582 if (p
->p_pid
!= proc_selfpid()) {
3587 if (bufsize
!= sizeof(p
->p_user_data
)) {
3593 case PROC_UDATA_INFO_SET
:
3594 err
= copyin(buffer
, &p
->p_user_data
, sizeof(p
->p_user_data
));
3596 case PROC_UDATA_INFO_GET
:
3597 err
= copyout(&p
->p_user_data
, buffer
, sizeof(p
->p_user_data
));
3613 #endif /* CONFIG_PROC_UDATA_STORAGE */