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