]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/proc_info.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / kern / proc_info.c
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 /*
24 * sysctl system call.
25 */
26
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/kernel.h>
30 #include <sys/malloc.h>
31 #include <sys/proc_internal.h>
32 #include <sys/kauth.h>
33 #include <sys/file_internal.h>
34 #include <sys/vnode_internal.h>
35 #include <sys/unistd.h>
36 #include <sys/buf.h>
37 #include <sys/ioctl.h>
38 #include <sys/namei.h>
39 #include <sys/tty.h>
40 #include <sys/disklabel.h>
41 #include <sys/vm.h>
42 #include <sys/sysctl.h>
43 #include <sys/user.h>
44 #include <sys/aio_kern.h>
45
46 #include <bsm/audit_kernel.h>
47
48 #include <mach/machine.h>
49 #include <mach/mach_types.h>
50 #include <mach/vm_param.h>
51 #include <kern/task.h>
52 #include <kern/lock.h>
53 #include <kern/kalloc.h>
54 #include <vm/vm_kern.h>
55 #include <vm/vm_map.h>
56 #include <mach/host_info.h>
57 #include <mach/task_info.h>
58 #include <mach/thread_info.h>
59 #include <mach/vm_region.h>
60
61 #include <sys/mount_internal.h>
62 #include <sys/proc_info.h>
63 #include <sys/bsdtask_info.h>
64 #include <sys/kdebug.h>
65 #include <sys/sysproto.h>
66 #include <sys/msgbuf.h>
67
68
69 #include <machine/machine_routines.h>
70
71 #include <vm/vm_protos.h>
72
73 struct pshmnode;
74 struct psemnode;
75 struct pipe;
76 struct kqueue;
77 struct atalk;
78
79 int proc_info_internal(int callnum, int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t * retval);
80
81 /* protos for proc_info calls */
82 int proc_listpids(uint32_t type, uint32_t tyoneinfo, user_addr_t buffer, uint32_t buffersize, register_t * retval);
83 int proc_pidinfo(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t * retval);
84 int proc_pidfdinfo(int pid, int flavor,int fd, user_addr_t buffer, uint32_t buffersize, register_t * retval);
85 int proc_kernmsgbuf(user_addr_t buffer, uint32_t buffersize, register_t * retval);
86
87 /* protos for procpidinfo calls */
88 int proc_pidfdlist(proc_t p, user_addr_t buffer, uint32_t buffersize, register_t *retval);
89 int proc_pidbsdinfo(proc_t p, struct proc_bsdinfo *pbsd);
90 int proc_pidtaskinfo(proc_t p, struct proc_taskinfo *ptinfo);
91 int proc_pidallinfo(proc_t p, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t *retval);
92 int proc_pidthreadinfo(proc_t p, uint64_t arg, struct proc_threadinfo *pthinfo);
93 int proc_pidlistthreads(proc_t p, user_addr_t buffer, uint32_t buffersize, register_t *retval);
94 int proc_pidregioninfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t *retval);
95 int proc_pidregionpathinfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t *retval);
96 int proc_pidvnodepathinfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t *retval);
97
98
99 /* protos for proc_pidfdinfo calls */
100 int pid_vnodeinfo(vnode_t vp, uint32_t vid, struct fileproc * fp, user_addr_t buffer, uint32_t buffersize, register_t * retval);
101 int pid_vnodeinfopath(vnode_t vp, uint32_t vid, struct fileproc * fp, user_addr_t buffer, uint32_t buffersize, register_t * retval);
102 int pid_socketinfo(socket_t so, struct fileproc *fp, user_addr_t buffer, uint32_t buffersize, register_t * retval);
103 int pid_pseminfo(struct psemnode * psem, struct fileproc * fp, user_addr_t buffer, uint32_t buffersize, register_t * retval);
104 int pid_pshminfo(struct pshmnode * pshm, struct fileproc * fp, user_addr_t buffer, uint32_t buffersize, register_t * retval);
105 int pid_pipeinfo(struct pipe * p, struct fileproc * fp, user_addr_t buffer, uint32_t buffersize, register_t * retval);
106 int pid_kqueueinfo(struct kqueue * kq, struct fileproc * fp, user_addr_t buffer, uint32_t buffersize, register_t * retval);
107 int pid_atalkinfo(struct atalk * at, struct fileproc * fp, user_addr_t buffer, uint32_t buffersize, register_t * retval);
108
109
110 /* protos for misc */
111
112 int fill_vnodeinfo(vnode_t vp, struct vnode_info *vinfo);
113 void fill_fileinfo(struct fileproc * fp, struct proc_fileinfo * finfo);
114 static int proc_security_policy(proc_t p);
115
116
117 /***************************** proc_info ********************/
118
119 int
120 proc_info(__unused struct proc *p, struct proc_info_args * uap, register_t *retval)
121 {
122 return(proc_info_internal(uap->callnum, uap->pid, uap->flavor, uap->arg, uap->buffer, uap->buffersize, retval));
123 }
124
125
126 int
127 proc_info_internal(int callnum, int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t * retval)
128 {
129
130 switch(callnum) {
131 case 1: /* proc_listpids */
132 /* pid contains type and flavor contains typeinfo */
133 return(proc_listpids(pid, flavor, buffer, buffersize, retval));
134 case 2: /* proc_pidinfo */
135 return(proc_pidinfo(pid, flavor, arg, buffer, buffersize, retval));
136 case 3: /* proc_pidfdinfo */
137 return(proc_pidfdinfo(pid, flavor, (int)arg, buffer, buffersize, retval));
138 case 4: /* proc_kernmsgbuf */
139 return(proc_kernmsgbuf( buffer, buffersize, retval));
140 default:
141 return(EINVAL);
142 }
143
144 return(EINVAL);
145 }
146
147 /******************* proc_listpids routine ****************/
148 int
149 proc_listpids(uint32_t type, uint32_t typeinfo, user_addr_t buffer, uint32_t buffersize, register_t * retval)
150 {
151 boolean_t funnel_state;
152 int numprocs, wantpids;
153 char * kbuf;
154 int * ptr;
155 int n, skip;
156 struct proc * p;
157 int error = 0;
158
159 /* if the buffer is null, return num of procs */
160 if (buffer == (user_addr_t)0) {
161 *retval = ((nprocs+20) * sizeof(int));
162 return(0);
163 }
164
165 if (buffersize < sizeof(int)) {
166 return(ENOMEM);
167 }
168 wantpids = buffersize/sizeof(int);
169 numprocs = nprocs+20;
170 if (numprocs > wantpids)
171 numprocs = wantpids;
172
173 kbuf = (char *)kalloc((vm_size_t)(numprocs * sizeof(int)));
174 bzero(kbuf, sizeof(int));
175
176 funnel_state = thread_funnel_set(kernel_flock, TRUE);
177
178 n = 0;
179 ptr = (int *)kbuf;
180 LIST_FOREACH(p, &allproc, p_list) {
181 skip = 0;
182 switch (type) {
183 case PROC_PGRP_ONLY:
184 if (p->p_pgrp->pg_id != (pid_t)typeinfo)
185 skip = 1;
186 break;
187 case PROC_ALL_PIDS:
188 skip = 0;
189 break;
190 case PROC_TTY_ONLY:
191 if ((p->p_flag & P_CONTROLT) == 0 ||
192 (p->p_session == NULL) ||
193 p->p_session->s_ttyp == NULL ||
194 p->p_session->s_ttyp->t_dev != (dev_t)typeinfo)
195 skip = 1;
196 break;
197 case PROC_UID_ONLY:
198 if ((p->p_ucred == NULL) ||
199 (kauth_cred_getuid(p->p_ucred) != (uid_t)typeinfo))
200 skip = 1;
201 break;
202 case PROC_RUID_ONLY:
203 if ((p->p_ucred == NULL) ||
204 (p->p_ucred->cr_ruid != (uid_t)typeinfo))
205 break;
206 default:
207 skip = 1;
208 break;
209 };
210
211 /* Do we have permission to look into this ? */
212 if (proc_security_policy(p) != 0) {
213 skip = 1;
214 }
215
216 if(skip == 0) {
217 *ptr++ = p->p_pid;
218 n++;
219 }
220 if (n >= numprocs)
221 break;
222 }
223
224 if (n < numprocs) {
225 LIST_FOREACH(p, &zombproc, p_list) {
226 *ptr++ = p->p_pid;
227 n++;
228 if (n >= numprocs)
229 break;
230 }
231 }
232
233 thread_funnel_set(kernel_flock, funnel_state);
234
235 ptr = (int *)kbuf;
236 error = copyout((caddr_t)ptr, buffer, n * sizeof(int));
237 if (error == 0)
238 *retval = (n * sizeof(int));
239 kfree((void *)kbuf, (vm_size_t)(numprocs * sizeof(int)));
240
241 return(error);
242 }
243
244
245 /********************************** proc_pidinfo routines ********************************/
246
247 int
248 proc_pidfdlist(proc_t p, user_addr_t buffer, uint32_t buffersize, register_t *retval)
249 {
250 int numfds, needfds;
251 char * kbuf;
252 struct proc_fdinfo * pfd;
253 struct fileproc * fp;
254 int n;
255 int count = 0;
256 int error = 0;
257
258 numfds = p->p_fd->fd_nfiles;
259
260 if (buffer == (user_addr_t) 0) {
261 numfds += 20;
262 *retval = (numfds * sizeof(struct proc_fdinfo));
263 return(0);
264 }
265
266 /* buffersize is big enough atleast for one struct */
267 needfds = buffersize/sizeof(struct proc_fdinfo);
268
269 if (numfds > needfds)
270 numfds = needfds;
271
272 kbuf = (char *)kalloc((vm_size_t)(numfds * sizeof(struct proc_fdinfo)));
273 bzero(kbuf, numfds * sizeof(struct proc_fdinfo));
274
275 proc_fdlock(p);
276
277 pfd = (struct proc_fdinfo *)kbuf;
278
279 for (n = 0; ((n < numfds) && (n < p->p_fd->fd_nfiles)); n++) {
280 if (((fp = p->p_fd->fd_ofiles[n]) != 0)
281 && ((p->p_fd->fd_ofileflags[n] & UF_RESERVED) == 0)) {
282 pfd->proc_fd = n;
283 pfd->proc_fdtype = fp->f_fglob->fg_type;
284 count++;
285 pfd++;
286 }
287 }
288 proc_fdunlock(p);
289
290 error = copyout(kbuf, buffer, count * sizeof(struct proc_fdinfo));
291 kfree((void *)kbuf, (vm_size_t)(numfds * sizeof(struct proc_fdinfo)));
292 if (error == 0)
293 *retval = (count * sizeof(struct proc_fdinfo));
294 return(error);
295 }
296
297
298 int
299 proc_pidbsdinfo(proc_t p, struct proc_bsdinfo * pbsd)
300 {
301 register struct tty *tp;
302 struct session *sessionp = NULL;
303
304 bzero(pbsd, sizeof(struct proc_bsdinfo));
305 pbsd->pbi_status = p->p_stat;
306 pbsd->pbi_xstatus = p->p_xstat;
307 pbsd->pbi_pid = p->p_pid;
308 pbsd->pbi_ppid = p->p_pptr->p_pid;
309 pbsd->pbi_uid = p->p_ucred->cr_uid;
310 pbsd->pbi_gid = p->p_ucred->cr_uid; /* XXX */
311 pbsd->pbi_ruid = p->p_ucred->cr_ruid;
312 pbsd->pbi_rgid = p->p_ucred->cr_rgid;
313 pbsd->pbi_svuid = p->p_ucred->cr_svuid;
314 pbsd->pbi_svgid = p->p_ucred->cr_svgid;
315
316 pbsd->pbi_nice = p->p_nice;
317 if (p->p_stats)
318 pbsd->pbi_start = p->p_stats->p_start;
319 bcopy(&p->p_comm, &pbsd->pbi_comm[0], MAXCOMLEN);
320 bcopy(&p->p_name, &pbsd->pbi_name[0], 2* MAXCOMLEN);
321
322 pbsd->pbi_flags = 0;
323 if ((p->p_flag & P_SYSTEM) == P_SYSTEM)
324 pbsd->pbi_flags |= PROC_FLAG_SYSTEM;
325 if ((p->p_flag & P_TRACED) == P_TRACED)
326 pbsd->pbi_flags |= PROC_FLAG_TRACED;
327 if ((p->p_flag & P_WEXIT) == P_WEXIT)
328 pbsd->pbi_flags |= PROC_FLAG_INEXIT;
329 if ((p->p_flag & P_PPWAIT) == P_PPWAIT)
330 pbsd->pbi_flags |= PROC_FLAG_PPWAIT;
331 if ((p->p_flag & P_LP64) == P_LP64)
332 pbsd->pbi_flags |= PROC_FLAG_LP64;
333 if ((p->p_flag & P_CONTROLT) == P_CONTROLT)
334 pbsd->pbi_flags |= PROC_FLAG_CONTROLT;
335
336 if (SESS_LEADER(p))
337 pbsd->pbi_flags |= PROC_FLAG_SLEADER;
338 if (p->p_pgrp->pg_session && p->p_pgrp->pg_session->s_ttyvp)
339 pbsd->pbi_flags |= PROC_FLAG_CTTY;
340
341 pbsd->pbi_nfiles = p->p_fd->fd_nfiles;
342 if (p->p_pgrp) {
343 sessionp = p->p_pgrp->pg_session;
344 pbsd->pbi_pgid = p->p_pgrp->pg_id;
345 pbsd->pbi_pjobc = p->p_pgrp->pg_jobc;
346 if ((p->p_flag & P_CONTROLT) && (sessionp) && (tp = sessionp->s_ttyp)) {
347 pbsd->e_tdev = tp->t_dev;
348 pbsd->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
349 }
350 }
351 return(0);
352 }
353
354
355 int
356 proc_pidtaskinfo(proc_t p, struct proc_taskinfo * ptinfo)
357 {
358 task_t task;
359
360 task = p->task;
361
362 bzero(ptinfo, sizeof(struct proc_taskinfo));
363 fill_taskprocinfo(task, (struct proc_taskinfo_internal *)ptinfo);
364
365 return(0);
366 }
367
368
369
370 int
371 proc_pidthreadinfo(proc_t p, uint64_t arg, struct proc_threadinfo *pthinfo)
372 {
373 int error = 0;
374 uint64_t threadaddr = (uint64_t)arg;
375
376 bzero(pthinfo, sizeof(struct proc_threadinfo));
377
378 error = fill_taskthreadinfo(p->task, threadaddr, (struct proc_threadinfo_internal *)pthinfo);
379 if (error)
380 return(ESRCH);
381 else
382 return(0);
383
384 }
385
386
387 int
388 proc_pidlistthreads(proc_t p, user_addr_t buffer, uint32_t buffersize, register_t *retval)
389 {
390 int count = 0;
391 int ret = 0;
392 int error = 0;
393 void * kbuf;
394 int numthreads;
395
396
397 count = buffersize/(sizeof(uint64_t));
398 numthreads = get_numthreads(p->task);
399
400 numthreads += 10;
401
402 if (numthreads > count)
403 numthreads = count;
404
405 kbuf = (void *)kalloc(numthreads * sizeof(uint64_t));
406 bzero(kbuf, numthreads * sizeof(uint64_t));
407
408 ret = fill_taskthreadlist(p->task, kbuf, numthreads);
409
410 error = copyout(kbuf, buffer, ret);
411 kfree(kbuf, numthreads * sizeof(uint64_t));
412 if (error == 0)
413 *retval = ret;
414 return(error);
415
416 }
417
418
419 int
420 proc_pidregioninfo(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, register_t *retval)
421 {
422 struct proc_regioninfo preginfo;
423 int ret, error = 0;
424
425 bzero(&preginfo, sizeof(struct proc_regioninfo));
426 ret = fill_procregioninfo( p->task, arg, (struct proc_regioninfo_internal *)&preginfo, (uint32_t *)0, (uint32_t *)0);
427 if (ret == 0)
428 return(EINVAL);
429 error = copyout(&preginfo, buffer, sizeof(struct proc_regioninfo));
430 if (error == 0)
431 *retval = sizeof(struct proc_regioninfo);
432 return(error);
433 }
434
435
436 int
437 proc_pidregionpathinfo(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, register_t *retval)
438 {
439 struct proc_regionwithpathinfo preginfo;
440 int ret, error = 0;
441 uint32_t vnodeaddr= 0;
442 uint32_t vnodeid= 0;
443 vnode_t vp;
444 int count;
445
446 bzero(&preginfo, sizeof(struct proc_regionwithpathinfo));
447
448 ret = fill_procregioninfo( p->task, arg, (struct proc_regioninfo_internal *)&preginfo.prp_prinfo, (uint32_t *)&vnodeaddr, (uint32_t *)&vnodeid);
449 if (ret == 0)
450 return(EINVAL);
451 if (vnodeaddr) {
452 vp = (vnode_t)vnodeaddr;
453 if ((vnode_getwithvid(vp, vnodeid)) == 0) {
454 /* FILL THE VNODEINFO */
455 error = fill_vnodeinfo(vp, &preginfo.prp_vip.vip_vi);
456 count = MAXPATHLEN;
457 vn_getpath(vp, &preginfo.prp_vip.vip_path[0], &count);
458 /* Always make sure it is null terminated */
459 preginfo.prp_vip.vip_path[MAXPATHLEN-1] = 0;
460 vnode_put(vp);
461 }
462 }
463 error = copyout(&preginfo, buffer, sizeof(struct proc_regionwithpathinfo));
464 if (error == 0)
465 *retval = sizeof(struct proc_regionwithpathinfo);
466 return(error);
467 }
468
469 int
470 proc_pidvnodepathinfo(proc_t p, __unused uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, register_t *retval)
471 {
472 struct proc_vnodepathinfo pvninfo;
473 int error = 0;
474 vnode_t vncdirvp = NULLVP;
475 uint32_t vncdirid=0;
476 vnode_t vnrdirvp = NULLVP;
477 uint32_t vnrdirid=0;
478 int count;
479
480 bzero(&pvninfo, sizeof(struct proc_vnodepathinfo));
481
482 proc_fdlock(p);
483 if (p->p_fd->fd_cdir) {
484 vncdirvp = p->p_fd->fd_cdir;
485 vncdirid = p->p_fd->fd_cdir->v_id;
486 }
487 if (p->p_fd->fd_rdir) {
488 vnrdirvp = p->p_fd->fd_rdir;
489 vnrdirid = p->p_fd->fd_rdir->v_id;
490 }
491 proc_fdunlock(p);
492
493 if (vncdirvp != NULLVP) {
494 if ((error = vnode_getwithvid(vncdirvp, vncdirid)) == 0) {
495 /* FILL THE VNODEINFO */
496 error = fill_vnodeinfo(vncdirvp, &pvninfo.pvi_cdir.vip_vi);
497 if ( error == 0) {
498 count = MAXPATHLEN;
499 vn_getpath(vncdirvp, &pvninfo.pvi_cdir.vip_path[0], &count);
500 pvninfo.pvi_cdir.vip_path[MAXPATHLEN-1] = 0;
501 }
502 vnode_put(vncdirvp);
503 } else {
504 goto out;
505 }
506 }
507
508 if ((error == 0) && (vnrdirvp != NULLVP)) {
509 if ((error = vnode_getwithvid(vnrdirvp, vnrdirid)) == 0) {
510 /* FILL THE VNODEINFO */
511 error = fill_vnodeinfo(vnrdirvp, &pvninfo.pvi_rdir.vip_vi);
512 if ( error == 0) {
513 count = MAXPATHLEN;
514 vn_getpath(vnrdirvp, &pvninfo.pvi_rdir.vip_path[0], &count);
515 pvninfo.pvi_rdir.vip_path[MAXPATHLEN-1] = 0;
516 }
517 vnode_put(vnrdirvp);
518 } else {
519 goto out;
520 }
521 }
522 if (error == 0) {
523 error = copyout(&pvninfo, buffer, sizeof(struct proc_vnodepathinfo));
524 if (error == 0)
525 *retval = sizeof(struct proc_vnodepathinfo);
526 }
527 out:
528 return(error);
529 }
530
531 /********************************** proc_pidinfo ********************************/
532
533
534 int
535 proc_pidinfo(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t * retval)
536 {
537 struct proc * p = PROC_NULL;
538 int error = ENOTSUP;
539 int gotref = 0;
540 int findzomb = 0;
541 boolean_t funnel_state;
542 uint32_t size;
543
544 switch (flavor) {
545 case PROC_PIDLISTFDS:
546 size = PROC_PIDLISTFD_SIZE;
547 if (buffer == (user_addr_t)0)
548 size = 0;
549 break;
550 case PROC_PIDTBSDINFO:
551 size = PROC_PIDTBSDINFO_SIZE;
552 break;
553 case PROC_PIDTASKINFO:
554 size = PROC_PIDTASKINFO_SIZE;
555 break;
556 case PROC_PIDTASKALLINFO:
557 size = PROC_PIDTASKALLINFO_SIZE;
558 break;
559 case PROC_PIDTHREADINFO:
560 size = PROC_PIDTHREADINFO_SIZE;
561 break;
562 case PROC_PIDLISTTHREADS:
563 size = PROC_PIDLISTTHREADS_SIZE;
564 break;
565 case PROC_PIDREGIONINFO:
566 size = PROC_PIDREGIONINFO_SIZE;
567 break;
568 case PROC_PIDREGIONPATHINFO:
569 size = PROC_PIDREGIONPATHINFO_SIZE;
570 break;
571 case PROC_PIDVNODEPATHINFO:
572 size = PROC_PIDVNODEPATHINFO_SIZE;
573 break;
574 default:
575 return(EINVAL);
576 }
577
578 if (buffersize < size)
579 return(ENOMEM);
580
581 if (flavor != PROC_PIDTBSDINFO) {
582 if ((p = proc_findref(pid)) == PROC_NULL) {
583 error = ESRCH;
584 goto out;
585 } else {
586 gotref = 1;
587
588 /* Do we have permission to look into this ? */
589 if ((error = proc_security_policy(p)) != 0) {
590 goto out;
591 }
592 }
593 }
594 switch (flavor) {
595 case PROC_PIDLISTFDS: {
596 error = proc_pidfdlist(p, buffer, buffersize, retval);
597 }
598 break;
599
600 case PROC_PIDTBSDINFO: {
601 struct proc_bsdinfo pbsd;
602
603 if (arg)
604 findzomb = 1;
605 funnel_state = thread_funnel_set(kernel_flock, TRUE);
606 p = pfind(pid);
607 if (p == PROC_NULL) {
608 if (findzomb)
609 p = pzfind(pid);
610 if (p == NULL) {
611 error = ESRCH;
612 thread_funnel_set(kernel_flock, funnel_state);
613 goto out;
614 }
615 }
616 /* Do we have permission to look into this ? */
617 if ((error = proc_security_policy(p)) != 0) {
618 thread_funnel_set(kernel_flock, funnel_state);
619 goto out;
620 }
621 error = proc_pidbsdinfo(p, &pbsd);
622 thread_funnel_set(kernel_flock, funnel_state);
623 if (error == 0) {
624 error = copyout(&pbsd, buffer, sizeof(struct proc_bsdinfo));
625 if (error == 0)
626 *retval = sizeof(struct proc_bsdinfo);
627 }
628 }
629 break;
630
631 case PROC_PIDTASKINFO: {
632 struct proc_taskinfo ptinfo;
633
634 error = proc_pidtaskinfo(p, &ptinfo);
635 if (error == 0) {
636 error = copyout(&ptinfo, buffer, sizeof(struct proc_taskinfo));
637 if (error == 0)
638 *retval = sizeof(struct proc_taskinfo);
639 }
640 }
641 break;
642
643 case PROC_PIDTASKALLINFO: {
644 struct proc_taskallinfo pall;
645
646 error = proc_pidbsdinfo(p, &pall.pbsd);
647 error = proc_pidtaskinfo(p, &pall.ptinfo);
648 if (error == 0) {
649 error = copyout(&pall, buffer, sizeof(struct proc_taskallinfo));
650 if (error == 0)
651 *retval = sizeof(struct proc_taskallinfo);
652 }
653 }
654 break;
655
656 case PROC_PIDTHREADINFO:{
657 struct proc_threadinfo pthinfo;
658
659 error = proc_pidthreadinfo(p, arg, &pthinfo);
660 if (error == 0) {
661 error = copyout(&pthinfo, buffer, sizeof(struct proc_threadinfo));
662 if (error == 0)
663 *retval = sizeof(struct proc_threadinfo);
664 }
665 }
666 break;
667
668 case PROC_PIDLISTTHREADS:{
669 error = proc_pidlistthreads(p, buffer, buffersize, retval);
670 }
671 break;
672
673 case PROC_PIDREGIONINFO:{
674 error = proc_pidregioninfo(p, arg, buffer, buffersize, retval);
675 }
676 break;
677
678
679 case PROC_PIDREGIONPATHINFO:{
680 error = proc_pidregionpathinfo(p, arg, buffer, buffersize, retval);
681 }
682 break;
683
684 case PROC_PIDVNODEPATHINFO:{
685 error = proc_pidvnodepathinfo(p, arg, buffer, buffersize, retval);
686 }
687 break;
688
689 default:
690 error = ENOTSUP;
691 }
692
693 out:
694 if (gotref)
695 proc_dropref(p);
696 return(error);
697 }
698
699
700 int
701 pid_vnodeinfo(vnode_t vp, uint32_t vid, struct fileproc * fp, user_addr_t buffer, __unused uint32_t buffersize, register_t * retval)
702 {
703 struct vnode_fdinfo vfi;
704 int error= 0;
705
706 if ((error = vnode_getwithvid(vp, vid)) != 0) {
707 return(error);
708 }
709 bzero(&vfi, sizeof(struct vnode_fdinfo));
710 fill_fileinfo(fp, &vfi.pfi);
711 error = fill_vnodeinfo(vp, &vfi.pvi);
712 vnode_put(vp);
713 if (error == 0) {
714 error = copyout((caddr_t)&vfi, buffer, sizeof(struct vnode_fdinfo));
715 if (error == 0)
716 *retval = sizeof(struct vnode_fdinfo);
717 }
718 return(error);
719 }
720
721 int
722 pid_vnodeinfopath(vnode_t vp, uint32_t vid, struct fileproc * fp, user_addr_t buffer, __unused uint32_t buffersize, register_t * retval)
723 {
724 struct vnode_fdinfowithpath vfip;
725 int count, error= 0;
726
727 if ((error = vnode_getwithvid(vp, vid)) != 0) {
728 return(error);
729 }
730 bzero(&vfip, sizeof(struct vnode_fdinfowithpath));
731 fill_fileinfo(fp, &vfip.pfi);
732 error = fill_vnodeinfo(vp, &vfip.pvip.vip_vi) ;
733 if (error == 0) {
734 count = MAXPATHLEN;
735 vn_getpath(vp, &vfip.pvip.vip_path[0], &count);
736 vfip.pvip.vip_path[MAXPATHLEN-1] = 0;
737 vnode_put(vp);
738 error = copyout((caddr_t)&vfip, buffer, sizeof(struct vnode_fdinfowithpath));
739 if (error == 0)
740 *retval = sizeof(struct vnode_fdinfowithpath);
741 } else
742 vnode_put(vp);
743 return(error);
744 }
745
746 void
747 fill_fileinfo(struct fileproc * fp, struct proc_fileinfo * fproc)
748 {
749 fproc->fi_openflags = fp->f_fglob->fg_flag;
750 fproc->fi_status = fp->f_flags;
751 fproc->fi_offset = fp->f_fglob->fg_offset;
752 fproc->fi_type = fp->f_fglob->fg_type;
753 }
754
755
756
757 int
758 fill_vnodeinfo(vnode_t vp, struct vnode_info *vinfo)
759 {
760 vfs_context_t context;
761 struct stat * sb;
762 int error = 0;
763
764 sb = &vinfo->vi_stat;
765
766 context = vfs_context_create((vfs_context_t)0);
767 error = vn_stat(vp, sb, NULL, context);
768 (void)vfs_context_rele(context);
769
770 if (error != 0)
771 goto out;
772
773 if (vp->v_mount != dead_mountp) {
774 vinfo->vi_fsid = vp->v_mount->mnt_vfsstat.f_fsid;
775 } else {
776 vinfo->vi_fsid.val[0] = 0;
777 vinfo->vi_fsid.val[1] = 0;
778 }
779 vinfo->vi_type = vp->v_type;
780 out:
781 return(error);
782 }
783
784 int
785 pid_socketinfo(socket_t so, struct fileproc *fp, user_addr_t buffer, __unused uint32_t buffersize, register_t * retval)
786 {
787 struct socket_fdinfo s;
788 int error = 0;
789
790 bzero(&s, sizeof(struct socket_fdinfo));
791 fill_fileinfo(fp, &s.pfi);
792 if ((error = fill_socketinfo(so, &s.psi)) == 0) {
793 if ((error = copyout(&s, buffer, sizeof(struct socket_fdinfo))) == 0)
794 *retval = sizeof(struct socket_fdinfo);
795 }
796
797 return (error);
798 }
799
800 int
801 pid_pseminfo(struct psemnode *psem, struct fileproc *fp, user_addr_t buffer, __unused uint32_t buffersize, register_t * retval)
802 {
803 struct psem_fdinfo pseminfo;
804 int error = 0;
805
806 bzero(&pseminfo, sizeof(struct psem_fdinfo));
807 fill_fileinfo(fp, &pseminfo.pfi);
808
809 if ((error = fill_pseminfo(psem, &pseminfo.pseminfo)) == 0) {
810 if ((error = copyout(&pseminfo, buffer, sizeof(struct psem_fdinfo))) == 0)
811 *retval = sizeof(struct psem_fdinfo);
812 }
813
814 return(error);
815 }
816
817 int
818 pid_pshminfo(struct pshmnode *pshm, struct fileproc *fp, user_addr_t buffer, __unused uint32_t buffersize, register_t * retval)
819 {
820 struct pshm_fdinfo pshminfo;
821 int error = 0;
822
823 bzero(&pshminfo, sizeof(struct pshm_fdinfo));
824 fill_fileinfo(fp, &pshminfo.pfi);
825
826 if ((error = fill_pshminfo(pshm, &pshminfo.pshminfo)) == 0) {
827 if ((error = copyout(&pshminfo, buffer, sizeof(struct pshm_fdinfo))) == 0)
828 *retval = sizeof(struct pshm_fdinfo);
829 }
830
831 return(error);
832 }
833
834 int
835 pid_pipeinfo(struct pipe * p, struct fileproc *fp, user_addr_t buffer, __unused uint32_t buffersize, register_t * retval)
836 {
837 struct pipe_fdinfo pipeinfo;
838 int error = 0;
839
840 bzero(&pipeinfo, sizeof(struct pipe_fdinfo));
841 fill_fileinfo(fp, &pipeinfo.pfi);
842 if ((error = fill_pipeinfo(p, &pipeinfo.pipeinfo)) == 0) {
843 if ((error = copyout(&pipeinfo, buffer, sizeof(struct pipe_fdinfo))) == 0)
844 *retval = sizeof(struct pipe_fdinfo);
845 }
846
847 return(error);
848 }
849
850 int
851 pid_kqueueinfo(struct kqueue * kq, struct fileproc *fp, user_addr_t buffer, __unused uint32_t buffersize, register_t * retval)
852 {
853 struct kqueue_fdinfo kqinfo;
854 int error = 0;
855
856 bzero(&kqinfo, sizeof(struct kqueue_fdinfo));
857
858 fill_fileinfo(fp, &kqinfo.pfi);
859
860 if ((error = fill_kqueueinfo(kq, &kqinfo.kqueueinfo)) == 0) {
861 if ((error = copyout(&kqinfo, buffer, sizeof(struct kqueue_fdinfo))) == 0)
862 *retval = sizeof(struct kqueue_fdinfo);
863 }
864
865 return(error);
866 }
867
868 int
869 pid_atalkinfo(__unused struct atalk * at, __unused struct fileproc *fp, __unused user_addr_t buffer, __unused uint32_t buffersize, __unused register_t * retval)
870 {
871 return ENOTSUP;
872 }
873
874
875
876 /************************** proc_pidfdinfo routine ***************************/
877 int
878 proc_pidfdinfo(int pid, int flavor, int fd, user_addr_t buffer, uint32_t buffersize, register_t * retval)
879 {
880 proc_t p;
881 int error = ENOTSUP;
882 struct fileproc * fp;
883 uint32_t size;
884
885
886 switch (flavor) {
887 case PROC_PIDFDVNODEINFO:
888 size = PROC_PIDFDVNODEINFO_SIZE;
889 break;
890 case PROC_PIDFDVNODEPATHINFO:
891 size = PROC_PIDFDVNODEPATHINFO_SIZE;
892 break;
893 case PROC_PIDFDSOCKETINFO:
894 size = PROC_PIDFDSOCKETINFO_SIZE;
895 break;
896 case PROC_PIDFDPSEMINFO:
897 size = PROC_PIDFDPSEMINFO_SIZE;
898 break;
899 case PROC_PIDFDPSHMINFO:
900 size = PROC_PIDFDPSHMINFO_SIZE;
901 break;
902 case PROC_PIDFDPIPEINFO:
903 size = PROC_PIDFDPIPEINFO_SIZE;
904 break;
905 case PROC_PIDFDKQUEUEINFO:
906 size = PROC_PIDFDKQUEUEINFO_SIZE;
907 break;
908 case PROC_PIDFDATALKINFO:
909 size = PROC_PIDFDATALKINFO_SIZE;
910 break;
911
912 default:
913 return(EINVAL);
914
915 }
916
917 if (buffersize < size)
918 return(ENOMEM);
919
920 if ((p = proc_findref(pid)) == PROC_NULL) {
921 error = ESRCH;
922 goto out;
923 }
924 /* Do we have permission to look into this ? */
925 if ((error = proc_security_policy(p)) != 0) {
926 goto out1;
927 }
928
929 switch (flavor) {
930 case PROC_PIDFDVNODEINFO: {
931 vnode_t vp;
932 uint32_t vid=0;
933
934 if ((error = fp_getfvpandvid(p, fd, &fp, &vp, &vid)) !=0) {
935 goto out1;
936 }
937 error = pid_vnodeinfo(vp, vid, fp, buffer, buffersize, retval);
938 }
939 break;
940
941 case PROC_PIDFDVNODEPATHINFO: {
942 vnode_t vp;
943 uint32_t vid=0;
944
945 if ((error = fp_getfvpandvid(p, fd, &fp, &vp, &vid)) !=0) {
946 goto out1;
947 }
948
949 error = pid_vnodeinfopath(vp, vid, fp, buffer, buffersize, retval);
950 }
951 break;
952
953 case PROC_PIDFDSOCKETINFO: {
954 socket_t so;
955
956 if ((error = fp_getfsock(p, fd, &fp, &so)) !=0) {
957 goto out1;
958 }
959 error = pid_socketinfo(so, fp, buffer, buffersize, retval);
960 }
961 break;
962
963 case PROC_PIDFDPSEMINFO: {
964 struct psemnode * psem;
965
966 if ((error = fp_getfpsem(p, fd, &fp, &psem)) !=0) {
967 goto out1;
968 }
969 error = pid_pseminfo(psem, fp, buffer, buffersize, retval);
970 }
971 break;
972
973 case PROC_PIDFDPSHMINFO: {
974 struct pshmnode * pshm;
975
976 if ((error = fp_getfpshm(p, fd, &fp, &pshm)) !=0) {
977 goto out1;
978 }
979 error = pid_pshminfo(pshm, fp, buffer, buffersize, retval);
980 }
981 break;
982
983 case PROC_PIDFDPIPEINFO: {
984 struct pipe * cpipe;
985
986 if ((error = fp_getfpipe(p, fd, &fp, &cpipe)) !=0) {
987 goto out1;
988 }
989 error = pid_pipeinfo(cpipe, fp, buffer, buffersize, retval);
990 }
991 break;
992
993 case PROC_PIDFDKQUEUEINFO: {
994 struct kqueue * kq;
995
996 if ((error = fp_getfkq(p, fd, &fp, &kq)) !=0) {
997 goto out1;
998 }
999 error = pid_kqueueinfo(kq, fp, buffer, buffersize, retval);
1000 }
1001 break;
1002
1003 case PROC_PIDFDATALKINFO: {
1004 struct atalk * at;
1005
1006 if ((error = fp_getfatalk(p, fd, &fp, &at)) !=0) {
1007 goto out1;
1008 }
1009
1010 error = pid_atalkinfo(at, fp, buffer, buffersize, retval);
1011 }
1012 break;
1013
1014 default: {
1015 error = EINVAL;
1016 }
1017 break;
1018
1019 }
1020
1021 fp_drop(p, fd, fp , 0);
1022 out1 :
1023 proc_dropref(p);
1024 out:
1025 return(error);
1026 }
1027
1028
1029 static int
1030 proc_security_policy(proc_t p)
1031 {
1032 if ((kauth_cred_getuid(p->p_ucred) != kauth_cred_getuid(kauth_cred_get()))
1033 && suser(kauth_cred_get(), (u_short *)0)) {
1034 return(EPERM);
1035 }
1036
1037 return(0);
1038 }
1039
1040
1041 /* Temporary hack to get dmesg to work. In Leopard this will disappear */
1042 int
1043 proc_kernmsgbuf(user_addr_t buffer, uint32_t buffersize, register_t * retval)
1044 {
1045 int error;
1046
1047 if (buffersize < sizeof(struct msgbuf))
1048 return(ENOMEM);
1049
1050 if (suser(kauth_cred_get(), (u_short *)0) == 0) {
1051 error = copyout(msgbufp, buffer, sizeof(struct msgbuf));
1052 if (error == 0)
1053 *retval = sizeof(struct msgbuf);
1054 return(error);
1055 } else
1056 return(EPERM);
1057 }
1058