Subject: bin/8184: /usr/bin/join crashes with SIGSEGV
To: None <gnats-bugs@gnats.netbsd.org>
From: None <thesing@cs.uni-sb.de>
List: netbsd-bugs
Date: 08/10/1999 07:22:04
>Number:         8184
>Category:       bin
>Synopsis:       join crashes under certain circumstances due to a wrong memmove operation
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Aug 10 04:20:01 1999
>Last-Modified:
>Originator:     
>Organization:
=  Tel.: +49-681-302-5571          = Universitaet des Saarlandes =
=  Fax.: +49-681-302-3065          = Postfach 15 11 50           =
=  Compiler Research Group         = 66041 Saarbruecken          =
=  FB 14 - Informatik              = GERMANY                     =
>Release:        NetBSD-current 090899
>Environment:
System: NetBSD gargoyle.cs.uni-sb.de 1.4J NetBSD 1.4J (Gargoyle) #0: Sun Aug 8 21:39:47 CEST 1999 thesing@gargoyle.cs.uni-sb.de:/usr/src/sys/arch/i386/compile/Gargoyle i386


>Description:
 join crashes due to an access to an invalid memory location.
 Why this happens:
    join reads lines from a FILE via the fgetln function, which returns
    a pointer into the buffer allocated by the FILE stream and the length
    of the line.
    The line is then copied to a user allocated buffer via memmove.
    Since fgetln does not append a '\0' to the line it reads (and does
     not count it in the returned length) one additional byte has to be
     allocated for the user buffer, so the NUL char can be appended.
    Unfortunately, the memmove function is told to copy length+1 bytes from
    the internal buffer to the user buffer. In the rare circumstance, where
    the line ends exactly at the end of the internal FILE buffer (and the page
    following the buffer is not allocated ) reading this extra byte causes
    an access to an illegal page and join crashes.
>How-To-Repeat:
   Create input files which causes a line read to end exactly at the
   end of the internal buffer and do something like
   join -111 -211 -v2 a b
   I came across this, since /etc/security  dumped core. security uses join 
   to list the difference between e.g. suid files across invocations.
>Fix:
   The following patch should fix this problem (and also includes a minor
   correction for a call to memset, which uses the wrong size)

--- /usr/src/usr.bin/join/join.c.orig   Sun Dec 20 13:17:41 1998
+++ /usr/src/usr.bin/join/join.c        Tue Aug 10 12:37:17 1999
@@ -317,7 +317,7 @@
                        if ((F->set = realloc(F->set,
                            F->setalloc * sizeof(LINE))) == NULL)
                                enomem();
-                       memset(F->set + cnt, 0, 100 * sizeof(LINE *));
+                       memset(F->set + cnt, 0, 100 * sizeof(LINE));
                }
 
                /*
@@ -347,7 +347,7 @@
                            lp->linealloc * sizeof(char))) == NULL)
                                enomem();
                }
-               memmove(lp->line, bp, len+1);
+               memmove(lp->line, bp, len);
 
                /* Replace trailing newline, if it exists. */ 
                if (bp[len - 1] == '\n')

>Audit-Trail:
>Unformatted: