1 /* $OpenBSD: kvm_file2.c,v 1.58 2024/02/11 21:29:12 bluhm 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 #endif
107
108 #include <fcntl.h>
109 #include <nlist.h>
110 #include <kvm.h>
111 #include <db.h>
112 #include <stddef.h>
113 #include <stdlib.h>
114 #include <string.h>
115 #include <unistd.h>
116 #include <limits.h>
117 #include <errno.h>
118
119 #include "kvm_private.h"
120 #include "kvm_file.h"
121
122 static struct kinfo_file *kvm_deadfile_byfile(kvm_t *, int, int,
123 size_t, int *);
124 static struct kinfo_file *kvm_deadfile_byid(kvm_t *, int, int,
125 size_t, int *);
126 static int fill_file(kvm_t *, struct kinfo_file *, struct file *, u_long,
127 struct vnode *, struct process *, int, pid_t);
128 static int filestat(kvm_t *, struct kinfo_file *, struct vnode *);
129
130 LIST_HEAD(processlist, process);
131
132 struct kinfo_file *
kvm_getfiles(kvm_t * kd,int op,int arg,size_t esize,int * cnt)133 kvm_getfiles(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
134 {
135 int mib[6], rv;
136 void *filebase;
137 size_t size;
138
139 if (ISALIVE(kd)) {
140 mib[0] = CTL_KERN;
141 mib[1] = KERN_FILE;
142 mib[2] = op;
143 mib[3] = arg;
144 mib[4] = esize;
145
146 do {
147 mib[5] = 0;
148
149 /* find size and alloc buffer */
150 rv = sysctl(mib, 6, NULL, &size, NULL, 0);
151 if (rv == -1) {
152 if (errno != ESRCH && kd->vmfd != -1)
153 goto deadway;
154 _kvm_syserr(kd, kd->program, "kvm_getfiles");
155 return (NULL);
156 }
157
158 size += size / 8; /* add ~10% */
159
160 filebase = _kvm_realloc(kd, kd->filebase, size);
161 if (filebase == NULL)
162 return (NULL);
163
164 kd->filebase = filebase;
165
166 /* get actual data */
167 mib[5] = size / esize;
168 rv = sysctl(mib, 6, kd->filebase, &size, NULL, 0);
169 if (rv == -1 && errno != ENOMEM) {
170 _kvm_syserr(kd, kd->program,
171 "kvm_getfiles");
172 return (NULL);
173 }
174 } while (rv == -1);
175
176 *cnt = size / esize;
177 return (kd->filebase);
178 } else {
179 if (esize > sizeof(struct kinfo_file)) {
180 _kvm_syserr(kd, kd->program,
181 "kvm_getfiles: unknown fields requested: libkvm out of date?");
182 return (NULL);
183 }
184 deadway:
185 switch (op) {
186 case KERN_FILE_BYFILE:
187 return (kvm_deadfile_byfile(kd, op, arg, esize, cnt));
188 break;
189 case KERN_FILE_BYPID:
190 case KERN_FILE_BYUID:
191 return (kvm_deadfile_byid(kd, op, arg, esize, cnt));
192 break;
193 default:
194 return (NULL);
195 }
196 }
197 }
198
199 static struct kinfo_file *
kvm_deadfile_byfile(kvm_t * kd,int op,int arg,size_t esize,int * cnt)200 kvm_deadfile_byfile(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
201 {
202 struct nlist nl[3], *p;
203 size_t buflen;
204 int n = 0;
205 char *where;
206 struct kinfo_file kf;
207 struct file *fp, file;
208 struct filelist filehead;
209 int nfiles;
210
211 nl[0].n_name = "_filehead";
212 nl[1].n_name = "_numfiles";
213 nl[2].n_name = 0;
214
215 if (kvm_nlist(kd, nl) != 0) {
216 for (p = nl; p->n_type != 0; ++p)
217 ;
218 _kvm_err(kd, kd->program,
219 "%s: no such symbol", p->n_name);
220 return (NULL);
221 }
222 if (KREAD(kd, nl[0].n_value, &filehead)) {
223 _kvm_err(kd, kd->program, "can't read filehead");
224 return (NULL);
225 }
226 if (KREAD(kd, nl[1].n_value, &nfiles)) {
227 _kvm_err(kd, kd->program, "can't read nfiles");
228 return (NULL);
229 }
230 where = _kvm_reallocarray(kd, kd->filebase, nfiles, esize);
231 if (where == NULL)
232 return (NULL);
233
234 kd->filebase = (void *)where;
235 buflen = nfiles * esize;
236
237 for (fp = LIST_FIRST(&filehead);
238 fp != NULL && esize <= buflen;
239 fp = LIST_NEXT(&file, f_list)) {
240 if (KREAD(kd, (u_long)fp, &file)) {
241 _kvm_err(kd, kd->program, "can't read kfp");
242 return (NULL);
243 }
244 if (file.f_count == 0)
245 continue;
246 if (arg != 0 && file.f_type != arg)
247 continue;
248 if (fill_file(kd, &kf, &file, (u_long)fp, NULL, NULL, 0, 0)
249 == -1)
250 return (NULL);
251 memcpy(where, &kf, esize);
252 where += esize;
253 buflen -= esize;
254 n++;
255 }
256 if (n != nfiles) {
257 _kvm_err(kd, kd->program, "inconsistent nfiles");
258 return (NULL);
259 }
260 *cnt = n;
261 return (kd->filebase);
262 }
263
264 static struct kinfo_file *
kvm_deadfile_byid(kvm_t * kd,int op,int arg,size_t esize,int * cnt)265 kvm_deadfile_byid(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
266 {
267 size_t buflen;
268 struct nlist nl[4], *np;
269 int n = 0, matched = 0;
270 char *where;
271 struct kinfo_file kf;
272 struct file *fp, file;
273 struct filelist filehead;
274 struct filedesc0 filed0;
275 #define filed filed0.fd_fd
276 struct processlist allprocess;
277 struct process *pr, process;
278 struct ucred ucred;
279 char *filebuf = NULL;
280 int i, nfiles;
281
282 nl[0].n_name = "_filehead";
283 nl[1].n_name = "_numfiles";
284 nl[2].n_name = "_allprocess";
285 nl[3].n_name = 0;
286
287 if (kvm_nlist(kd, nl) != 0) {
288 for (np = nl; np->n_type != 0; ++np)
289 ;
290 _kvm_err(kd, kd->program,
291 "%s: no such symbol", np->n_name);
292 return (NULL);
293 }
294 if (KREAD(kd, nl[0].n_value, &filehead)) {
295 _kvm_err(kd, kd->program, "can't read filehead");
296 return (NULL);
297 }
298 if (KREAD(kd, nl[1].n_value, &nfiles)) {
299 _kvm_err(kd, kd->program, "can't read nfiles");
300 return (NULL);
301 }
302 if (KREAD(kd, nl[2].n_value, &allprocess)) {
303 _kvm_err(kd, kd->program, "can't read allprocess");
304 return (NULL);
305 }
306 /* this may be more room than we need but counting is expensive */
307 where = _kvm_reallocarray(kd, kd->filebase, nfiles + 10, esize);
308 if (where == NULL)
309 return (NULL);
310
311 kd->filebase = (void *)where;
312 buflen = (nfiles + 10) * esize;
313
314 if (op != KERN_FILE_BYPID || arg <= 0)
315 matched = 1;
316
317 for (pr = LIST_FIRST(&allprocess);
318 pr != NULL;
319 pr = LIST_NEXT(&process, ps_list)) {
320 if (KREAD(kd, (u_long)pr, &process)) {
321 _kvm_err(kd, kd->program, "can't read process at %lx",
322 (u_long)pr);
323 goto cleanup;
324 }
325
326 /* skip system, exiting, embryonic and undead processes */
327 if (process.ps_flags & (PS_SYSTEM | PS_EMBRYO | PS_EXITING))
328 continue;
329
330 if (op == KERN_FILE_BYPID) {
331 /* check if this is the pid we are looking for */
332 if (arg > 0 && process.ps_pid != (pid_t)arg)
333 continue;
334 matched = 1;
335 }
336
337 if (KREAD(kd, (u_long)process.ps_ucred, &ucred)) {
338 _kvm_err(kd, kd->program, "can't read ucred at %lx",
339 (u_long)process.ps_ucred);
340 goto cleanup;
341 }
342 process.ps_ucred = &ucred;
343
344 if (op == KERN_FILE_BYUID && arg >= 0 &&
345 process.ps_ucred->cr_uid != (uid_t)arg) {
346 /* not the uid we are looking for */
347 continue;
348 }
349
350 if (KREAD(kd, (u_long)process.ps_fd, &filed0)) {
351 _kvm_err(kd, kd->program, "can't read filedesc at %lx",
352 (u_long)process.ps_fd);
353 goto cleanup;
354 }
355 if ((char *)process.ps_fd + offsetof(struct filedesc0,fd_dfiles)
356 == (char *)filed.fd_ofiles) {
357 filed.fd_ofiles = filed0.fd_dfiles;
358 filed.fd_ofileflags = filed0.fd_dfileflags;
359 } else {
360 size_t fsize;
361 char *tmp = reallocarray(filebuf,
362 filed.fd_nfiles, OFILESIZE);
363
364 fsize = filed.fd_nfiles * OFILESIZE;
365 if (tmp == NULL) {
366 _kvm_syserr(kd, kd->program, "realloc ofiles");
367 goto cleanup;
368 }
369 filebuf = tmp;
370 if (kvm_read(kd, (u_long)filed.fd_ofiles, filebuf,
371 fsize) != fsize) {
372 _kvm_err(kd, kd->program,
373 "can't read fd_ofiles");
374 goto cleanup;
375 }
376 filed.fd_ofiles = (void *)filebuf;
377 filed.fd_ofileflags = filebuf +
378 (filed.fd_nfiles * sizeof(struct file *));
379 }
380 process.ps_fd = &filed;
381
382 if (process.ps_textvp) {
383 if (buflen < esize)
384 goto done;
385 if (fill_file(kd, &kf, NULL, 0, process.ps_textvp,
386 &process, KERN_FILE_TEXT, process.ps_pid) == -1)
387 goto cleanup;
388 memcpy(where, &kf, esize);
389 where += esize;
390 buflen -= esize;
391 n++;
392 }
393 if (filed.fd_cdir) {
394 if (buflen < esize)
395 goto done;
396 if (fill_file(kd, &kf, NULL, 0, filed.fd_cdir,
397 &process, KERN_FILE_CDIR, process.ps_pid) == -1)
398 goto cleanup;
399 memcpy(where, &kf, esize);
400 where += esize;
401 buflen -= esize;
402 n++;
403 }
404 if (filed.fd_rdir) {
405 if (buflen < esize)
406 goto done;
407 if (fill_file(kd, &kf, NULL, 0, filed.fd_rdir,
408 &process, KERN_FILE_RDIR, process.ps_pid) == -1)
409 goto cleanup;
410 memcpy(where, &kf, esize);
411 where += esize;
412 buflen -= esize;
413 n++;
414 }
415 if (process.ps_tracevp) {
416 if (buflen < esize)
417 goto done;
418 if (fill_file(kd, &kf, NULL, 0, process.ps_tracevp,
419 &process, KERN_FILE_TRACE, process.ps_pid) == -1)
420 goto cleanup;
421 memcpy(where, &kf, esize);
422 where += esize;
423 buflen -= esize;
424 n++;
425 }
426
427 if (filed.fd_nfiles < 0 ||
428 filed.fd_lastfile >= filed.fd_nfiles ||
429 filed.fd_freefile > filed.fd_lastfile + 1) {
430 _kvm_err(kd, kd->program,
431 "filedesc corrupted at %lx for pid %d",
432 (u_long)process.ps_fd, process.ps_pid);
433 goto cleanup;
434 }
435
436 for (i = 0; i < filed.fd_nfiles; i++) {
437 if (buflen < esize)
438 goto done;
439 if ((fp = filed.fd_ofiles[i]) == NULL)
440 continue;
441 if (KREAD(kd, (u_long)fp, &file)) {
442 _kvm_err(kd, kd->program, "can't read file");
443 goto cleanup;
444 }
445 if (fill_file(kd, &kf, &file, (u_long)fp, NULL,
446 &process, i, process.ps_pid) == -1)
447 goto cleanup;
448 memcpy(where, &kf, esize);
449 where += esize;
450 buflen -= esize;
451 n++;
452 }
453 }
454 if (!matched) {
455 errno = ESRCH;
456 goto cleanup;
457 }
458 done:
459 *cnt = n;
460 free(filebuf);
461 return (kd->filebase);
462 cleanup:
463 free(filebuf);
464 return (NULL);
465 }
466
467 static int
fill_file(kvm_t * kd,struct kinfo_file * kf,struct file * fp,u_long fpaddr,struct vnode * vp,struct process * pr,int fd,pid_t pid)468 fill_file(kvm_t *kd, struct kinfo_file *kf, struct file *fp, u_long fpaddr,
469 struct vnode *vp, struct process *pr, int fd, pid_t pid)
470 {
471 struct ucred f_cred;
472
473 memset(kf, 0, sizeof(*kf));
474
475 kf->fd_fd = fd; /* might not really be an fd */
476
477 if (fp != NULL) {
478 /* Fill in f_cred */
479 if (KREAD(kd, (u_long)fp->f_cred, &f_cred)) {
480 _kvm_err(kd, kd->program, "can't read f_cred");
481 return (-1);
482 }
483
484 kf->f_fileaddr = PTRTOINT64(fpaddr);
485 kf->f_flag = fp->f_flag;
486 kf->f_iflags = fp->f_iflags;
487 kf->f_type = fp->f_type;
488 kf->f_count = fp->f_count;
489 kf->f_ucred = PTRTOINT64(fp->f_cred);
490 kf->f_uid = f_cred.cr_uid;
491 kf->f_gid = f_cred.cr_gid;
492 kf->f_ops = PTRTOINT64(fp->f_ops);
493 kf->f_offset = fp->f_offset;
494 kf->f_data = PTRTOINT64(fp->f_data);
495 kf->f_usecount = 0;
496
497 kf->f_rxfer = fp->f_rxfer;
498 kf->f_rwfer = fp->f_wxfer;
499 kf->f_seek = fp->f_seek;
500 kf->f_rbytes = fp->f_rbytes;
501 kf->f_wbytes = fp->f_wbytes;
502 } else if (vp != NULL) {
503 /* fake it */
504 kf->f_type = DTYPE_VNODE;
505 kf->f_flag = FREAD;
506 if (fd == KERN_FILE_TRACE)
507 kf->f_flag |= FWRITE;
508 kf->f_data = PTRTOINT64(vp);
509 }
510
511 /* information about the object associated with this file */
512 switch (kf->f_type) {
513 case DTYPE_VNODE: {
514 struct vnode vbuf;
515
516 if (KREAD(kd, (u_long)(fp ? fp->f_data : vp), &vbuf)) {
517 _kvm_err(kd, kd->program, "can't read vnode");
518 return (-1);
519 }
520 vp = &vbuf;
521
522 kf->v_un = PTRTOINT64(vp->v_un.vu_socket);
523 kf->v_type = vp->v_type;
524 kf->v_tag = vp->v_tag;
525 kf->v_flag = vp->v_flag;
526 kf->v_data = PTRTOINT64(vp->v_data);
527 kf->v_mount = PTRTOINT64(vp->v_mount);
528
529 if (vp->v_mount != NULL) {
530 struct mount mount;
531
532 if (KREAD(kd, (u_long)vp->v_mount, &mount)) {
533 _kvm_err(kd, kd->program, "can't read v_mount");
534 return (-1);
535 }
536
537 strlcpy(kf->f_mntonname, mount.mnt_stat.f_mntonname,
538 sizeof(kf->f_mntonname));
539 }
540
541 /* Fill in va_fsid, va_fileid, va_mode, va_size, va_rdev */
542 filestat(kd, kf, vp);
543 break;
544 }
545
546 case DTYPE_SOCKET: {
547 struct socket sock;
548 struct sosplice ssp;
549 struct protosw protosw;
550 struct domain domain;
551
552 if (KREAD(kd, (u_long)fp->f_data, &sock)) {
553 _kvm_err(kd, kd->program, "can't read socket");
554 return (-1);
555 }
556
557 kf->so_type = sock.so_type;
558 kf->so_state = sock.so_state;
559 kf->so_pcb = PTRTOINT64(sock.so_pcb);
560 if (KREAD(kd, (u_long)sock.so_proto, &protosw)) {
561 _kvm_err(kd, kd->program, "can't read protosw");
562 return (-1);
563 }
564 kf->so_protocol = protosw.pr_protocol;
565 if (KREAD(kd, (u_long)protosw.pr_domain, &domain)) {
566 _kvm_err(kd, kd->program, "can't read domain");
567 return (-1);
568 }
569 kf->so_family = domain.dom_family;
570 kf->so_rcv_cc = sock.so_rcv.sb_cc;
571 kf->so_snd_cc = sock.so_snd.sb_cc;
572 if (sock.so_sp) {
573 if (KREAD(kd, (u_long)sock.so_sp, &ssp)) {
574 _kvm_err(kd, kd->program, "can't read splice");
575 return (-1);
576 }
577 if (ssp.ssp_socket) {
578 kf->so_splice = PTRTOINT64(ssp.ssp_socket);
579 kf->so_splicelen = ssp.ssp_len;
580 } else if (ssp.ssp_soback) {
581 kf->so_splicelen = -1;
582 }
583 }
584 if (!sock.so_pcb)
585 break;
586 switch (kf->so_family) {
587 case AF_INET: {
588 struct inpcb inpcb;
589
590 if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
591 _kvm_err(kd, kd->program, "can't read inpcb");
592 return (-1);
593 }
594 kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
595 kf->inp_lport = inpcb.inp_lport;
596 kf->inp_laddru[0] = inpcb.inp_laddr.s_addr;
597 kf->inp_fport = inpcb.inp_fport;
598 kf->inp_faddru[0] = inpcb.inp_faddr.s_addr;
599 kf->inp_rtableid = inpcb.inp_rtableid;
600 if (sock.so_type == SOCK_RAW)
601 kf->inp_proto = inpcb.inp_ip.ip_p;
602 if (protosw.pr_protocol == IPPROTO_TCP) {
603 struct tcpcb tcpcb;
604 if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) {
605 _kvm_err(kd, kd->program,
606 "can't read tcpcb");
607 return (-1);
608 }
609 kf->t_rcv_wnd = tcpcb.rcv_wnd;
610 kf->t_snd_wnd = tcpcb.snd_wnd;
611 kf->t_snd_cwnd = tcpcb.snd_cwnd;
612 kf->t_state = tcpcb.t_state;
613 }
614 break;
615 }
616 case AF_INET6: {
617 struct inpcb inpcb;
618 #define s6_addr32 __u6_addr.__u6_addr32
619
620 if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
621 _kvm_err(kd, kd->program, "can't read inpcb");
622 return (-1);
623 }
624 kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
625 kf->inp_lport = inpcb.inp_lport;
626 kf->inp_laddru[0] = inpcb.inp_laddr6.s6_addr32[0];
627 kf->inp_laddru[1] = inpcb.inp_laddr6.s6_addr32[1];
628 kf->inp_laddru[2] = inpcb.inp_laddr6.s6_addr32[2];
629 kf->inp_laddru[3] = inpcb.inp_laddr6.s6_addr32[3];
630 kf->inp_fport = inpcb.inp_fport;
631 kf->inp_faddru[0] = inpcb.inp_laddr6.s6_addr32[0];
632 kf->inp_faddru[1] = inpcb.inp_faddr6.s6_addr32[1];
633 kf->inp_faddru[2] = inpcb.inp_faddr6.s6_addr32[2];
634 kf->inp_faddru[3] = inpcb.inp_faddr6.s6_addr32[3];
635 kf->inp_rtableid = inpcb.inp_rtableid;
636 if (sock.so_type == SOCK_RAW)
637 kf->inp_proto = inpcb.inp_ipv6.ip6_nxt;
638 if (protosw.pr_protocol == IPPROTO_TCP) {
639 struct tcpcb tcpcb;
640 if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) {
641 _kvm_err(kd, kd->program,
642 "can't read tcpcb");
643 return (-1);
644 }
645 kf->t_rcv_wnd = tcpcb.rcv_wnd;
646 kf->t_snd_wnd = tcpcb.snd_wnd;
647 kf->t_snd_cwnd = tcpcb.snd_cwnd;
648 kf->t_state = tcpcb.t_state;
649 }
650 break;
651 }
652 case AF_UNIX: {
653 struct unpcb unpcb;
654
655 if (KREAD(kd, (u_long)sock.so_pcb, &unpcb)) {
656 _kvm_err(kd, kd->program, "can't read unpcb");
657 return (-1);
658 }
659 kf->f_msgcount = unpcb.unp_msgcount;
660 kf->unp_conn = PTRTOINT64(unpcb.unp_conn);
661 kf->unp_refs = PTRTOINT64(
662 SLIST_FIRST(&unpcb.unp_refs));
663 kf->unp_nextref = PTRTOINT64(
664 SLIST_NEXT(&unpcb, unp_nextref));
665 kf->v_un = PTRTOINT64(unpcb.unp_vnode);
666 if (unpcb.unp_addr != NULL) {
667 struct mbuf mb;
668 struct sockaddr_un un;
669
670 if (KREAD(kd, (u_long)unpcb.unp_addr, &mb)) {
671 _kvm_err(kd, kd->program,
672 "can't read sockaddr_un mbuf");
673 return (-1);
674 }
675 if (KREAD(kd, (u_long)mb.m_data, &un)) {
676 _kvm_err(kd, kd->program,
677 "can't read sockaddr_un");
678 return (-1);
679 }
680
681 kf->unp_addr = PTRTOINT64(unpcb.unp_addr);
682 memcpy(kf->unp_path, un.sun_path, un.sun_len
683 - offsetof(struct sockaddr_un,sun_path));
684 }
685
686 break;
687 }
688 }
689 break;
690 }
691
692 case DTYPE_PIPE: {
693 struct pipe pipe;
694
695 if (KREAD(kd, (u_long)fp->f_data, &pipe)) {
696 _kvm_err(kd, kd->program, "can't read pipe");
697 return (-1);
698 }
699 kf->pipe_peer = PTRTOINT64(pipe.pipe_peer);
700 kf->pipe_state = pipe.pipe_state;
701 break;
702 }
703
704 case DTYPE_KQUEUE: {
705 struct kqueue kqi;
706
707 if (KREAD(kd, (u_long)fp->f_data, &kqi)) {
708 _kvm_err(kd, kd->program, "can't read kqi");
709 return (-1);
710 }
711 kf->kq_count = kqi.kq_count;
712 kf->kq_state = kqi.kq_state;
713 break;
714 }
715 }
716
717 /* per-process information for KERN_FILE_BY[PU]ID */
718 if (pr != NULL) {
719 kf->p_pid = pid;
720 kf->p_uid = pr->ps_ucred->cr_uid;
721 kf->p_gid = pr->ps_ucred->cr_gid;
722 kf->p_tid = -1;
723 strlcpy(kf->p_comm, pr->ps_comm, sizeof(kf->p_comm));
724 if (pr->ps_fd != NULL)
725 kf->fd_ofileflags = pr->ps_fd->fd_ofileflags[fd];
726 }
727
728 return (0);
729 }
730
731 mode_t
_kvm_getftype(enum vtype v_type)732 _kvm_getftype(enum vtype v_type)
733 {
734 mode_t ftype = 0;
735
736 switch (v_type) {
737 case VREG:
738 ftype = S_IFREG;
739 break;
740 case VDIR:
741 ftype = S_IFDIR;
742 break;
743 case VBLK:
744 ftype = S_IFBLK;
745 break;
746 case VCHR:
747 ftype = S_IFCHR;
748 break;
749 case VLNK:
750 ftype = S_IFLNK;
751 break;
752 case VSOCK:
753 ftype = S_IFSOCK;
754 break;
755 case VFIFO:
756 ftype = S_IFIFO;
757 break;
758 case VNON:
759 case VBAD:
760 break;
761 }
762
763 return (ftype);
764 }
765
766 static int
ufs_filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)767 ufs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
768 {
769 struct inode inode;
770 struct ufs1_dinode di1;
771
772 if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
773 _kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
774 return (-1);
775 }
776
777 if (KREAD(kd, (u_long)inode.i_din1, &di1)) {
778 _kvm_err(kd, kd->program, "can't read dinode at %p",
779 inode.i_din1);
780 return (-1);
781 }
782
783 inode.i_din1 = &di1;
784
785 kf->va_fsid = inode.i_dev & 0xffff;
786 kf->va_fileid = (long)inode.i_number;
787 kf->va_mode = inode.i_ffs1_mode;
788 kf->va_size = inode.i_ffs1_size;
789 kf->va_rdev = inode.i_ffs1_rdev;
790 kf->va_nlink = inode.i_ffs1_nlink;
791
792 return (0);
793 }
794
795 static int
ext2fs_filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)796 ext2fs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
797 {
798 struct inode inode;
799 struct ext2fs_dinode e2di;
800
801 if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
802 _kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
803 return (-1);
804 }
805
806 if (KREAD(kd, (u_long)inode.i_e2din, &e2di)) {
807 _kvm_err(kd, kd->program, "can't read dinode at %p",
808 inode.i_e2din);
809 return (-1);
810 }
811
812 inode.i_e2din = &e2di;
813
814 kf->va_fsid = inode.i_dev & 0xffff;
815 kf->va_fileid = (long)inode.i_number;
816 kf->va_mode = inode.i_e2fs_mode;
817 kf->va_size = inode.i_e2fs_size;
818 kf->va_rdev = 0; /* XXX */
819 kf->va_nlink = inode.i_e2fs_nlink;
820
821 return (0);
822 }
823
824 static int
msdos_filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)825 msdos_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
826 {
827 struct denode de;
828 struct msdosfsmount mp;
829
830 if (KREAD(kd, (u_long)VTODE(vp), &de)) {
831 _kvm_err(kd, kd->program, "can't read denode at %p", VTODE(vp));
832 return (-1);
833 }
834 if (KREAD(kd, (u_long)de.de_pmp, &mp)) {
835 _kvm_err(kd, kd->program, "can't read mount struct at %p",
836 de.de_pmp);
837 return (-1);
838 }
839
840 kf->va_fsid = de.de_dev & 0xffff;
841 kf->va_fileid = 0; /* XXX see msdosfs_vptofh() for more info */
842 kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type);
843 kf->va_size = de.de_FileSize;
844 kf->va_rdev = 0; /* msdosfs doesn't support device files */
845 kf->va_nlink = 1;
846
847 return (0);
848 }
849
850 static int
nfs_filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)851 nfs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
852 {
853 struct nfsnode nfsnode;
854
855 if (KREAD(kd, (u_long)VTONFS(vp), &nfsnode)) {
856 _kvm_err(kd, kd->program, "can't read nfsnode at %p",
857 VTONFS(vp));
858 return (-1);
859 }
860 kf->va_fsid = nfsnode.n_vattr.va_fsid;
861 kf->va_fileid = nfsnode.n_vattr.va_fileid;
862 kf->va_size = nfsnode.n_size;
863 kf->va_rdev = nfsnode.n_vattr.va_rdev;
864 kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type);
865 kf->va_nlink = nfsnode.n_vattr.va_nlink;
866
867 return (0);
868 }
869
870 static int
spec_filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)871 spec_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
872 {
873 struct specinfo specinfo;
874 struct vnode parent;
875
876 if (KREAD(kd, (u_long)vp->v_specinfo, &specinfo)) {
877 _kvm_err(kd, kd->program, "can't read specinfo at %p",
878 vp->v_specinfo);
879 return (-1);
880 }
881
882 vp->v_specinfo = &specinfo;
883
884 if (KREAD(kd, (u_long)vp->v_specparent, &parent)) {
885 _kvm_err(kd, kd->program, "can't read parent vnode at %p",
886 vp->v_specparent);
887 return (-1);
888 }
889
890 if (ufs_filestat(kd, kf, vp))
891 return (-1);
892
893 return (0);
894 }
895
896 static int
filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)897 filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
898 {
899 int ret = 0;
900
901 if (vp->v_type != VNON && vp->v_type != VBAD) {
902 switch (vp->v_tag) {
903 case VT_UFS:
904 case VT_MFS:
905 ret = ufs_filestat(kd, kf, vp);
906 break;
907 case VT_NFS:
908 ret = nfs_filestat(kd, kf, vp);
909 break;
910 case VT_EXT2FS:
911 ret = ext2fs_filestat(kd, kf, vp);
912 break;
913 case VT_ISOFS:
914 ret = _kvm_stat_cd9660(kd, kf, vp);
915 break;
916 case VT_MSDOSFS:
917 ret = msdos_filestat(kd, kf, vp);
918 break;
919 case VT_UDF:
920 ret = _kvm_stat_udf(kd, kf, vp);
921 break;
922 case VT_NTFS:
923 ret = _kvm_stat_ntfs(kd, kf, vp);
924 break;
925 case VT_NON:
926 if (vp->v_flag & VCLONE)
927 ret = spec_filestat(kd, kf, vp);
928 break;
929 default:
930 ret = -1;
931 break;
932 }
933 }
934 return (ret);
935 }
936