Bug 45391

Summary: /usr/bin/cmp coredumps while reading a faulty CD-R
Product: Base System Reporter: Cinek <cinekcvs>
Component: i386Assignee: David Schultz <das>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 4.7-RELEASE   
Hardware: Any   
OS: Any   

Description Cinek 2002-11-18 09:50:01 UTC
When using the command /usr/bin/cmp from the default
FreeBSD-4.7 package, it is possible to produce a coredump.
It seems, there is a problem in handling errors while
reading faulty files. It happened to me while I was comparing
two files which I suspected to be dupes on my CD-Rs.

I guess it will not help much when I post the output
from gdb without symbol tables, but let's try at least:

----------------------------------------------------------------------
GNU gdb 4.18 (FreeBSD)
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you =
are
welcome to change it and/or distribute copies of it under certain conditi=
ons.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for detail=
s.
This GDB was configured as "i386-unknown-freebsd"...
(no debugging symbols found)...
Core was generated by `cmp'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /usr/lib/libc.so.4...(no debugging symbols found)...=
done.
Reading symbols from /usr/libexec/ld-elf.so.1...(no debugging symbols=20
found)...
done.
#0  0x8048e17 in open ()
(gdb) bt
#0  0x8048e17 in open ()
#1  0xbfbffb0d in ?? ()
#2  0x8048bc1 in open ()
#3  0x8048731 in open ()
(gdb) info frame
Stack level 0, frame at 0xbfbff840:
 eip =3D 0x8048e17 in open; saved eip 0x8048bc1
 (FRAMELESS), called by frame at 0xbfbff840
 Arglist at 0xbfbff840, args:
 Locals at 0xbfbff840, Previous frame's sp is 0x0
 Saved registers:
  ebp at 0xbfbff840, eip at 0xbfbff844
(gdb) info sharedlibrary
=46rom        To          Syms Read   Shared Object Library
0x28067000  0x280fec78  Yes         /usr/lib/libc.so.4
0x2804a000  0x2805e210  Yes         /usr/libexec/ld-elf.so.1
----------------------------------------------------------------------

Fix: 

There is no fix.
How-To-Repeat:         1) You need two copies of files. One on Your hard-disk,
           the other one on a _almost_ unreadable CD(R).
           (That might be somehow difficult.)
        2) Start the following command:
           cmp locally_stored_file same_file_on_unreadable_cd
Comment 1 Bruce Evans 2002-11-18 11:21:06 UTC
> >Description:
> When using the command /usr/bin/cmp from the default
> FreeBSD-4.7 package, it is possible to produce a coredump.
> It seems, there is a problem in handling errors while
> reading faulty files. It happened to me while I was comparing
> two files which I suspected to be dupes on my CD-Rs.

I think there is a problem with mmap() on files with i/o errors in
them.  Pages should not be mapped if some part of them is unreadable,
and this should result in the application getting signals.  cmp makes
no attempt to handle signals.

> I guess it will not help much when I post the output
> from gdb without symbol tables, but let's try at least:

Not much, but you might be able to see that the fauilting instruction
is an ordinary memory access, which would indicate that the problem is
just unmapped memory.

Bruce
Comment 2 Cinek 2002-11-18 17:16:37 UTC
On Monday 18 November 2002 12:21, Bruce Evans wrote:

> I think there is a problem with mmap() on files with i/o errors in
> them.  Pages should not be mapped if some part of them is unreadable,
> and this should result in the application getting signals.  cmp makes
> no attempt to handle signals.

I see. I guess I cannot help much about it.

> Not much, but you might be able to see that the fauilting instruction
> is an ordinary memory access, which would indicate that the problem is
> just unmapped memory.

I have disassembled the part and indeed a memory access is causing
the segfault. I will paste some lines here:

Program terminated with signal 11, Segmentation fault.
 0x8048e17 in open ()

0x8048e14 <open+1904>:  mov    0xfffffff8(%ebp),%edx
0x8048e17 <open+1907>:  mov    (%edx),%dl
0x8048e19 <open+1909>:  mov    %dl,0xffffffff(%ebp)
0x8048e1c <open+1912>:  mov    0xfffffff4(%ebp),%eax
0x8048e1f <open+1915>:  cmp    (%eax),%dl
0x8048e21 <open+1917>:  je     0x8048eb7 <open+2067>
0x8048e27 <open+1923>:  cmpl   $0x0,0x804a80c
0x8048e2e <open+1930>:  je     0x8048e60 <open+1980>

Martin
Comment 3 dschultz 2003-01-25 01:17:13 UTC
> >Number:         45391
> >Category:       i386
> >Synopsis:       /usr/bin/cmp coredumps while reading a faulty CD-R
...
> >Description:
> When using the command /usr/bin/cmp from the default
> FreeBSD-4.7 package, it is possible to produce a coredump.
> It seems, there is a problem in handling errors while
> reading faulty files. It happened to me while I was comparing
> two files which I suspected to be dupes on my CD-Rs.

This is not the first time this buglet has confused someone, so
here's a simple fix.  The diff is against -CURRENT, but it can be
applied to -STABLE as well.


Index: usr.bin/cmp/regular.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/cmp/regular.c,v
retrieving revision 1.17
diff -u -u -r1.17 regular.c
--- usr.bin/cmp/regular.c	2002/07/28 15:13:17	1.17
+++ usr.bin/cmp/regular.c	2003/01/25 01:14:02
@@ -45,7 +45,9 @@
 #include <sys/stat.h>
 
 #include <err.h>
+#include <errno.h>
 #include <limits.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -54,6 +56,7 @@
 #include "extern.h"
 
 static u_char *remmap(u_char *, int, off_t);
+static void segv_handler(int);
 #define MMAP_CHUNK (8*1024*1024)
 
 #define ROUNDPAGE(i) ((i) & ~pagemask)
@@ -67,6 +70,7 @@
 	int dfound;
 	off_t pagemask, off1, off2;
 	size_t pagesize;
+	struct sigaction act, oact;
 
 	if (skip1 > len1)
 		eofmsg(file1);
@@ -78,6 +82,12 @@
 	if (sflag && len1 != len2)
 		exit(DIFF_EXIT);
 
+	sigemptyset(&act.sa_mask);
+	act.sa_flags = SA_NODEFER;
+	act.sa_handler = segv_handler;
+	if (sigaction(SIGSEGV, &act, &oact))
+		err(ERR_EXIT, "sigaction");
+
 	pagesize = getpagesize();
 	pagemask = (off_t)pagesize - 1;
 	off1 = ROUNDPAGE(skip1);
@@ -138,6 +148,9 @@
 	munmap(m1, MMAP_CHUNK);
 	munmap(m2, MMAP_CHUNK);
 
+	if (sigaction(SIGSEGV, &oact, NULL))
+		err(ERR_EXIT, "sigaction");
+
 	if (len1 != len2)
 		eofmsg (len1 > len2 ? file2 : file1);
 	if (dfound)
@@ -154,4 +167,10 @@
 		return (NULL);
 	madvise(mem, MMAP_CHUNK, MADV_SEQUENTIAL);
 	return (mem);
+}
+
+static void
+segv_handler(int sig) {
+
+	errc(ERR_EXIT, EIO, "(caught SIGSEGV)");
 }
Comment 4 David Schultz freebsd_committer freebsd_triage 2003-02-24 09:24:32 UTC
Responsible Changed
From-To: freebsd-bugs->das

Over to me.
Comment 5 David Schultz freebsd_committer freebsd_triage 2003-02-26 06:45:22 UTC
State Changed
From-To: open->closed

Fixed in -CURRENT, src/usr.bin/cmp regular.c,v 1.18. 
Since this is mostly a cosmetic change, I don't intend 
to MFC it unless someone thinks it's important.