From nobody  Fri Jul 24 13:03:54 1998
Received: (from nobody@localhost)
          by hub.freebsd.org (8.8.8/8.8.8) id NAA19437;
          Fri, 24 Jul 1998 13:03:54 -0700 (PDT)
          (envelope-from nobody)
Message-Id: <199807242003.NAA19437@hub.freebsd.org>
Date: Fri, 24 Jul 1998 13:03:54 -0700 (PDT)
From: jhicks@glenatl.glenayre.com
To: freebsd-gnats-submit@freebsd.org
Subject: du throws SIGSEGV whenever '-c' option is used (at du.c:226)

>Number:         7393
>Category:       bin
>Synopsis:       du throws SIGSEGV whenever '-c' option is used (at du.c:226)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jul 24 13:10:01 PDT 1998
>Closed-Date:    Wed Jul 29 11:31:19 PDT 1998
>Last-Modified:  Wed Jul 29 11:31:56 PDT 1998
>Originator:     Jerry Hicks
>Release:        2.2.7-STABLE
>Organization:
Glenayre Electronics
>Environment:
FreeBSD jhicks.glenatl.glenayre.com 2.2.7-STABLE FreeBSD
2.2.7-STABLE #0: Fri Jul 24 11:14:56 EDT 1998     
root@jhicks.glenatl.glenayre.com:/usr/src/sys/compile/JHICKS  i386

>Description:
du.c (1.6.2.5)

du throws SIGSEGV whenever '-c' option is used (at du.c:226)

du.c:224
	if (cflag) {
		p = savedp->fts_parent;
		(void) printf("%ld\ttotal\n", howmany(p->fts_number, blocksize));
	}


(gdb) display *savedp
3: *savedp = {
	fts_cycle = 0xd0d0d0d0,
	fts_parent = 0xd0d0d0d0,
	fts_link = 0xd0d0d0d0,
	fts_number = -791621424,
	fts_pointer = 0xd0d0d0d0,
	fts_accpath = 0xd0d0d0d0 <Error reading address 0xd0d0d0d0: Invalid argument>, 
        fts_path = 0xd0d0d0d0 <Error reading address 0xd0d0d0d0: Invalid argument>, 
        fts_errno = -791621424, 
        fts_symfd = -791621424,
        fts_pathlen = 53456,
        fts_namelen = 53456,
        fts_ino = 3503345872,
        fts_dev = 3503345872,
        fts_nlink = 53456,
        fts_level = -12080,
        fts_info = 53456,
        fts_flags = 53456,
        fts_instr = 53456,
        fts_statp = 0xd0d0d0d0,
        fts_name = ""
}
(gdb) 


*/
>How-To-Repeat:
du -c .   (100% repeatable here)
>Fix:

>Release-Note:
>Audit-Trail:

From: dag-erli@ifi.uio.no (Dag-Erling Coidan =?iso-8859-1?Q?Sm=F8rgrav?= )
To: jhicks@glenatl.glenayre.com
Cc: freebsd-gnats-submit@FreeBSD.ORG
Subject: Re: bin/7393: du throws SIGSEGV whenever '-c' option is used (at du.c:226)
Date: 25 Jul 1998 23:02:17 +0200

 jhicks@glenatl.glenayre.com writes:
 > du throws SIGSEGV whenever '-c' option is used (at du.c:226)
 > 
 > du.c:224
 > 	if (cflag) {
 > 		p = savedp->fts_parent;
 > 		(void) printf("%ld\ttotal\n", howmany(p->fts_number, blocksize));
 > 	}
 > 
 > 
 > (gdb) display *savedp
 > 3: *savedp = {
 > 	fts_cycle = 0xd0d0d0d0,
 > 	fts_parent = 0xd0d0d0d0,
 > 	fts_link = 0xd0d0d0d0,
 > [...]
 
 This FTSENT is quite obviously totally fubar. Could you please provide
 some more information about the exact circumstances in which the bug
 manifested itself? I haven't succeeded in reproducing it on my
 machine. Do you still have (or could you produce) a core dump? If so,
 could you tar together the core dump, your (unstripped) du binary, and
 a description of the circumstances of the SIGSEGV, and put the tarball
 up somewhere where I can get it?
 
 DES
 -- 
 Dag-Erling Smrgrav - dag-erli@ifi.uio.no

From: Poul-Henning Kamp <phk@critter.freebsd.dk>
To: dag-erli@ifi.uio.no (Dag-Erling Coidan =?iso-8859-1?Q?Sm=F8rgrav?= )
Cc: freebsd-bugs@FreeBSD.ORG, freebsd-gnats-submit@FreeBSD.ORG
Subject: Re: bin/7393: du throws SIGSEGV whenever '-c' option is used (at du.c:226) 
Date: Sun, 26 Jul 1998 10:02:19 +0200

 > > du.c:224
 > > 	if (cflag) {
 > > 		p = savedp->fts_parent;
 > > 		(void) printf("%ld\ttotal\n", howmany(p->fts_number, blocksize));
 > > 	}
 > > 
 > > 
 > > (gdb) display *savedp
 > > 3: *savedp = {
 > > 	fts_cycle = 0xd0d0d0d0,
 > > 	fts_parent = 0xd0d0d0d0,
 > > 	fts_link = 0xd0d0d0d0,
 > > [...]
 > 
 > This FTSENT is quite obviously totally fubar. 
 
 This looks like malloc(3) usage mistake and a phkmalloc with the 'J' flag.
 
 Try to run it with electric fence or similar.
 
 --
 Poul-Henning Kamp             FreeBSD coreteam member
 phk@FreeBSD.ORG               "Real hackers run -current on their laptop."
 "ttyv0" -- What UNIX calls a $20K state-of-the-art, 3D, hi-res color terminal

From: Jerry Hicks <jhicks@glenatl.glenayre.com>
To: freebsd-gnats-submit@freebsd.org, jhicks@glenatl.glenayre.com
Cc:  Subject: Re: bin/7393: du throws SIGSEGV whenever '-c' option is used (at du.c:226)
Date: Tue, 28 Jul 1998 23:14:23 -0400

 Indeed, I confirmed with Dag-Colin that /etc/malloc.conf -> AJ on the
 affected system.
 
 Using efence, the reference to 'savedp' triggers a bus error at du.c:225
 
 savedp is assigned a value only if the loop started at du.c:186 and then
 only at the following line, where it is assigned the value of 'p' which
 comes from the 'fts_read()' function call.
 
 Ordinarily I would expect a compiler diagnostic to complain about the
 use of a possibly uninitialized variable ( fts_read() could return NULL
 the first time through? )
 
 Off to study fts_read() & Co.
 
 -----
 Jerry Hicks
 jhicks@glenatl.glenayre.com

From: dag-erli@ifi.uio.no (Dag-Erling Coidan =?iso-8859-1?Q?Sm=F8rgrav?= )
To: jhicks@glenatl.glenayre.com
Cc: freebsd-gnats-submit@freebsd.org
Subject: Re: bin/7393: nailed
Date: 29 Jul 1998 19:29:44 +0200

 On line 224 in /usr/src/usr.bin/du/du.c, there is the following piece
 of code which handles the -c flag:
 
     if (cflag) {
         p = savedp->fts_parent;
         (void) printf("%ld\ttotal\n", howmany(p->fts_number, blocksize));
     }
 
 It relies on the fact that the code in the while loop above saves the
 value of p in savedp at every iteration, so that at the end of it,
 savedp points to the FTSENT for the last entry in the root directory
 (i.e. the one passed on the command line), and savedp->fts_parent
 points to FTSENT for the root directory itself. However, this
 assumption is incorrect.
 
 The problem arises when du traverses the root directory the second
 time, i.e. on the way down. fts_read() notices a) that it's on the way
 down, and b) that there's nothing left to do. Because of a) it frees
 the current FTSENT, and because of b) it frees the parent (root)
 FTSENT as well, on line 403 in /usr/src/lib/libc/gen/fts.c:
 
     /* Move up to the parent node. */
     p = tmp->fts_parent;
     free(tmp);
 
     if (p->fts_level == FTS_ROOTPARENTLEVEL) {
         /*
          * Done; free everything up and set errno to 0 so the user
          * can distinguish between error and EOF.
          */
         free(p);
         errno = 0;
         return (sp->fts_cur = NULL);
     }
 
 This means that the -c code in du.c tries to dereference a garbage
 pointer which even if it were not garbage *points* to garbage. Since
 there's no more malloc() activity after the last fts_read() until the
 end of the program, this kinda works - unless you have J in your
 malloc options, since in that case free() will overwrite the freed
 memory with garbage, to catch bugs like this one :)
 
 Conclusion: the -c option to du is broken as designed, since it relies
 on the contents of dynamically allocated memory which has been
 released.
 
 Now, off to write a fix for this.
 
 DES
 -- 
 Dag-Erling Smrgrav - dag-erli@ifi.uio.no
State-Changed-From-To: open->closed 
State-Changed-By: des 
State-Changed-When: Wed Jul 29 11:31:19 PDT 1998 
State-Changed-Why:  
Fixed in -stable and -current. 
>Unformatted:
X-Send-Pr-Version: www-1.0


