xref: /openbsd-src/lib/libkvm/kvm_file2.c (revision 1ad61ae0a79a724d2d3ec69e69c8e1d1ff6b53a0)
1 /*	$OpenBSD: kvm_file2.c,v 1.57 2022/02/22 17:35:01 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2009 Todd C. Miller <millert@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*-
20  * Copyright (c) 1989, 1992, 1993
21  *	The Regents of the University of California.  All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. Neither the name of the University nor the names of its contributors
32  *    may be used to endorse or promote products derived from this software
33  *    without specific prior written permission.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  * SUCH DAMAGE.
46  */
47 
48 /*
49  * Extended file list interface for kvm.  pstat, fstat and netstat are
50  * users of this code, so we've factored it out into a separate module.
51  * Thus, we keep this grunge out of the other kvm applications (i.e.,
52  * most other applications are interested only in open/close/read/nlist).
53  */
54 
55 #define __need_process
56 
57 #include <sys/types.h>
58 #include <sys/signal.h>
59 #include <sys/uio.h>
60 #include <sys/ucred.h>
61 #include <sys/proc.h>
62 #define _KERNEL
63 #include <sys/file.h>
64 #include <sys/mount.h>
65 #undef _KERNEL
66 #include <sys/vnode.h>
67 #include <sys/socket.h>
68 #include <sys/socketvar.h>
69 #include <sys/domain.h>
70 #include <sys/protosw.h>
71 #include <sys/event.h>
72 #include <sys/eventvar.h>
73 #include <sys/un.h>
74 #include <sys/unpcb.h>
75 #include <sys/filedesc.h>
76 #include <sys/mbuf.h>
77 #include <sys/pipe.h>
78 #include <sys/stat.h>
79 #include <sys/sysctl.h>
80 #include <sys/specdev.h>
81 
82 #define _KERNEL
83 #include <ufs/ufs/quota.h>
84 #include <ufs/ufs/inode.h>
85 #undef _KERNEL
86 
87 #include <nfs/nfsproto.h>
88 #include <nfs/rpcv2.h>
89 #include <nfs/nfs.h>
90 #include <nfs/nfsnode.h>
91 
92 #include <msdosfs/bpb.h>
93 #include <msdosfs/denode.h>
94 #include <msdosfs/msdosfsmount.h>
95 
96 #include <net/route.h>
97 #include <netinet/in.h>
98 #include <netinet/ip.h>
99 #include <netinet/in_pcb.h>
100 #include <netinet/tcp.h>
101 #include <netinet/tcp_timer.h>
102 #include <netinet/tcp_var.h>
103 
104 #ifdef INET6
105 #include <netinet/ip6.h>
106 #include <netinet6/ip6_var.h>
107 #endif
108 
109 #include <fcntl.h>
110 #include <nlist.h>
111 #include <kvm.h>
112 #include <db.h>
113 #include <stddef.h>
114 #include <stdlib.h>
115 #include <string.h>
116 #include <unistd.h>
117 #include <limits.h>
118 #include <errno.h>
119 
120 #include "kvm_private.h"
121 #include "kvm_file.h"
122 
123 static struct kinfo_file *kvm_deadfile_byfile(kvm_t *, int, int,
124     size_t, int *);
125 static struct kinfo_file *kvm_deadfile_byid(kvm_t *, int, int,
126     size_t, int *);
127 static int fill_file(kvm_t *, struct kinfo_file *, struct file *, u_long,
128     struct vnode *, struct process *, int, pid_t);
129 static int filestat(kvm_t *, struct kinfo_file *, struct vnode *);
130 
131 LIST_HEAD(processlist, process);
132 
133 struct kinfo_file *
134 kvm_getfiles(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
135 {
136 	int mib[6], rv;
137 	void *filebase;
138 	size_t size;
139 
140 	if (ISALIVE(kd)) {
141 		mib[0] = CTL_KERN;
142 		mib[1] = KERN_FILE;
143 		mib[2] = op;
144 		mib[3] = arg;
145 		mib[4] = esize;
146 
147 		do {
148 			mib[5] = 0;
149 
150 			/* find size and alloc buffer */
151 			rv = sysctl(mib, 6, NULL, &size, NULL, 0);
152 			if (rv == -1) {
153 				if (errno != ESRCH && kd->vmfd != -1)
154 					goto deadway;
155 				_kvm_syserr(kd, kd->program, "kvm_getfiles");
156 				return (NULL);
157 			}
158 
159 			size += size / 8; /* add ~10% */
160 
161 			filebase = _kvm_realloc(kd, kd->filebase, size);
162 			if (filebase == NULL)
163 				return (NULL);
164 
165 			kd->filebase = filebase;
166 
167 			/* get actual data */
168 			mib[5] = size / esize;
169 			rv = sysctl(mib, 6, kd->filebase, &size, NULL, 0);
170 			if (rv == -1 && errno != ENOMEM) {
171 				_kvm_syserr(kd, kd->program,
172 				    "kvm_getfiles");
173 				return (NULL);
174 			}
175 		} while (rv == -1);
176 
177 		*cnt = size / esize;
178 		return (kd->filebase);
179 	} else {
180 		if (esize > sizeof(struct kinfo_file)) {
181 			_kvm_syserr(kd, kd->program,
182 			    "kvm_getfiles: unknown fields requested: libkvm out of date?");
183 			return (NULL);
184 		}
185 	    deadway:
186 		switch (op) {
187 		case KERN_FILE_BYFILE:
188 			return (kvm_deadfile_byfile(kd, op, arg, esize, cnt));
189 			break;
190 		case KERN_FILE_BYPID:
191 		case KERN_FILE_BYUID:
192 			return (kvm_deadfile_byid(kd, op, arg, esize, cnt));
193 			break;
194 		default:
195 			return (NULL);
196 		}
197 	}
198 }
199 
200 static struct kinfo_file *
201 kvm_deadfile_byfile(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
202 {
203 	struct nlist nl[3], *p;
204 	size_t buflen;
205 	int n = 0;
206 	char *where;
207 	struct kinfo_file kf;
208 	struct file *fp, file;
209 	struct filelist filehead;
210 	int nfiles;
211 
212 	nl[0].n_name = "_filehead";
213 	nl[1].n_name = "_numfiles";
214 	nl[2].n_name = 0;
215 
216 	if (kvm_nlist(kd, nl) != 0) {
217 		for (p = nl; p->n_type != 0; ++p)
218 			;
219 		_kvm_err(kd, kd->program,
220 			 "%s: no such symbol", p->n_name);
221 		return (NULL);
222 	}
223 	if (KREAD(kd, nl[0].n_value, &filehead)) {
224 		_kvm_err(kd, kd->program, "can't read filehead");
225 		return (NULL);
226 	}
227 	if (KREAD(kd, nl[1].n_value, &nfiles)) {
228 		_kvm_err(kd, kd->program, "can't read nfiles");
229 		return (NULL);
230 	}
231 	where = _kvm_reallocarray(kd, kd->filebase, nfiles, esize);
232 	if (where == NULL)
233 		return (NULL);
234 
235 	kd->filebase = (void *)where;
236 	buflen = nfiles * esize;
237 
238 	for (fp = LIST_FIRST(&filehead);
239 	    fp != NULL && esize <= buflen;
240 	    fp = LIST_NEXT(&file, f_list)) {
241 		if (KREAD(kd, (u_long)fp, &file)) {
242 			_kvm_err(kd, kd->program, "can't read kfp");
243 			return (NULL);
244 		}
245 		if (file.f_count == 0)
246 			continue;
247 		if (arg != 0 && file.f_type != arg)
248 			continue;
249 		if (fill_file(kd, &kf, &file, (u_long)fp, NULL, NULL, 0, 0)
250 		    == -1)
251 			return (NULL);
252 		memcpy(where, &kf, esize);
253 		where += esize;
254 		buflen -= esize;
255 		n++;
256 	}
257 	if (n != nfiles) {
258 		_kvm_err(kd, kd->program, "inconsistent nfiles");
259 		return (NULL);
260 	}
261 	*cnt = n;
262 	return (kd->filebase);
263 }
264 
265 static struct kinfo_file *
266 kvm_deadfile_byid(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
267 {
268 	size_t buflen;
269 	struct nlist nl[4], *np;
270 	int n = 0, matched = 0;
271 	char *where;
272 	struct kinfo_file kf;
273 	struct file *fp, file;
274 	struct filelist filehead;
275 	struct filedesc0 filed0;
276 #define filed	filed0.fd_fd
277 	struct processlist allprocess;
278 	struct process *pr, process;
279 	struct ucred ucred;
280 	char *filebuf = NULL;
281 	int i, nfiles;
282 
283 	nl[0].n_name = "_filehead";
284 	nl[1].n_name = "_numfiles";
285 	nl[2].n_name = "_allprocess";
286 	nl[3].n_name = 0;
287 
288 	if (kvm_nlist(kd, nl) != 0) {
289 		for (np = nl; np->n_type != 0; ++np)
290 			;
291 		_kvm_err(kd, kd->program,
292 			 "%s: no such symbol", np->n_name);
293 		return (NULL);
294 	}
295 	if (KREAD(kd, nl[0].n_value, &filehead)) {
296 		_kvm_err(kd, kd->program, "can't read filehead");
297 		return (NULL);
298 	}
299 	if (KREAD(kd, nl[1].n_value, &nfiles)) {
300 		_kvm_err(kd, kd->program, "can't read nfiles");
301 		return (NULL);
302 	}
303 	if (KREAD(kd, nl[2].n_value, &allprocess)) {
304 		_kvm_err(kd, kd->program, "can't read allprocess");
305 		return (NULL);
306 	}
307 	/* this may be more room than we need but counting is expensive */
308 	where = _kvm_reallocarray(kd, kd->filebase, nfiles + 10, esize);
309 	if (where == NULL)
310 		return (NULL);
311 
312 	kd->filebase = (void *)where;
313 	buflen = (nfiles + 10) * esize;
314 
315 	if (op != KERN_FILE_BYPID || arg <= 0)
316 		matched = 1;
317 
318 	for (pr = LIST_FIRST(&allprocess);
319 	    pr != NULL;
320 	    pr = LIST_NEXT(&process, ps_list)) {
321 		if (KREAD(kd, (u_long)pr, &process)) {
322 			_kvm_err(kd, kd->program, "can't read process at %lx",
323 			    (u_long)pr);
324 			goto cleanup;
325 		}
326 
327 		/* skip system, exiting, embryonic and undead processes */
328 		if (process.ps_flags & (PS_SYSTEM | PS_EMBRYO | PS_EXITING))
329 			continue;
330 
331 		if (op == KERN_FILE_BYPID) {
332 			/* check if this is the pid we are looking for */
333 			if (arg > 0 && process.ps_pid != (pid_t)arg)
334 				continue;
335 			matched = 1;
336 		}
337 
338 		if (KREAD(kd, (u_long)process.ps_ucred, &ucred)) {
339 			_kvm_err(kd, kd->program, "can't read ucred at %lx",
340 			    (u_long)process.ps_ucred);
341 			goto cleanup;
342 		}
343 		process.ps_ucred = &ucred;
344 
345 		if (op == KERN_FILE_BYUID && arg >= 0 &&
346 		    process.ps_ucred->cr_uid != (uid_t)arg) {
347 			/* not the uid we are looking for */
348 			continue;
349 		}
350 
351 		if (KREAD(kd, (u_long)process.ps_fd, &filed0)) {
352 			_kvm_err(kd, kd->program, "can't read filedesc at %lx",
353 			    (u_long)process.ps_fd);
354 			goto cleanup;
355 		}
356 		if ((char *)process.ps_fd + offsetof(struct filedesc0,fd_dfiles)
357 		    == (char *)filed.fd_ofiles) {
358 			filed.fd_ofiles = filed0.fd_dfiles;
359 			filed.fd_ofileflags = filed0.fd_dfileflags;
360 		} else {
361 			size_t fsize;
362 			char *tmp = reallocarray(filebuf,
363 			    filed.fd_nfiles, OFILESIZE);
364 
365 			fsize = filed.fd_nfiles * OFILESIZE;
366 			if (tmp == NULL) {
367 				_kvm_syserr(kd, kd->program, "realloc ofiles");
368 				goto cleanup;
369 			}
370 			filebuf = tmp;
371 			if (kvm_read(kd, (u_long)filed.fd_ofiles, filebuf,
372 			    fsize) != fsize) {
373 				_kvm_err(kd, kd->program,
374 				    "can't read fd_ofiles");
375 				goto cleanup;
376 			}
377 			filed.fd_ofiles = (void *)filebuf;
378 			filed.fd_ofileflags = filebuf +
379 			    (filed.fd_nfiles * sizeof(struct file *));
380 		}
381 		process.ps_fd = &filed;
382 
383 		if (process.ps_textvp) {
384 			if (buflen < esize)
385 				goto done;
386 			if (fill_file(kd, &kf, NULL, 0, process.ps_textvp,
387 			    &process, KERN_FILE_TEXT, process.ps_pid) == -1)
388 				goto cleanup;
389 			memcpy(where, &kf, esize);
390 			where += esize;
391 			buflen -= esize;
392 			n++;
393 		}
394 		if (filed.fd_cdir) {
395 			if (buflen < esize)
396 				goto done;
397 			if (fill_file(kd, &kf, NULL, 0, filed.fd_cdir,
398 			    &process, KERN_FILE_CDIR, process.ps_pid) == -1)
399 				goto cleanup;
400 			memcpy(where, &kf, esize);
401 			where += esize;
402 			buflen -= esize;
403 			n++;
404 		}
405 		if (filed.fd_rdir) {
406 			if (buflen < esize)
407 				goto done;
408 			if (fill_file(kd, &kf, NULL, 0, filed.fd_rdir,
409 			    &process, KERN_FILE_RDIR, process.ps_pid) == -1)
410 				goto cleanup;
411 			memcpy(where, &kf, esize);
412 			where += esize;
413 			buflen -= esize;
414 			n++;
415 		}
416 		if (process.ps_tracevp) {
417 			if (buflen < esize)
418 				goto done;
419 			if (fill_file(kd, &kf, NULL, 0, process.ps_tracevp,
420 			    &process, KERN_FILE_TRACE, process.ps_pid) == -1)
421 				goto cleanup;
422 			memcpy(where, &kf, esize);
423 			where += esize;
424 			buflen -= esize;
425 			n++;
426 		}
427 
428 		if (filed.fd_nfiles < 0 ||
429 		    filed.fd_lastfile >= filed.fd_nfiles ||
430 		    filed.fd_freefile > filed.fd_lastfile + 1) {
431 			_kvm_err(kd, kd->program,
432 			    "filedesc corrupted at %lx for pid %d",
433 			    (u_long)process.ps_fd, process.ps_pid);
434 			goto cleanup;
435 		}
436 
437 		for (i = 0; i < filed.fd_nfiles; i++) {
438 			if (buflen < esize)
439 				goto done;
440 			if ((fp = filed.fd_ofiles[i]) == NULL)
441 				continue;
442 			if (KREAD(kd, (u_long)fp, &file)) {
443 				_kvm_err(kd, kd->program, "can't read file");
444 				goto cleanup;
445 			}
446 			if (fill_file(kd, &kf, &file, (u_long)fp, NULL,
447 			    &process, i, process.ps_pid) == -1)
448 				goto cleanup;
449 			memcpy(where, &kf, esize);
450 			where += esize;
451 			buflen -= esize;
452 			n++;
453 		}
454 	}
455 	if (!matched) {
456 		errno = ESRCH;
457 		goto cleanup;
458 	}
459 done:
460 	*cnt = n;
461 	free(filebuf);
462 	return (kd->filebase);
463 cleanup:
464 	free(filebuf);
465 	return (NULL);
466 }
467 
468 static int
469 fill_file(kvm_t *kd, struct kinfo_file *kf, struct file *fp, u_long fpaddr,
470     struct vnode *vp, struct process *pr, int fd, pid_t pid)
471 {
472 	struct ucred f_cred;
473 
474 	memset(kf, 0, sizeof(*kf));
475 
476 	kf->fd_fd = fd;		/* might not really be an fd */
477 
478 	if (fp != NULL) {
479 		/* Fill in f_cred */
480 		if (KREAD(kd, (u_long)fp->f_cred, &f_cred)) {
481 			_kvm_err(kd, kd->program, "can't read f_cred");
482 			return (-1);
483 		}
484 
485 		kf->f_fileaddr = PTRTOINT64(fpaddr);
486 		kf->f_flag = fp->f_flag;
487 		kf->f_iflags = fp->f_iflags;
488 		kf->f_type = fp->f_type;
489 		kf->f_count = fp->f_count;
490 		kf->f_ucred = PTRTOINT64(fp->f_cred);
491 		kf->f_uid = f_cred.cr_uid;
492 		kf->f_gid = f_cred.cr_gid;
493 		kf->f_ops = PTRTOINT64(fp->f_ops);
494 		kf->f_offset = fp->f_offset;
495 		kf->f_data = PTRTOINT64(fp->f_data);
496 		kf->f_usecount = 0;
497 
498 		kf->f_rxfer = fp->f_rxfer;
499 		kf->f_rwfer = fp->f_wxfer;
500 		kf->f_seek = fp->f_seek;
501 		kf->f_rbytes = fp->f_rbytes;
502 		kf->f_wbytes = fp->f_wbytes;
503 	} else if (vp != NULL) {
504 		/* fake it */
505 		kf->f_type = DTYPE_VNODE;
506 		kf->f_flag = FREAD;
507 		if (fd == KERN_FILE_TRACE)
508 			kf->f_flag |= FWRITE;
509 		kf->f_data = PTRTOINT64(vp);
510 	}
511 
512 	/* information about the object associated with this file */
513 	switch (kf->f_type) {
514 	case DTYPE_VNODE: {
515 		struct vnode vbuf;
516 
517 		if (KREAD(kd, (u_long)(fp ? fp->f_data : vp), &vbuf)) {
518 			_kvm_err(kd, kd->program, "can't read vnode");
519 			return (-1);
520 		}
521 		vp = &vbuf;
522 
523 		kf->v_un = PTRTOINT64(vp->v_un.vu_socket);
524 		kf->v_type = vp->v_type;
525 		kf->v_tag = vp->v_tag;
526 		kf->v_flag = vp->v_flag;
527 		kf->v_data = PTRTOINT64(vp->v_data);
528 		kf->v_mount = PTRTOINT64(vp->v_mount);
529 
530 		if (vp->v_mount != NULL) {
531 			struct mount mount;
532 
533 			if (KREAD(kd, (u_long)vp->v_mount, &mount)) {
534 				_kvm_err(kd, kd->program, "can't read v_mount");
535 				return (-1);
536 			}
537 
538 			strlcpy(kf->f_mntonname, mount.mnt_stat.f_mntonname,
539 			    sizeof(kf->f_mntonname));
540 		}
541 
542 		/* Fill in va_fsid, va_fileid, va_mode, va_size, va_rdev */
543 		filestat(kd, kf, vp);
544 		break;
545 	    }
546 
547 	case DTYPE_SOCKET: {
548 		struct socket sock;
549 		struct sosplice ssp;
550 		struct protosw protosw;
551 		struct domain domain;
552 
553 		if (KREAD(kd, (u_long)fp->f_data, &sock)) {
554 			_kvm_err(kd, kd->program, "can't read socket");
555 			return (-1);
556 		}
557 
558 		kf->so_type = sock.so_type;
559 		kf->so_state = sock.so_state;
560 		kf->so_pcb = PTRTOINT64(sock.so_pcb);
561 		if (KREAD(kd, (u_long)sock.so_proto, &protosw)) {
562 			_kvm_err(kd, kd->program, "can't read protosw");
563 			return (-1);
564 		}
565 		kf->so_protocol = protosw.pr_protocol;
566 		if (KREAD(kd, (u_long)protosw.pr_domain, &domain)) {
567 			_kvm_err(kd, kd->program, "can't read domain");
568 			return (-1);
569 		}
570 		kf->so_family = domain.dom_family;
571 		kf->so_rcv_cc = sock.so_rcv.sb_cc;
572 		kf->so_snd_cc = sock.so_snd.sb_cc;
573 		if (sock.so_sp) {
574 			if (KREAD(kd, (u_long)sock.so_sp, &ssp)) {
575 				_kvm_err(kd, kd->program, "can't read splice");
576 				return (-1);
577 			}
578 			if (ssp.ssp_socket) {
579 				kf->so_splice = PTRTOINT64(ssp.ssp_socket);
580 				kf->so_splicelen = ssp.ssp_len;
581 			} else if (ssp.ssp_soback) {
582 				kf->so_splicelen = -1;
583 			}
584 		}
585 		if (!sock.so_pcb)
586 			break;
587 		switch (kf->so_family) {
588 		case AF_INET: {
589 			struct inpcb inpcb;
590 
591 			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
592 				_kvm_err(kd, kd->program, "can't read inpcb");
593 				return (-1);
594 			}
595 			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
596 			kf->inp_lport = inpcb.inp_lport;
597 			kf->inp_laddru[0] = inpcb.inp_laddr.s_addr;
598 			kf->inp_fport = inpcb.inp_fport;
599 			kf->inp_faddru[0] = inpcb.inp_faddr.s_addr;
600 			kf->inp_rtableid = inpcb.inp_rtableid;
601 			if (sock.so_type == SOCK_RAW)
602 				kf->inp_proto = inpcb.inp_ip.ip_p;
603 			if (protosw.pr_protocol == IPPROTO_TCP) {
604 				struct tcpcb tcpcb;
605 				if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) {
606 					_kvm_err(kd, kd->program,
607 					    "can't read tcpcb");
608 					return (-1);
609 				}
610 				kf->t_rcv_wnd = tcpcb.rcv_wnd;
611 				kf->t_snd_wnd = tcpcb.snd_wnd;
612 				kf->t_snd_cwnd = tcpcb.snd_cwnd;
613 				kf->t_state = tcpcb.t_state;
614 			}
615 			break;
616 		    }
617 		case AF_INET6: {
618 			struct inpcb inpcb;
619 #define s6_addr32 __u6_addr.__u6_addr32
620 
621 			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
622 				_kvm_err(kd, kd->program, "can't read inpcb");
623 				return (-1);
624 			}
625 			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
626 			kf->inp_lport = inpcb.inp_lport;
627 			kf->inp_laddru[0] = inpcb.inp_laddr6.s6_addr32[0];
628 			kf->inp_laddru[1] = inpcb.inp_laddr6.s6_addr32[1];
629 			kf->inp_laddru[2] = inpcb.inp_laddr6.s6_addr32[2];
630 			kf->inp_laddru[3] = inpcb.inp_laddr6.s6_addr32[3];
631 			kf->inp_fport = inpcb.inp_fport;
632 			kf->inp_faddru[0] = inpcb.inp_laddr6.s6_addr32[0];
633 			kf->inp_faddru[1] = inpcb.inp_faddr6.s6_addr32[1];
634 			kf->inp_faddru[2] = inpcb.inp_faddr6.s6_addr32[2];
635 			kf->inp_faddru[3] = inpcb.inp_faddr6.s6_addr32[3];
636 			kf->inp_rtableid = inpcb.inp_rtableid;
637 			if (sock.so_type == SOCK_RAW)
638 				kf->inp_proto = inpcb.inp_ipv6.ip6_nxt;
639 			if (protosw.pr_protocol == IPPROTO_TCP) {
640 				struct tcpcb tcpcb;
641 				if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) {
642 					_kvm_err(kd, kd->program,
643 					    "can't read tcpcb");
644 					return (-1);
645 				}
646 				kf->t_rcv_wnd = tcpcb.rcv_wnd;
647 				kf->t_snd_wnd = tcpcb.snd_wnd;
648 				kf->t_snd_cwnd = tcpcb.snd_cwnd;
649 				kf->t_state = tcpcb.t_state;
650 			}
651 			break;
652 		    }
653 		case AF_UNIX: {
654 			struct unpcb unpcb;
655 
656 			if (KREAD(kd, (u_long)sock.so_pcb, &unpcb)) {
657 				_kvm_err(kd, kd->program, "can't read unpcb");
658 				return (-1);
659 			}
660 			kf->f_msgcount	= unpcb.unp_msgcount;
661 			kf->unp_conn	= PTRTOINT64(unpcb.unp_conn);
662 			kf->unp_refs	= PTRTOINT64(
663 			    SLIST_FIRST(&unpcb.unp_refs));
664 			kf->unp_nextref	= PTRTOINT64(
665 			    SLIST_NEXT(&unpcb, unp_nextref));
666 			kf->v_un	= PTRTOINT64(unpcb.unp_vnode);
667 			if (unpcb.unp_addr != NULL) {
668 				struct mbuf mb;
669 				struct sockaddr_un un;
670 
671 				if (KREAD(kd, (u_long)unpcb.unp_addr, &mb)) {
672 					_kvm_err(kd, kd->program,
673 					    "can't read sockaddr_un mbuf");
674 					return (-1);
675 				}
676 				if (KREAD(kd, (u_long)mb.m_data, &un)) {
677 					_kvm_err(kd, kd->program,
678 					    "can't read sockaddr_un");
679 					return (-1);
680 				}
681 
682 				kf->unp_addr = PTRTOINT64(unpcb.unp_addr);
683 				memcpy(kf->unp_path, un.sun_path, un.sun_len
684 				    - offsetof(struct sockaddr_un,sun_path));
685 			}
686 
687 			break;
688 		    }
689 		}
690 		break;
691 	    }
692 
693 	case DTYPE_PIPE: {
694 		struct pipe pipe;
695 
696 		if (KREAD(kd, (u_long)fp->f_data, &pipe)) {
697 			_kvm_err(kd, kd->program, "can't read pipe");
698 			return (-1);
699 		}
700 		kf->pipe_peer = PTRTOINT64(pipe.pipe_peer);
701 		kf->pipe_state = pipe.pipe_state;
702 		break;
703 	    }
704 
705 	case DTYPE_KQUEUE: {
706 		struct kqueue kqi;
707 
708 		if (KREAD(kd, (u_long)fp->f_data, &kqi)) {
709 			_kvm_err(kd, kd->program, "can't read kqi");
710 			return (-1);
711 		}
712 		kf->kq_count = kqi.kq_count;
713 		kf->kq_state = kqi.kq_state;
714 		break;
715 	    }
716 	}
717 
718 	/* per-process information for KERN_FILE_BY[PU]ID */
719 	if (pr != NULL) {
720 		kf->p_pid = pid;
721 		kf->p_uid = pr->ps_ucred->cr_uid;
722 		kf->p_gid = pr->ps_ucred->cr_gid;
723 		kf->p_tid = -1;
724 		strlcpy(kf->p_comm, pr->ps_comm, sizeof(kf->p_comm));
725 		if (pr->ps_fd != NULL)
726 			kf->fd_ofileflags = pr->ps_fd->fd_ofileflags[fd];
727 	}
728 
729 	return (0);
730 }
731 
732 mode_t
733 _kvm_getftype(enum vtype v_type)
734 {
735 	mode_t ftype = 0;
736 
737 	switch (v_type) {
738 	case VREG:
739 		ftype = S_IFREG;
740 		break;
741 	case VDIR:
742 		ftype = S_IFDIR;
743 		break;
744 	case VBLK:
745 		ftype = S_IFBLK;
746 		break;
747 	case VCHR:
748 		ftype = S_IFCHR;
749 		break;
750 	case VLNK:
751 		ftype = S_IFLNK;
752 		break;
753 	case VSOCK:
754 		ftype = S_IFSOCK;
755 		break;
756 	case VFIFO:
757 		ftype = S_IFIFO;
758 		break;
759 	case VNON:
760 	case VBAD:
761 		break;
762 	}
763 
764 	return (ftype);
765 }
766 
767 static int
768 ufs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
769 {
770 	struct inode inode;
771 	struct ufs1_dinode di1;
772 
773 	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
774 		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
775 		return (-1);
776 	}
777 
778 	if (KREAD(kd, (u_long)inode.i_din1, &di1)) {
779 		_kvm_err(kd, kd->program, "can't read dinode at %p",
780 		    inode.i_din1);
781 		return (-1);
782 	}
783 
784 	inode.i_din1 = &di1;
785 
786 	kf->va_fsid = inode.i_dev & 0xffff;
787 	kf->va_fileid = (long)inode.i_number;
788 	kf->va_mode = inode.i_ffs1_mode;
789 	kf->va_size = inode.i_ffs1_size;
790 	kf->va_rdev = inode.i_ffs1_rdev;
791 	kf->va_nlink = inode.i_ffs1_nlink;
792 
793 	return (0);
794 }
795 
796 static int
797 ext2fs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
798 {
799 	struct inode inode;
800 	struct ext2fs_dinode e2di;
801 
802 	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
803 		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
804 		return (-1);
805 	}
806 
807 	if (KREAD(kd, (u_long)inode.i_e2din, &e2di)) {
808 		_kvm_err(kd, kd->program, "can't read dinode at %p",
809 		    inode.i_e2din);
810 		return (-1);
811 	}
812 
813 	inode.i_e2din = &e2di;
814 
815 	kf->va_fsid = inode.i_dev & 0xffff;
816 	kf->va_fileid = (long)inode.i_number;
817 	kf->va_mode = inode.i_e2fs_mode;
818 	kf->va_size = inode.i_e2fs_size;
819 	kf->va_rdev = 0;	/* XXX */
820 	kf->va_nlink = inode.i_e2fs_nlink;
821 
822 	return (0);
823 }
824 
825 static int
826 msdos_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
827 {
828 	struct denode de;
829 	struct msdosfsmount mp;
830 
831 	if (KREAD(kd, (u_long)VTODE(vp), &de)) {
832 		_kvm_err(kd, kd->program, "can't read denode at %p", VTODE(vp));
833 		return (-1);
834 	}
835 	if (KREAD(kd, (u_long)de.de_pmp, &mp)) {
836 		_kvm_err(kd, kd->program, "can't read mount struct at %p",
837 		    de.de_pmp);
838 		return (-1);
839 	}
840 
841 	kf->va_fsid = de.de_dev & 0xffff;
842 	kf->va_fileid = 0; /* XXX see msdosfs_vptofh() for more info */
843 	kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type);
844 	kf->va_size = de.de_FileSize;
845 	kf->va_rdev = 0;  /* msdosfs doesn't support device files */
846 	kf->va_nlink = 1;
847 
848 	return (0);
849 }
850 
851 static int
852 nfs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
853 {
854 	struct nfsnode nfsnode;
855 
856 	if (KREAD(kd, (u_long)VTONFS(vp), &nfsnode)) {
857 		_kvm_err(kd, kd->program, "can't read nfsnode at %p",
858 		    VTONFS(vp));
859 		return (-1);
860 	}
861 	kf->va_fsid = nfsnode.n_vattr.va_fsid;
862 	kf->va_fileid = nfsnode.n_vattr.va_fileid;
863 	kf->va_size = nfsnode.n_size;
864 	kf->va_rdev = nfsnode.n_vattr.va_rdev;
865 	kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type);
866 	kf->va_nlink = nfsnode.n_vattr.va_nlink;
867 
868 	return (0);
869 }
870 
871 static int
872 spec_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
873 {
874 	struct specinfo		specinfo;
875 	struct vnode		parent;
876 
877 	if (KREAD(kd, (u_long)vp->v_specinfo, &specinfo)) {
878 		_kvm_err(kd, kd->program, "can't read specinfo at %p",
879 		     vp->v_specinfo);
880 		return (-1);
881 	}
882 
883 	vp->v_specinfo = &specinfo;
884 
885 	if (KREAD(kd, (u_long)vp->v_specparent, &parent)) {
886 		_kvm_err(kd, kd->program, "can't read parent vnode at %p",
887 		     vp->v_specparent);
888 		return (-1);
889 	}
890 
891 	if (ufs_filestat(kd, kf, vp))
892 		return (-1);
893 
894 	return (0);
895 }
896 
897 static int
898 filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
899 {
900 	int ret = 0;
901 
902 	if (vp->v_type != VNON && vp->v_type != VBAD) {
903 		switch (vp->v_tag) {
904 		case VT_UFS:
905 		case VT_MFS:
906 			ret = ufs_filestat(kd, kf, vp);
907 			break;
908 		case VT_NFS:
909 			ret = nfs_filestat(kd, kf, vp);
910 			break;
911 		case VT_EXT2FS:
912 			ret = ext2fs_filestat(kd, kf, vp);
913 			break;
914 		case VT_ISOFS:
915 			ret = _kvm_stat_cd9660(kd, kf, vp);
916 			break;
917 		case VT_MSDOSFS:
918 			ret = msdos_filestat(kd, kf, vp);
919 			break;
920 		case VT_UDF:
921 			ret = _kvm_stat_udf(kd, kf, vp);
922 			break;
923 		case VT_NTFS:
924 			ret = _kvm_stat_ntfs(kd, kf, vp);
925 			break;
926 		case VT_NON:
927 			if (vp->v_flag & VCLONE)
928 				ret = spec_filestat(kd, kf, vp);
929 			break;
930 		default:
931 			ret = -1;
932 			break;
933 		}
934 	}
935 	return (ret);
936 }
937