Subject: bin/36078: pstat segfaults when used for kernel core file with -v and -T options
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: None <antiright@gmail.com>
List: netbsd-bugs
Date: 03/24/2007 11:20:01
>Number:         36078
>Category:       bin
>Synopsis:       pstat segfaults when used for kernel core file with -v and -T options
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Mar 24 11:20:00 +0000 2007
>Originator:     Jeffrey Bedard
>Release:        4.99.16 (amd64)
>Organization:
>Environment:
NetBSD antiright.dyndns.org 4.99.16 NetBSD 4.99.16 (AR) #7: Thu Mar 22 08:41:32 EDT 2007  root@antiright.dyndns.org:/usr/sources/src-current/sys/arch/amd64/compile/AR amd64
>Description:
pstat segfaults when used on a kernel core file when the -T or -v options are specified.  This segfault occurs in kinfo_vnodes(), according to gdb.


(gdb) r -M netbsd.0.core -T
Starting program: /usr/sbin/pstat -M netbsd.0.core -T
...
230/3404 files

Program received signal SIGSEGV, Segmentation fault.
0x000000000040240b in kinfo_vnodes ()

(gdb) r -M netbsd.0.core -v
...
Starting program: /usr/sbin/pstat -M netbsd.0.core -v
...
Program received signal SIGSEGV, Segmentation fault.
0x000000000040240b in kinfo_vnodes ()

(gdb) bt
#0  0x000000000040240b in kinfo_vnodes ()
#1  0x00000000004024ba in loadvnodes ()
#2  0x0000000000402688 in vnodemode ()
#3  0x0000000000402f7a in main ()

Running with pstat compiled with -g3:

0x0000000000402e99 in kinfo_vnodes (avnodes=0x7f7fffffdfbc) at pstat.c:744
744                     TAILQ_FOREACH(vp, &mount.mnt_vnodelist, v_mntvnodes) {



>How-To-Repeat:
pstat -M netbsd.0.core -v
pstat -M netbsd.0.core -T

>Fix:
vp->v_mntvnodes.tqe_next within TAILQ_FOREACH is the source of the segfault.  vp is uninitialized before this call.

patch:


--- pstat.c.orig        2007-03-24 06:14:47.000000000 -0400
+++ pstat.c     2007-03-24 07:12:33.000000000 -0400
@@ -731,25 +731,30 @@
        struct vnode *vp, vnode;
        char *beg, *bp, *ep;
        int numvnodes;
-
+
        KGET(V_NUMV, numvnodes);
        if ((bp = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL)
                err(1, "malloc");
        beg = bp;
        ep = bp + (numvnodes + 20) * (VPTRSZ + VNODESZ);
        KGET(V_MOUNTLIST, mountlist);
+
+       vp=(struct vnode *)bp;
+
        for (mp = mountlist.cqh_first;;
            mp = mount.mnt_list.cqe_next) {
                KGET2(mp, &mount, sizeof(mount), "mount entry");
-               TAILQ_FOREACH(vp, &mount.mnt_vnodelist, v_mntvnodes) {
-                       KGET2(vp, &vnode, sizeof(vnode), "vnode");
-                       if (bp + VPTRSZ + VNODESZ > ep)
+               if(vp->v_mntvnodes.tqe_next != NULL) {
+                       TAILQ_FOREACH(vp, &mount.mnt_vnodelist, v_mntvnodes) {
+                               KGET2(vp, &vnode, sizeof(vnode), "vnode");
+                               if (bp + VPTRSZ + VNODESZ > ep)
                                /* XXX - should realloc */
-                               errx(1, "no more room for vnodes");
-                       memmove(bp, &vp, VPTRSZ);
-                       bp += VPTRSZ;
-                       memmove(bp, &vnode, VNODESZ);
-                       bp += VNODESZ;
+                                       errx(1, "no more room for vnodes");
+                               memmove(bp, &vp, VPTRSZ);
+                               bp += VPTRSZ;
+                               memmove(bp, &vnode, VNODESZ);
+                               bp += VNODESZ;
+                       }
                }
                if (mp == mountlist.cqh_last)
                        break;