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