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