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