]>
Commit | Line | Data |
---|---|---|
c0fea474 A |
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 |