1/*
2 * Copyright (c) 2005 Apple Computer, 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
52#include <bsm/audit_kernel.h>
53
54#include <mach/machine.h>
55#include <mach/mach_types.h>
56#include <mach/vm_param.h>
57#include <kern/task.h>
58#include <kern/lock.h>
59#include <kern/kalloc.h>
60#include <vm/vm_kern.h>
61#include <vm/vm_map.h>
62#include <mach/host_info.h>
63#include <mach/task_info.h>
64#include <mach/thread_info.h>
65#include <mach/vm_region.h>
66
67#include <sys/mount_internal.h>
68#include <sys/proc_info.h>
69#include <sys/bsdtask_info.h>
70#include <sys/kdebug.h>
71#include <sys/sysproto.h>
72#include <sys/msgbuf.h>
73
74#include <sys/msgbuf.h>
75
76#include <machine/machine_routines.h>
77
78#include <vm/vm_protos.h>
79
80struct pshmnode;
81struct psemnode;
82struct pipe;
83struct kqueue;
84struct atalk;
85
86int proc_info_internal(int callnum, int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t * retval);
87
88/* protos for proc_info calls */
89int proc_listpids(uint32_t type, uint32_t tyoneinfo, user_addr_t buffer, uint32_t buffersize, register_t * retval);
90int proc_pidinfo(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t * retval);
91int proc_pidfdinfo(int pid, int flavor,int fd, user_addr_t buffer, uint32_t buffersize, register_t * retval);
92int proc_kernmsgbuf(user_addr_t buffer, uint32_t buffersize, register_t * retval);
93
94/* protos for procpidinfo calls */
95int proc_pidfdlist(proc_t p, user_addr_t buffer, uint32_t buffersize, register_t *retval);
96int proc_pidbsdinfo(proc_t p, struct proc_bsdinfo *pbsd);
97int proc_pidtaskinfo(proc_t p, struct proc_taskinfo *ptinfo);
98int proc_pidallinfo(proc_t p, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t *retval);
99int proc_pidthreadinfo(proc_t p, uint64_t arg,  struct proc_threadinfo *pthinfo);
100int proc_pidthreadpathinfo(proc_t p, uint64_t arg,  struct proc_threadwithpathinfo *pinfo);
101int proc_pidlistthreads(proc_t p,  user_addr_t buffer, uint32_t buffersize, register_t *retval);
102int proc_pidregioninfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t *retval);
103int proc_pidregionpathinfo(proc_t p,  uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t *retval);
104int proc_pidvnodepathinfo(proc_t p,  uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t *retval);
105int proc_pidpathinfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, register_t *retval);
106
107
108/* protos for proc_pidfdinfo calls */
109int pid_vnodeinfo(vnode_t vp, uint32_t vid, struct fileproc * fp, int closeonexec, user_addr_t  buffer, uint32_t buffersize, register_t * retval);
110int pid_vnodeinfopath(vnode_t vp, uint32_t vid, struct fileproc * fp, int closeonexec, user_addr_t  buffer, uint32_t buffersize, register_t * retval);
111int pid_socketinfo(socket_t  so, struct fileproc *fp, int closeonexec, user_addr_t  buffer, uint32_t buffersize, register_t * retval);
112int pid_pseminfo(struct psemnode * psem, struct fileproc * fp,  int closeonexec, user_addr_t  buffer, uint32_t buffersize, register_t * retval);
113int pid_pshminfo(struct pshmnode * pshm, struct fileproc * fp,  int closeonexec, user_addr_t  buffer, uint32_t buffersize, register_t * retval);
114int pid_pipeinfo(struct pipe * p, struct fileproc * fp,  int closeonexec, user_addr_t  buffer, uint32_t buffersize, register_t * retval);
115int pid_kqueueinfo(struct kqueue * kq, struct fileproc * fp,  int closeonexec, user_addr_t  buffer, uint32_t buffersize, register_t * retval);
116int pid_atalkinfo(struct atalk  * at, struct fileproc * fp,  int closeonexec, user_addr_t  buffer, uint32_t buffersize, register_t * retval);
117
118
119/* protos for misc */
120
121int fill_vnodeinfo(vnode_t vp, struct vnode_info *vinfo);
122void  fill_fileinfo(struct fileproc * fp, int closeonexec, struct proc_fileinfo * finfo);
123static int proc_security_policy(proc_t p);
124static void munge_vinfo_stat(struct stat64 *sbp, struct vinfo_stat *vsbp);
125
126/***************************** proc_info ********************/
127
128int
129proc_info(__unused struct proc *p, struct proc_info_args * uap, register_t *retval)
130{
131	return(proc_info_internal(uap->callnum, uap->pid, uap->flavor, uap->arg, uap->buffer, uap->buffersize, retval));
132}
133
134
135int
136proc_info_internal(int callnum, int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t  buffersize, register_t * retval)
137{
138
139	switch(callnum) {
140		case 1: /* proc_listpids */
141			/* pid contains type and flavor contains typeinfo */
142			return(proc_listpids(pid, flavor, buffer, buffersize, retval));
143		case 2: /* proc_pidinfo */
144			return(proc_pidinfo(pid, flavor, arg, buffer, buffersize, retval));
145		case 3: /* proc_pidfdinfo */
146			return(proc_pidfdinfo(pid, flavor, (int)arg, buffer, buffersize, retval));
147		case 4: /* proc_kernmsgbuf */
148			return(proc_kernmsgbuf(buffer, buffersize, retval));
149		default:
150				return(EINVAL);
151	}
152
153	return(EINVAL);
154}
155
156/******************* proc_listpids routine ****************/
157int
158proc_listpids(uint32_t type, uint32_t typeinfo, user_addr_t buffer, uint32_t  buffersize, register_t * retval)
159{
160	int numprocs, wantpids;
161	char * kbuf;
162	int * ptr;
163	int n, skip;
164	struct proc * p;
165	int error = 0;
166
167	/* if the buffer is null, return num of procs */
168	if (buffer == (user_addr_t)0) {
169		*retval = ((nprocs+20) * sizeof(int));
170		return(0);
171	}
172
173	if (buffersize < sizeof(int)) {
174		return(ENOMEM);
175	}
176	wantpids = buffersize/sizeof(int);
177	numprocs = nprocs+20;
178	if (numprocs > wantpids)
179		numprocs = wantpids;
180
181	kbuf = (char *)kalloc((vm_size_t)(numprocs * sizeof(int)));
182	if (kbuf == NULL)
183		return(ENOMEM);
184	bzero(kbuf, sizeof(int));
185
186	proc_list_lock();
187
188
189	n = 0;
190	ptr = (int *)kbuf;
191	LIST_FOREACH(p, &allproc, p_list) {
192		skip = 0;
193		switch (type) {
194			case PROC_PGRP_ONLY:
195				if (p->p_pgrpid != (pid_t)typeinfo)
196					skip = 1;
197			  	break;
198			case PROC_ALL_PIDS:
199				skip = 0;
200			  	break;
201			case PROC_TTY_ONLY:
202				/* racy but list lock is held */
203				if ((p->p_flag & P_CONTROLT) == 0 ||
204					(p->p_pgrp == NULL) || (p->p_pgrp->pg_session == NULL) ||
205			    	p->p_pgrp->pg_session->s_ttyp == NULL ||
206			    	p->p_pgrp->pg_session->s_ttyp->t_dev != (dev_t)typeinfo)
207					skip = 1;
208			  	break;
209			case PROC_UID_ONLY:
210				if (p->p_ucred == NULL)
211					skip = 1;
212				else {
213					kauth_cred_t my_cred;
214					uid_t uid;
215
216					my_cred = kauth_cred_proc_ref(p);
217					uid = kauth_cred_getuid(my_cred);
218					kauth_cred_unref(&my_cred);
219					if (uid != (uid_t)typeinfo)
220						skip = 1;
221				}
222			  	break;
223			case PROC_RUID_ONLY:
224				if (p->p_ucred == NULL)
225					skip = 1;
226				else {
227					kauth_cred_t my_cred;
228					uid_t uid;
229
230					my_cred = kauth_cred_proc_ref(p);
231					uid = my_cred->cr_ruid;
232					kauth_cred_unref(&my_cred);
233					if (uid != (uid_t)typeinfo)
234						skip = 1;
235				}
236			  	break;
237			default:
238			  skip = 1;
239			  break;
240		};
241
242		/* Do we have permission to look into this ? */
243		if (proc_security_policy(p) != 0) {
244			skip = 1;
245		}
246
247		if(skip == 0) {
248			*ptr++ = p->p_pid;
249			n++;
250		}
251		if (n >= numprocs)
252			break;
253	}
254
255	if (n < numprocs) {
256		LIST_FOREACH(p, &zombproc, p_list) {
257			*ptr++ = p->p_pid;
258			n++;
259			if (n >= numprocs)
260				break;
261		}
262	}
263
264
265	proc_list_unlock();
266
267	ptr = (int *)kbuf;
268	error = copyout((caddr_t)ptr, buffer, n * sizeof(int));
269	if (error == 0)
270		*retval = (n * sizeof(int));
271	kfree((void *)kbuf, (vm_size_t)(numprocs * sizeof(int)));
272
273	return(error);
274}
275
276
277/********************************** proc_pidinfo routines ********************************/
278
279int
280proc_pidfdlist(proc_t p, user_addr_t buffer, uint32_t  buffersize, register_t *retval)
281{
282		int numfds, needfds;
283		char * kbuf;
284		struct proc_fdinfo * pfd;
285		struct fileproc * fp;
286		int n;
287		int count = 0;
288		int error = 0;
289
290	 	numfds = p->p_fd->fd_nfiles;
291
292		if (buffer == (user_addr_t) 0) {
293			numfds += 20;
294			*retval = (numfds * sizeof(struct proc_fdinfo));
295			return(0);
296		}
297
298		/* buffersize is big enough atleast for one struct */
299		needfds = buffersize/sizeof(struct proc_fdinfo);
300
301		if (numfds > needfds)
302			numfds = needfds;
303
304		kbuf = (char *)kalloc((vm_size_t)(numfds * sizeof(struct proc_fdinfo)));
305		if (kbuf == NULL)
306			return(ENOMEM);
307		bzero(kbuf, numfds * sizeof(struct proc_fdinfo));
308
309		proc_fdlock(p);
310
311		pfd = (struct proc_fdinfo *)kbuf;
312
313		for (n = 0; ((n < numfds) && (n < p->p_fd->fd_nfiles)); n++) {
314			if (((fp = p->p_fd->fd_ofiles[n]) != 0)
315			     && ((p->p_fd->fd_ofileflags[n] & UF_RESERVED) == 0)) {
316				pfd->proc_fd = n;
317				pfd->proc_fdtype = fp->f_fglob->fg_type;
318				count++;
319				pfd++;
320			}
321		}
322		proc_fdunlock(p);
323
324		error = copyout(kbuf, buffer, count * sizeof(struct proc_fdinfo));
325		kfree((void *)kbuf, (vm_size_t)(numfds * sizeof(struct proc_fdinfo)));
326		if (error == 0)
327			*retval = (count * sizeof(struct proc_fdinfo));
328		return(error);
329}
330
331
332int
333proc_pidbsdinfo(proc_t p, struct proc_bsdinfo * pbsd)
334{
335	register struct tty *tp;
336	struct  session *sessionp = NULL;
337	struct pgrp * pg;
338	kauth_cred_t my_cred;
339
340	pg = proc_pgrp(p);
341	sessionp = proc_session(p);
342
343	my_cred = kauth_cred_proc_ref(p);
344	bzero(pbsd, sizeof(struct proc_bsdinfo));
345	pbsd->pbi_status = p->p_stat;
346	pbsd->pbi_xstatus = p->p_xstat;
347	pbsd->pbi_pid = p->p_pid;
348	pbsd->pbi_ppid = p->p_ppid;
349	pbsd->pbi_uid = my_cred->cr_uid;
350	pbsd->pbi_gid = my_cred->cr_gid;
351	pbsd->pbi_ruid =  my_cred->cr_ruid;
352	pbsd->pbi_rgid = my_cred->cr_rgid;
353	pbsd->pbi_svuid =  my_cred->cr_svuid;
354	pbsd->pbi_svgid = my_cred->cr_svgid;
355	kauth_cred_unref(&my_cred);
356
357	pbsd->pbi_nice = p->p_nice;
358	pbsd->pbi_start = p->p_start;
359	bcopy(&p->p_comm, &pbsd->pbi_comm[0], MAXCOMLEN);
360	bcopy(&p->p_name, &pbsd->pbi_name[0], 2* MAXCOMLEN);
361
362	pbsd->pbi_flags = 0;
363	if ((p->p_flag & P_SYSTEM) == P_SYSTEM)
364		pbsd->pbi_flags |= PROC_FLAG_SYSTEM;
365	if ((p->p_lflag & P_LTRACED) == P_LTRACED)
366		pbsd->pbi_flags |= PROC_FLAG_TRACED;
367	if ((p->p_lflag & P_LEXIT) == P_LEXIT)
368		pbsd->pbi_flags |= PROC_FLAG_INEXIT;
369	if ((p->p_lflag & P_LPPWAIT) == P_LPPWAIT)
370		pbsd->pbi_flags |= PROC_FLAG_PPWAIT;
371	if ((p->p_flag & P_LP64) == P_LP64)
372		pbsd->pbi_flags |= PROC_FLAG_LP64;
373	if ((p->p_flag & P_CONTROLT) == P_CONTROLT)
374		pbsd->pbi_flags |= PROC_FLAG_CONTROLT;
375	if ((p->p_flag & P_THCWD) == P_THCWD)
376		pbsd->pbi_flags |= PROC_FLAG_THCWD;
377
378	if (SESS_LEADER(p, sessionp))
379		pbsd->pbi_flags |= PROC_FLAG_SLEADER;
380	if ((sessionp != SESSION_NULL) && sessionp->s_ttyvp)
381		pbsd->pbi_flags |= PROC_FLAG_CTTY;
382
383	pbsd->pbi_nfiles = p->p_fd->fd_nfiles;
384	if (pg != PGRP_NULL) {
385		pbsd->pbi_pgid = p->p_pgrpid;
386		pbsd->pbi_pjobc = pg->pg_jobc;
387		if ((p->p_flag & P_CONTROLT) && (sessionp != SESSION_NULL) && (tp = sessionp->s_ttyp)) {
388			pbsd->e_tdev = tp->t_dev;
389			pbsd->e_tpgid = sessionp->s_ttypgrpid;
390		}
391	}
392	if (sessionp != SESSION_NULL)
393		session_rele(sessionp);
394	if (pg != PGRP_NULL)
395		pg_rele(pg);
396
397	return(0);
398}
399
400
401int
402proc_pidtaskinfo(proc_t p, struct proc_taskinfo * ptinfo)
403{
404	task_t task;
405
406	task = p->task;
407
408	bzero(ptinfo, sizeof(struct proc_taskinfo));
409	fill_taskprocinfo(task, (struct proc_taskinfo_internal *)ptinfo);
410
411	return(0);
412}
413
414
415
416int
417proc_pidthreadinfo(proc_t p, uint64_t arg,  struct proc_threadinfo *pthinfo)
418{
419	int error = 0;
420	uint64_t threadaddr = (uint64_t)arg;
421
422	bzero(pthinfo, sizeof(struct proc_threadinfo));
423
424	error = fill_taskthreadinfo(p->task, threadaddr, (struct proc_threadinfo_internal *)pthinfo, NULL, NULL);
425	if (error)
426		return(ESRCH);
427	else
428		return(0);
429
430}
431
432
433void
434bsd_threadcdir(void * uth, void *vptr, int *vidp)
435{
436	struct uthread * ut = (struct uthread *)uth;
437	vnode_t vp;
438	vnode_t *vpp = (vnode_t *)vptr;
439
440	vp = ut->uu_cdir;
441	if (vp  != NULLVP) {
442		if (vpp != NULL) {
443			*vpp = vp;
444			if (vidp != NULL)
445				*vidp = vp->v_id;
446		}
447	}
448}
449
450
451int
452proc_pidthreadpathinfo(proc_t p, uint64_t arg,  struct proc_threadwithpathinfo *pinfo)
453{
454	vnode_t vp = NULLVP;
455	int vid;
456	int error = 0;
457	uint64_t threadaddr = (uint64_t)arg;
458	int count;
459
460	bzero(pinfo, sizeof(struct proc_threadwithpathinfo));
461
462	error = fill_taskthreadinfo(p->task, threadaddr, (struct proc_threadinfo_internal *)&pinfo->pt, (void *)&vp, &vid);
463	if (error)
464		return(ESRCH);
465
466	if ((vp != NULLVP) && ((vnode_getwithvid(vp, vid)) == 0)) {
467		error = fill_vnodeinfo(vp, &pinfo->pvip.vip_vi) ;
468		if (error == 0) {
469			count = MAXPATHLEN;
470			vn_getpath(vp, &pinfo->pvip.vip_path[0], &count);
471			pinfo->pvip.vip_path[MAXPATHLEN-1] = 0;
472		}
473		vnode_put(vp);
474	}
475	return(error);
476}
477
478
479
480int
481proc_pidlistthreads(proc_t p,  user_addr_t buffer, uint32_t  buffersize, register_t *retval)
482{
483	int count = 0;
484	int ret = 0;
485	int error = 0;
486	void * kbuf;
487	int numthreads;
488
489
490	count = buffersize/(sizeof(uint64_t));
491	numthreads = get_numthreads(p->task);
492
493	numthreads += 10;
494
495	if (numthreads > count)
496		numthreads = count;
497
498	kbuf = (void *)kalloc(numthreads * sizeof(uint64_t));
499	if (kbuf == NULL)
500		return(ENOMEM);
501	bzero(kbuf, numthreads * sizeof(uint64_t));
502
503	ret = fill_taskthreadlist(p->task, kbuf, numthreads);
504
505	error = copyout(kbuf, buffer, ret);
506	kfree(kbuf, numthreads * sizeof(uint64_t));
507	if (error == 0)
508		*retval = ret;
509	return(error);
510
511}
512
513
514int
515proc_pidregioninfo(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t  buffersize, register_t *retval)
516{
517	struct proc_regioninfo preginfo;
518	int ret, error = 0;
519
520	bzero(&preginfo, sizeof(struct proc_regioninfo));
521	ret = fill_procregioninfo( p->task, arg, (struct proc_regioninfo_internal *)&preginfo, (uint32_t *)0, (uint32_t *)0);
522	if (ret == 0)
523		return(EINVAL);
524	error = copyout(&preginfo, buffer, sizeof(struct proc_regioninfo));
525	if (error == 0)
526		*retval = sizeof(struct proc_regioninfo);
527	return(error);
528}
529
530
531int
532proc_pidregionpathinfo(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t  buffersize, register_t *retval)
533{
534	struct proc_regionwithpathinfo preginfo;
535	int ret, error = 0;
536	uint32_t vnodeaddr= 0;
537	uint32_t vnodeid= 0;
538	vnode_t vp;
539	int count;
540
541	bzero(&preginfo, sizeof(struct proc_regionwithpathinfo));
542
543	ret = fill_procregioninfo( p->task, arg, (struct proc_regioninfo_internal *)&preginfo.prp_prinfo, (uint32_t *)&vnodeaddr, (uint32_t *)&vnodeid);
544	if (ret == 0)
545		return(EINVAL);
546	if (vnodeaddr) {
547		vp = (vnode_t)vnodeaddr;
548		if ((vnode_getwithvid(vp, vnodeid)) == 0) {
549			/* FILL THE VNODEINFO */
550			error = fill_vnodeinfo(vp, &preginfo.prp_vip.vip_vi);
551			count = MAXPATHLEN;
552			vn_getpath(vp, &preginfo.prp_vip.vip_path[0], &count);
553			/* Always make sure it is null terminated */
554			preginfo.prp_vip.vip_path[MAXPATHLEN-1] = 0;
555			vnode_put(vp);
556		}
557	}
558	error = copyout(&preginfo, buffer, sizeof(struct proc_regionwithpathinfo));
559	if (error == 0)
560		*retval = sizeof(struct proc_regionwithpathinfo);
561	return(error);
562}
563
564/*
565 * Path is relative to current process directory; may different from current
566 * thread directory.
567 */
568int
569proc_pidvnodepathinfo(proc_t p, __unused uint64_t arg, user_addr_t buffer, __unused uint32_t  buffersize, register_t *retval)
570{
571	struct proc_vnodepathinfo pvninfo;
572	int error = 0;
573	vnode_t vncdirvp = NULLVP;
574	uint32_t vncdirid=0;
575	vnode_t vnrdirvp = NULLVP;
576	uint32_t vnrdirid=0;
577	int count;
578
579	bzero(&pvninfo, sizeof(struct proc_vnodepathinfo));
580
581	proc_fdlock(p);
582	if (p->p_fd->fd_cdir) {
583		vncdirvp = p->p_fd->fd_cdir;
584		vncdirid = p->p_fd->fd_cdir->v_id;
585	}
586	if (p->p_fd->fd_rdir) {
587		vnrdirvp = p->p_fd->fd_rdir;
588		vnrdirid = p->p_fd->fd_rdir->v_id;
589	}
590	proc_fdunlock(p);
591
592	if (vncdirvp != NULLVP) {
593		if ((error = vnode_getwithvid(vncdirvp, vncdirid)) == 0) {
594			/* FILL THE VNODEINFO */
595			error = fill_vnodeinfo(vncdirvp, &pvninfo.pvi_cdir.vip_vi);
596			if ( error == 0) {
597				count = MAXPATHLEN;
598				vn_getpath(vncdirvp, &pvninfo.pvi_cdir.vip_path[0], &count);
599				pvninfo.pvi_cdir.vip_path[MAXPATHLEN-1] = 0;
600			}
601			vnode_put(vncdirvp);
602		} else {
603			goto out;
604		}
605	}
606
607	if ((error == 0) && (vnrdirvp != NULLVP)) {
608		if ((error = vnode_getwithvid(vnrdirvp, vnrdirid)) == 0) {
609			/* FILL THE VNODEINFO */
610			error = fill_vnodeinfo(vnrdirvp, &pvninfo.pvi_rdir.vip_vi);
611			if ( error == 0) {
612				count = MAXPATHLEN;
613				vn_getpath(vnrdirvp, &pvninfo.pvi_rdir.vip_path[0], &count);
614				pvninfo.pvi_rdir.vip_path[MAXPATHLEN-1] = 0;
615			}
616			vnode_put(vnrdirvp);
617		} else {
618			goto out;
619		}
620	}
621	if (error == 0) {
622		error = copyout(&pvninfo, buffer, sizeof(struct proc_vnodepathinfo));
623		if (error == 0)
624			*retval = sizeof(struct proc_vnodepathinfo);
625	}
626out:
627	return(error);
628}
629
630int
631proc_pidpathinfo(proc_t p, __unused uint64_t arg, user_addr_t buffer, uint32_t buffersize, __unused register_t *retval)
632{
633	int vid, error;
634	vnode_t tvp;
635	vnode_t nvp = NULLVP;
636	int len = buffersize;
637	char * buf;
638
639	tvp = p->p_textvp;
640
641	if (tvp == NULLVP)
642		return(ESRCH);
643
644	buf = (char *)kalloc(buffersize);
645	if (buf == NULL)
646		return(ENOMEM);
647
648
649	vid = vnode_vid(tvp);
650	error = vnode_getwithvid(tvp, vid);
651	if (error == 0) {
652		error = vn_getpath(tvp, buf, &len);
653		vnode_put(tvp);
654		if (error == 0) {
655			error = vnode_lookup(buf, 0, &nvp, vfs_context_current());
656			if ((error == 0) && ( nvp != NULLVP))
657				vnode_put(nvp);
658			if (error == 0) {
659				error = copyout(buf, buffer, len);
660			}
661		}
662	}
663	kfree(buf, buffersize);
664	return(error);
665}
666
667
668/********************************** proc_pidinfo ********************************/
669
670
671int
672proc_pidinfo(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t  buffersize, register_t * retval)
673{
674	struct proc * p = PROC_NULL;
675	int error = ENOTSUP;
676	int gotref = 0;
677	int findzomb = 0;
678	int refheld = 0;
679	uint32_t size;
680
681	switch (flavor) {
682		case PROC_PIDLISTFDS:
683			size = PROC_PIDLISTFD_SIZE;
684			if (buffer == (user_addr_t)0)
685				size = 0;
686			break;
687		case PROC_PIDTBSDINFO:
688			size = PROC_PIDTBSDINFO_SIZE;
689			break;
690		case PROC_PIDTASKINFO:
691			size = PROC_PIDTASKINFO_SIZE;
692			break;
693		case PROC_PIDTASKALLINFO:
694			size = PROC_PIDTASKALLINFO_SIZE;
695			break;
696		case PROC_PIDTHREADINFO:
697			size = PROC_PIDTHREADINFO_SIZE;
698			break;
699		case PROC_PIDLISTTHREADS:
700			size = PROC_PIDLISTTHREADS_SIZE;
701			break;
702		case PROC_PIDREGIONINFO:
703			size = PROC_PIDREGIONINFO_SIZE;
704			break;
705		case PROC_PIDREGIONPATHINFO:
706			size = PROC_PIDREGIONPATHINFO_SIZE;
707			break;
708		case PROC_PIDVNODEPATHINFO:
709			size = PROC_PIDVNODEPATHINFO_SIZE;
710			break;
711		case PROC_PIDTHREADPATHINFO:
712			size = PROC_PIDTHREADPATHINFO_SIZE;
713			break;
714		case PROC_PIDPATHINFO:
715			size = MAXPATHLEN;
716			break;
717		default:
718			return(EINVAL);
719	}
720
721	if (buffersize < size)
722		return(ENOMEM);
723
724	if ((flavor == PROC_PIDPATHINFO) && (buffersize > PROC_PIDPATHINFO_MAXSIZE)) {
725		return(EOVERFLOW);
726	}
727
728	if ((flavor != PROC_PIDTBSDINFO) && (flavor != PROC_PIDPATHINFO)) {
729		if ((p = proc_find(pid)) == PROC_NULL) {
730				error = ESRCH;
731				goto out;
732			} else {
733				gotref = 1;
734
735				/* Do we have permission to look into this ? */
736				if ((error = proc_security_policy(p)) != 0) {
737					goto out;
738				}
739			}
740	}
741	switch (flavor) {
742		case PROC_PIDLISTFDS: {
743			error = proc_pidfdlist(p, buffer, buffersize, retval);
744		}
745		break;
746
747		case PROC_PIDTBSDINFO: {
748			struct proc_bsdinfo pbsd;
749
750			if (arg)
751				findzomb = 1;
752			p = proc_find(pid);
753			if (p == PROC_NULL) {
754				if (findzomb)
755					p = pzfind(pid);
756				if (p == NULL) {
757					error = ESRCH;
758					goto out;
759				}
760			} else
761				refheld = 1;
762			/* Do we have permission to look into this ? */
763			if ((error = proc_security_policy(p)) != 0) {
764				if (refheld != 0)
765					proc_rele(p);
766				goto out;
767			}
768			error = proc_pidbsdinfo(p, &pbsd);
769			if (refheld != 0)
770				proc_rele(p);
771			if (error == 0) {
772				error = copyout(&pbsd, buffer, sizeof(struct proc_bsdinfo));
773				if (error == 0)
774					*retval = sizeof(struct proc_bsdinfo);
775			}
776		}
777		break;
778
779		case PROC_PIDTASKINFO: {
780			struct proc_taskinfo ptinfo;
781
782			error =  proc_pidtaskinfo(p, &ptinfo);
783			if (error == 0) {
784				error = copyout(&ptinfo, buffer, sizeof(struct proc_taskinfo));
785				if (error == 0)
786					*retval = sizeof(struct proc_taskinfo);
787			}
788		}
789		break;
790
791		case PROC_PIDTASKALLINFO: {
792		struct proc_taskallinfo pall;
793
794			error = proc_pidbsdinfo(p, &pall.pbsd);
795			error =  proc_pidtaskinfo(p, &pall.ptinfo);
796			if (error == 0) {
797				error = copyout(&pall, buffer, sizeof(struct proc_taskallinfo));
798				if (error == 0)
799					*retval = sizeof(struct proc_taskallinfo);
800			}
801		}
802		break;
803
804		case PROC_PIDTHREADINFO:{
805		struct proc_threadinfo pthinfo;
806
807			error  = proc_pidthreadinfo(p,  arg, &pthinfo);
808			if (error == 0) {
809				error = copyout(&pthinfo, buffer, sizeof(struct proc_threadinfo));
810				if (error == 0)
811					*retval = sizeof(struct proc_threadinfo);
812			}
813		}
814		break;
815
816		case PROC_PIDLISTTHREADS:{
817			error =  proc_pidlistthreads(p,  buffer, buffersize, retval);
818		}
819		break;
820
821		case PROC_PIDREGIONINFO:{
822			error =  proc_pidregioninfo(p,  arg, buffer, buffersize, retval);
823		}
824		break;
825
826
827		case PROC_PIDREGIONPATHINFO:{
828			error =  proc_pidregionpathinfo(p, arg, buffer, buffersize, retval);
829		}
830		break;
831
832		case PROC_PIDVNODEPATHINFO:{
833			error =  proc_pidvnodepathinfo(p, arg, buffer, buffersize, retval);
834		}
835		break;
836
837
838		case PROC_PIDTHREADPATHINFO:{
839		struct proc_threadwithpathinfo pinfo;
840
841			error  = proc_pidthreadpathinfo(p,  arg, &pinfo);
842			if (error == 0) {
843				error = copyout((caddr_t)&pinfo, buffer, sizeof(struct proc_threadwithpathinfo));
844				if (error == 0)
845						*retval = sizeof(struct proc_threadwithpathinfo);
846			}
847		}
848		break;
849
850		case PROC_PIDPATHINFO: {
851			p = proc_find(pid);
852			if (p == PROC_NULL) {
853				error = ESRCH;
854				goto out;
855			}
856			gotref = 1;
857			error =  proc_pidpathinfo(p, arg, buffer, buffersize, retval);
858		}
859		break;
860
861		default:
862			error = ENOTSUP;
863	}
864
865out:
866	if (gotref)
867		proc_rele(p);
868	return(error);
869}
870
871
872int
873pid_vnodeinfo(vnode_t vp, uint32_t vid, struct fileproc * fp, int closeonexec, user_addr_t  buffer, __unused uint32_t buffersize, register_t * retval)
874{
875	struct vnode_fdinfo vfi;
876	int error= 0;
877
878	if ((error = vnode_getwithvid(vp, vid)) != 0) {
879		return(error);
880	}
881	bzero(&vfi, sizeof(struct vnode_fdinfo));
882	fill_fileinfo(fp, closeonexec, &vfi.pfi);
883	error = fill_vnodeinfo(vp, &vfi.pvi);
884	vnode_put(vp);
885	if (error == 0) {
886		error = copyout((caddr_t)&vfi, buffer, sizeof(struct vnode_fdinfo));
887		if (error == 0)
888			*retval = sizeof(struct vnode_fdinfo);
889	}
890	return(error);
891}
892
893int
894pid_vnodeinfopath(vnode_t vp, uint32_t vid, struct fileproc * fp, int closeonexec, user_addr_t  buffer, __unused uint32_t buffersize, register_t * retval)
895{
896	struct vnode_fdinfowithpath vfip;
897	int count, error= 0;
898
899	if ((error = vnode_getwithvid(vp, vid)) != 0) {
900		return(error);
901	}
902	bzero(&vfip, sizeof(struct vnode_fdinfowithpath));
903	fill_fileinfo(fp, closeonexec, &vfip.pfi);
904	error = fill_vnodeinfo(vp, &vfip.pvip.vip_vi) ;
905	if (error == 0) {
906		count = MAXPATHLEN;
907		vn_getpath(vp, &vfip.pvip.vip_path[0], &count);
908		vfip.pvip.vip_path[MAXPATHLEN-1] = 0;
909		vnode_put(vp);
910		error = copyout((caddr_t)&vfip, buffer, sizeof(struct vnode_fdinfowithpath));
911		if (error == 0)
912			*retval = sizeof(struct vnode_fdinfowithpath);
913	} else
914		vnode_put(vp);
915	return(error);
916}
917
918void
919fill_fileinfo(struct fileproc * fp, int closeonexec, struct proc_fileinfo * fproc)
920{
921		fproc->fi_openflags = fp->f_fglob->fg_flag;
922		fproc->fi_status = 0;
923		fproc->fi_offset = fp->f_fglob->fg_offset;
924		fproc->fi_type = fp->f_fglob->fg_type;
925		if (fp->f_fglob->fg_count)
926			fproc->fi_status |= PROC_FP_SHARED;
927		if (closeonexec != 0)
928			fproc->fi_status |= PROC_FP_CLEXEC;
929}
930
931
932
933int
934fill_vnodeinfo(vnode_t vp, struct vnode_info *vinfo)
935{
936		vfs_context_t context;
937		struct stat64 sb;
938		int error = 0;
939
940		context = vfs_context_create((vfs_context_t)0);
941		error = vn_stat(vp, &sb, NULL, 1, context);
942		(void)vfs_context_rele(context);
943
944		munge_vinfo_stat(&sb, &vinfo->vi_stat);
945
946		if (error != 0)
947			goto out;
948
949		if (vp->v_mount != dead_mountp) {
950			vinfo->vi_fsid = vp->v_mount->mnt_vfsstat.f_fsid;
951		} else {
952			vinfo->vi_fsid.val[0] = 0;
953			vinfo->vi_fsid.val[1] = 0;
954		}
955		vinfo->vi_type = vp->v_type;
956out:
957		return(error);
958}
959
960int
961pid_socketinfo(socket_t so, struct fileproc *fp, int closeonexec, user_addr_t  buffer, __unused uint32_t buffersize, register_t * retval)
962{
963#if SOCKETS
964	struct socket_fdinfo s;
965	int error = 0;
966
967	bzero(&s, sizeof(struct socket_fdinfo));
968	fill_fileinfo(fp, closeonexec, &s.pfi);
969	if ((error = fill_socketinfo(so, &s.psi)) == 0) {
970		if ((error = copyout(&s, buffer, sizeof(struct socket_fdinfo))) == 0)
971				*retval = sizeof(struct socket_fdinfo);
972	}
973	return (error);
974#else
975	*retval = 0;
976	return (ENOTSUP);
977#endif
978}
979
980int
981pid_pseminfo(struct psemnode *psem, struct fileproc *fp,  int closeonexec, user_addr_t  buffer, __unused uint32_t buffersize, register_t * retval)
982{
983	struct psem_fdinfo pseminfo;
984	int error = 0;
985
986	bzero(&pseminfo, sizeof(struct psem_fdinfo));
987	fill_fileinfo(fp, closeonexec, &pseminfo.pfi);
988
989	if ((error = fill_pseminfo(psem, &pseminfo.pseminfo)) == 0) {
990		if ((error = copyout(&pseminfo, buffer, sizeof(struct psem_fdinfo))) == 0)
991				*retval = sizeof(struct psem_fdinfo);
992	}
993
994	return(error);
995}
996
997int
998pid_pshminfo(struct pshmnode *pshm, struct fileproc *fp,  int closeonexec, user_addr_t  buffer, __unused uint32_t buffersize, register_t * retval)
999{
1000	struct pshm_fdinfo pshminfo;
1001	int error = 0;
1002
1003	bzero(&pshminfo, sizeof(struct pshm_fdinfo));
1004	fill_fileinfo(fp, closeonexec, &pshminfo.pfi);
1005
1006	if ((error = fill_pshminfo(pshm, &pshminfo.pshminfo)) == 0) {
1007		if ((error = copyout(&pshminfo, buffer, sizeof(struct pshm_fdinfo))) == 0)
1008				*retval = sizeof(struct pshm_fdinfo);
1009	}
1010
1011	return(error);
1012}
1013
1014int
1015pid_pipeinfo(struct pipe *  p, struct fileproc *fp,  int closeonexec, user_addr_t  buffer, __unused uint32_t buffersize, register_t * retval)
1016{
1017	struct pipe_fdinfo pipeinfo;
1018	int error = 0;
1019
1020	bzero(&pipeinfo, sizeof(struct pipe_fdinfo));
1021	fill_fileinfo(fp, closeonexec, &pipeinfo.pfi);
1022	if ((error = fill_pipeinfo(p, &pipeinfo.pipeinfo)) == 0) {
1023		if ((error = copyout(&pipeinfo, buffer, sizeof(struct pipe_fdinfo))) == 0)
1024				*retval = sizeof(struct pipe_fdinfo);
1025	}
1026
1027	return(error);
1028}
1029
1030int
1031pid_kqueueinfo(struct kqueue * kq, struct fileproc *fp,  int closeonexec, user_addr_t  buffer, __unused uint32_t buffersize, register_t * retval)
1032{
1033	struct kqueue_fdinfo kqinfo;
1034	int error = 0;
1035
1036	bzero(&kqinfo, sizeof(struct kqueue_fdinfo));
1037
1038	fill_fileinfo(fp, closeonexec, &kqinfo.pfi);
1039
1040	if ((error = fill_kqueueinfo(kq, &kqinfo.kqueueinfo)) == 0) {
1041		if ((error = copyout(&kqinfo, buffer, sizeof(struct kqueue_fdinfo))) == 0)
1042				*retval = sizeof(struct kqueue_fdinfo);
1043	}
1044
1045	return(error);
1046}
1047
1048int
1049pid_atalkinfo(__unused struct atalk * at, __unused struct fileproc *fp,  __unused int closeonexec, __unused user_addr_t  buffer, __unused uint32_t buffersize, __unused register_t * retval)
1050{
1051	return ENOTSUP;
1052}
1053
1054
1055
1056/************************** proc_pidfdinfo routine ***************************/
1057int
1058proc_pidfdinfo(int pid, int flavor,  int fd, user_addr_t buffer, uint32_t buffersize, register_t * retval)
1059{
1060	proc_t p;
1061	int error = ENOTSUP;
1062	struct fileproc * fp;
1063	uint32_t size;
1064	int closeonexec = 0;
1065
1066	switch (flavor) {
1067		case PROC_PIDFDVNODEINFO:
1068			size = PROC_PIDFDVNODEINFO_SIZE;
1069			break;
1070		case PROC_PIDFDVNODEPATHINFO:
1071			size = PROC_PIDFDVNODEPATHINFO_SIZE;
1072			break;
1073		case PROC_PIDFDSOCKETINFO:
1074			size = PROC_PIDFDSOCKETINFO_SIZE;
1075			break;
1076		case PROC_PIDFDPSEMINFO:
1077			size = PROC_PIDFDPSEMINFO_SIZE;
1078			break;
1079		case PROC_PIDFDPSHMINFO:
1080			size = PROC_PIDFDPSHMINFO_SIZE;
1081			break;
1082		case PROC_PIDFDPIPEINFO:
1083			size = PROC_PIDFDPIPEINFO_SIZE;
1084			break;
1085		case PROC_PIDFDKQUEUEINFO:
1086			size = PROC_PIDFDKQUEUEINFO_SIZE;
1087			break;
1088		case PROC_PIDFDATALKINFO:
1089			size = PROC_PIDFDATALKINFO_SIZE;
1090			break;
1091
1092		default:
1093			return(EINVAL);
1094
1095	}
1096
1097	if (buffersize < size)
1098		return(ENOMEM);
1099
1100	if ((p = proc_find(pid)) == PROC_NULL) {
1101		error = ESRCH;
1102		goto out;
1103	}
1104	/* Do we have permission to look into this ? */
1105	if ((error = proc_security_policy(p)) != 0) {
1106		goto out1;
1107	}
1108
1109	switch (flavor) {
1110		case PROC_PIDFDVNODEINFO: {
1111			vnode_t vp;
1112			uint32_t vid=0;
1113
1114			if ((error = fp_getfvpandvid(p, fd, &fp,  &vp, &vid)) !=0) {
1115				goto out1;
1116			}
1117			/* no need to be under the fdlock */
1118			closeonexec = p->p_fd->fd_ofileflags[fd] & UF_EXCLOSE;
1119			error =  pid_vnodeinfo(vp, vid, fp, closeonexec, buffer, buffersize, retval);
1120		}
1121		break;
1122
1123		case PROC_PIDFDVNODEPATHINFO: {
1124			vnode_t vp;
1125			uint32_t vid=0;
1126
1127			if ((error = fp_getfvpandvid(p, fd, &fp,  &vp, &vid)) !=0) {
1128				goto out1;
1129			}
1130
1131			/* no need to be under the fdlock */
1132			closeonexec = p->p_fd->fd_ofileflags[fd] & UF_EXCLOSE;
1133			error =  pid_vnodeinfopath(vp, vid, fp, closeonexec, buffer, buffersize, retval);
1134		}
1135		break;
1136
1137		case PROC_PIDFDSOCKETINFO: {
1138			socket_t so;
1139
1140			if ((error = fp_getfsock(p, fd, &fp,  &so)) !=0) {
1141				goto out1;
1142			}
1143			/* no need to be under the fdlock */
1144			closeonexec = p->p_fd->fd_ofileflags[fd] & UF_EXCLOSE;
1145			error =  pid_socketinfo(so, fp, closeonexec, buffer, buffersize, retval);
1146		}
1147		break;
1148
1149		case PROC_PIDFDPSEMINFO: {
1150			struct psemnode * psem;
1151
1152			if ((error = fp_getfpsem(p, fd, &fp,  &psem)) !=0) {
1153				goto out1;
1154			}
1155			/* no need to be under the fdlock */
1156			closeonexec = p->p_fd->fd_ofileflags[fd] & UF_EXCLOSE;
1157			error =  pid_pseminfo(psem, fp, closeonexec, buffer, buffersize, retval);
1158		}
1159		break;
1160
1161		case PROC_PIDFDPSHMINFO: {
1162			struct pshmnode * pshm;
1163
1164			if ((error = fp_getfpshm(p, fd, &fp,  &pshm)) !=0) {
1165				goto out1;
1166			}
1167			/* no need to be under the fdlock */
1168			closeonexec = p->p_fd->fd_ofileflags[fd] & UF_EXCLOSE;
1169			error =  pid_pshminfo(pshm, fp, closeonexec, buffer, buffersize, retval);
1170		}
1171		break;
1172
1173		case PROC_PIDFDPIPEINFO: {
1174			struct pipe * cpipe;
1175
1176			if ((error = fp_getfpipe(p, fd, &fp,  &cpipe)) !=0) {
1177				goto out1;
1178			}
1179			/* no need to be under the fdlock */
1180			closeonexec = p->p_fd->fd_ofileflags[fd] & UF_EXCLOSE;
1181			error =  pid_pipeinfo(cpipe, fp, closeonexec, buffer, buffersize, retval);
1182		}
1183		break;
1184
1185		case PROC_PIDFDKQUEUEINFO: {
1186			struct kqueue * kq;
1187
1188			if ((error = fp_getfkq(p, fd, &fp,  &kq)) !=0) {
1189				goto out1;
1190			}
1191			/* no need to be under the fdlock */
1192			closeonexec = p->p_fd->fd_ofileflags[fd] & UF_EXCLOSE;
1193			error =  pid_kqueueinfo(kq, fp, closeonexec, buffer, buffersize, retval);
1194		}
1195		break;
1196
1197		case PROC_PIDFDATALKINFO: {
1198			struct atalk * at;
1199
1200			if ((error = fp_getfatalk(p, fd, &fp,  &at)) !=0) {
1201				goto out1;
1202			}
1203
1204			/* no need to be under the fdlock */
1205			closeonexec = p->p_fd->fd_ofileflags[fd] & UF_EXCLOSE;
1206			error =  pid_atalkinfo(at, fp, closeonexec, buffer, buffersize, retval);
1207		}
1208		break;
1209
1210		default: {
1211			error = EINVAL;
1212		}
1213		break;
1214
1215	}
1216
1217	fp_drop(p, fd, fp , 0);
1218out1 :
1219	proc_rele(p);
1220out:
1221	return(error);
1222}
1223
1224
1225static int
1226proc_security_policy(proc_t p)
1227{
1228	kauth_cred_t my_cred;
1229	uid_t uid;
1230
1231	my_cred = kauth_cred_proc_ref(p);
1232	uid = kauth_cred_getuid(my_cred) ;
1233	kauth_cred_unref(&my_cred);
1234
1235	if ((uid != kauth_cred_getuid(kauth_cred_get()))
1236		&& suser(kauth_cred_get(), (u_short *)0)) {
1237			return(EPERM);
1238		}
1239
1240	return(0);
1241}
1242
1243int
1244proc_kernmsgbuf(user_addr_t buffer, uint32_t buffersize, register_t * retval)
1245{
1246	if (suser(kauth_cred_get(), (u_short *)0) == 0) {
1247		return(log_dmesg(buffer, buffersize, retval));
1248	} else
1249		return(EPERM);
1250}
1251
1252/*
1253 * copy stat64 structure into vinfo_stat structure.
1254 */
1255static void
1256munge_vinfo_stat(struct stat64 *sbp, struct vinfo_stat *vsbp)
1257{
1258        bzero(vsbp, sizeof(struct vinfo_stat));
1259
1260	vsbp->vst_dev = sbp->st_dev;
1261	vsbp->vst_mode = sbp->st_mode;
1262	vsbp->vst_nlink = sbp->st_nlink;
1263	vsbp->vst_ino = sbp->st_ino;
1264	vsbp->vst_uid = sbp->st_uid;
1265	vsbp->vst_gid = sbp->st_gid;
1266	vsbp->vst_atime = sbp->st_atimespec.tv_sec;
1267	vsbp->vst_atimensec = sbp->st_atimespec.tv_nsec;
1268	vsbp->vst_mtime = sbp->st_mtimespec.tv_sec;
1269	vsbp->vst_mtimensec = sbp->st_mtimespec.tv_nsec;
1270	vsbp->vst_ctime = sbp->st_ctimespec.tv_sec;
1271	vsbp->vst_ctimensec = sbp->st_ctimespec.tv_nsec;
1272	vsbp->vst_birthtime = sbp->st_birthtimespec.tv_sec;
1273	vsbp->vst_birthtimensec = sbp->st_birthtimespec.tv_nsec;
1274	vsbp->vst_size = sbp->st_size;
1275	vsbp->vst_blocks = sbp->st_blocks;
1276	vsbp->vst_blksize = sbp->st_blksize;
1277	vsbp->vst_flags = sbp->st_flags;
1278	vsbp->vst_gen = sbp->st_gen;
1279	vsbp->vst_rdev = sbp->st_rdev;
1280	vsbp->vst_qspare[0] = sbp->st_qspare[0];
1281	vsbp->vst_qspare[1] = sbp->st_qspare[1];
1282}
1283