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