From timur@FreeBSD.org  Sun Aug 12 01:31:32 2007
Return-Path: <timur@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 2657716A41B
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 12 Aug 2007 01:31:32 +0000 (UTC)
	(envelope-from timur@FreeBSD.org)
Received: from mail.bat.ru (dzokonda.xs4all.nl [194.109.164.75])
	by mx1.freebsd.org (Postfix) with ESMTP id 7934013C46E
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 12 Aug 2007 01:31:31 +0000 (UTC)
	(envelope-from timur@FreeBSD.org)
Received: from timur.home.bat.ru (account timur [192.168.0.4] verified)
  by mail.bat.ru (CommuniGate Pro SMTP 4.2.7)
  with ESMTP id 539689 for FreeBSD-gnats-submit@freebsd.org; Sun, 12 Aug 2007 03:33:27 +0200
Message-Id: <1186882289.87499@timur.home.bat.ru>
Date: Sun, 12 Aug 2007 03:31:29 +0200
From: "Timur I. Bakeyev" <timur@FreeBSD.org>
To: "FreeBSD gnats submit" <FreeBSD-gnats-submit@freebsd.org>
Subject: rpc.statd core dumps if unable to mmap() /var/db/statd.status file
X-Send-Pr-Version: gtk-send-pr 0.4.8 
X-GNATS-Notify:

>Number:         115430
>Category:       bin
>Synopsis:       [rpc.statd] rpc.statd core dumps if unable to mmap() /var/db/statd.status file
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Aug 12 01:40:01 GMT 2007
>Closed-Date:    Sun Aug 12 21:52:05 GMT 2007
>Last-Modified:  Mon Aug 20 13:10:07 GMT 2007
>Originator:     Timur I. Bakeyev
>Release:        FreeBSD 6.2-STABLE i386
>Organization:
>Environment:


System: FreeBSD 6.2-STABLE #0: Tue Jun 26 16:02:16 CEST 2007
    root@timur.home.bat.ru:/usr/src/sys/i386/compile/COMMON



>Description:


Somehow with my recent enough build rpc.statd is unable to mmap()
"/var/db/statd.status" file and core dumps.  Possibly, the failure of
mmap() is fixed in latest STABLE, but this problem revealed a race
condition in the rpc.statd. Here is the stack trace and piece of offending code:

timur# gdb `which rpc.statd` rpc.statd.0.1092.core 
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 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 conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd"...
Core was generated by `rpc.statd'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /usr/lib/librpcsvc.so.3...done.
Loaded symbols for /usr/lib/librpcsvc.so.3
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /libexec/ld-elf.so.1...done.
Loaded symbols for /libexec/ld-elf.so.1
#0  0x08049531 in init_file (filename=0x804a880 "/var/db/statd.status") at /usr/src/usr.sbin/rpc.statd/file.c:170
(gdb) l 150
145
146       /* try to open existing file - if not present, create one             */
147       status_fd = open(filename, O_RDWR);
148       if ((status_fd < 0) && (errno == ENOENT))
149       {
150         status_fd = open(filename, O_RDWR | O_CREAT, 0644);
151         new_file = TRUE;
152       }
153       if (status_fd < 0)
154         errx(1, "unable to open status file %s", filename);
155
156       /* File now open.  mmap() it, with a generous size to allow for       */
157       /* later growth, where we will extend the file but not re-map it.     */
158       status_info = (FileLayout *)
159         mmap(NULL, 0x10000000, PROT_READ | PROT_WRITE, MAP_SHARED, status_fd, 0);
160
161       if (status_info == (FileLayout *) MAP_FAILED)
162         warn("unable to mmap() status file");
163
164       status_file_len = lseek(status_fd, 0L, SEEK_END);
165
166       /* If the file was not newly created, validate the contents, and if   */
167       /* defective, re-create from scratch.                                 */
168       if (!new_file)
169       {
170         if ((status_file_len < HEADER_LEN) || (status_file_len
171           < (HEADER_LEN + sizeof(HostInfo) * status_info->noOfHosts)) )
172         {
173           warnx("status file is corrupt");
174           new_file = TRUE;

On line 170 we have a guardian condition:

170         if ((status_file_len < HEADER_LEN) ||

But it doesn't work after second invokation of rpc.statd, when status
file was already created.

statd.h:#define HEADER_LEN (sizeof(FileLayout) - sizeof(HostInfo))

(gdb) p status_file_len 
$1 = 256
(gdb) p sizeof(FileLayout) - sizeof(HostInfo)
$2 = 256

As it's seen on line 161, in case of mmap() failure status_info variable
takes special value MAP_FAILED:

mman.h:#define MAP_FAILED       ((void *)-1) 

And a warning issued. Possibly, such a failure shouldn't be a fatal
event, we just lose some speed in processing. But the fact of a failure
isn't taken into account on line 171, when we try to dereference
status_info unconditionally:

   sizeof(HostInfo) * status_info->noOfHosts

which leads to the core dump. I don't think, this bug is exploitable,
but definetly, it have to be fixed one way or another.



>How-To-Repeat:


I wish I know what's wrong with mmap() function in my build. If it is
reproduced then rpc.statd will crash for sure. But the bug is visible
on a first glance.




>Fix:


Simplest solution would be to croak on mmap() failure, but possibly
it's too taugh. 

The better approach would be to have a branch in the code, which
executed only when mmap() is succeded.


>Release-Note:
>Audit-Trail:

From: Maxim Konovalov <maxim@macomnet.ru>
To: "Timur I. Bakeyev" <timur@freebsd.org>
Cc: bug-followup@freebsd.org, truckman@freebsd.org
Subject: Re: bin/115430: rpc.statd core dumps if unable to mmap()
 /var/db/statd.status file
Date: Mon, 13 Aug 2007 00:23:23 +0400 (MSD)

 [...]
 > >Release:        FreeBSD 6.2-STABLE i386
 > >Organization:
 > >Environment:
 >
 > >Description:
 >
 > Somehow with my recent enough build rpc.statd is unable to mmap() "/var/db/statd.status" file and core dumps. Possibly, the failure of mmap() is fixed in latest STABLE, but this problem revealed a race condition in the rpc.statd. Here is the stack trace and piece of offending code:
 >
 > timur# gdb `which rpc.statd` rpc.statd.0.1092.core
 > GNU gdb 6.1.1 [FreeBSD]
 > Copyright 2004 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 conditions.
 > Type "show copying" to see the conditions.
 > There is absolutely no warranty for GDB.  Type "show warranty" for details.
 > This GDB was configured as "i386-marcel-freebsd"...
 > Core was generated by `rpc.statd'.
 > Program terminated with signal 11, Segmentation fault.
 > Reading symbols from /usr/lib/librpcsvc.so.3...done.
 > Loaded symbols for /usr/lib/librpcsvc.so.3
 > Reading symbols from /lib/libc.so.6...done.
 > Loaded symbols for /lib/libc.so.6
 > Reading symbols from /libexec/ld-elf.so.1...done.
 > Loaded symbols for /libexec/ld-elf.so.1
 > #0  0x08049531 in init_file (filename=0x804a880 "/var/db/statd.status") at /usr/src/usr.sbin/rpc.statd/file.c:170
 > (gdb) l 150
 > 145
 > 146       /* try to open existing file - if not present, create one             */
 > 147       status_fd = open(filename, O_RDWR);
 > 148       if ((status_fd < 0) && (errno == ENOENT))
 > 149       {
 > 150         status_fd = open(filename, O_RDWR | O_CREAT, 0644);
 > 151         new_file = TRUE;
 > 152       }
 > 153       if (status_fd < 0)
 > 154         errx(1, "unable to open status file %s", filename);
 > 155
 > 156       /* File now open.  mmap() it, with a generous size to allow for       */
 > 157       /* later growth, where we will extend the file but not re-map it.     */
 > 158       status_info = (FileLayout *)
 > 159         mmap(NULL, 0x10000000, PROT_READ | PROT_WRITE, MAP_SHARED, status_fd, 0);
 > 160
 > 161       if (status_info == (FileLayout *) MAP_FAILED)
 > 162         warn("unable to mmap() status file");
 > 163
 > 164       status_file_len = lseek(status_fd, 0L, SEEK_END);
 > 165
 > 166       /* If the file was not newly created, validate the contents, and if   */
 > 167       /* defective, re-create from scratch.                                 */
 > 168       if (!new_file)
 > 169       {
 > 170         if ((status_file_len < HEADER_LEN) || (status_file_len
 > 171           < (HEADER_LEN + sizeof(HostInfo) * status_info->noOfHosts)) )
 > 172         {
 > 173           warnx("status file is corrupt");
 > 174           new_file = TRUE;
 >
 > On line 170 we have a guardian condition:
 >
 > 170         if ((status_file_len < HEADER_LEN) ||
 >
 > But it doesn't work after second invokation of rpc.statd, when status file was already created.
 >
 > statd.h:#define HEADER_LEN (sizeof(FileLayout) - sizeof(HostInfo))
 >
 > (gdb) p status_file_len
 > $1 = 256
 > (gdb) p sizeof(FileLayout) - sizeof(HostInfo)
 > $2 = 256
 >
 > As it's seen on line 161, in case of mmap() failure status_info variable takes special value MAP_FAILED:
 >
 > mman.h:#define MAP_FAILED       ((void *)-1)
 >
 > And a warning issued. Possibly, such a failure shouldn't be a fatal event, we just loose some speed in processing. But the fact of a failure isn't taken into account on line 171, when we try to dereference status_info unconditionally:
 >
 >    sizeof(HostInfo) * status_info->noOfHosts
 >
 > which leads to the core dump. I don't think, this bug is
 > exploitable, but definetly, it have to be fixed one way or another.
 >
 > >How-To-Repeat:
 >
 > I wish I know what's wrong with mmap() functino in my build. If it
 > is reproduced then rpc.statd will crash for sure. But the bug is
 > visible on a first glance.
 >
 Could it be fixed by the latest truckman@ work?
 
 -- 
 Maxim Konovalov

From: Don Lewis <truckman@FreeBSD.org>
To: maxim@macomnet.ru
Cc: timur@FreeBSD.org, bug-followup@FreeBSD.org
Subject: Re: bin/115430: rpc.statd core dumps if unable to mmap()
 /var/db/statd.status file
Date: Sun, 12 Aug 2007 14:25:26 -0700 (PDT)

 On 13 Aug, Maxim Konovalov wrote:
 
 > [...]
 >> >Release:        FreeBSD 6.2-STABLE i386
 >> >Organization:
 >> >Environment:
 >>
 >> >Description:
 >>
 >> Somehow with my recent enough build rpc.statd is unable to mmap() "/var/db/statd.status" file and core dumps. Possibly, the failure of mmap() is fixed in latest STABLE, but this problem revealed a race condition in the rpc.statd. Here is the stack trace and piece of offending code:
 >>
 [snip]
 >>
 > Could it be fixed by the latest truckman@ work?
 
 This problem should be fixed for 6.2-STABLE by
 usr.sbin/rpc.statd/statd.c 1.12.8.2 (Sun Aug 12 01:46:19 2007 UTC) and
 for 7.0-CURRENT by statd.c 1.15 (Sun Aug 5 16:33:06 2007 UTC).
 
 The warn() call should probably be changed to err() because the
 implemention does not have code to handle the case where mmap() fails.
 
 
State-Changed-From-To: open->closed 
State-Changed-By: truckman 
State-Changed-When: Sun Aug 12 21:49:38 UTC 2007 
State-Changed-Why:  
The mmap() failure is fixed in: 
usr.sbin/rpc.statd/statd.c 1.15 (Sun Aug 5 16:33:06 2007 UTC) -      HEAD 
usr.sbin/rpc.statd/statd.c 1.12.8.2 (Sun Aug 12 01:46:19 2007 UTC) - RELENG_6 

http://www.freebsd.org/cgi/query-pr.cgi?pr=115430 

From: "Timur I. Bakeyev" <timur@freebsd.org>
To: bug-followup@freebsd.org
Cc: truckman@freebsd.org, Maxim Konovalov <maxim@macomnet.ru>
Subject: Re: bin/115430: [rpc.statd] rpc.statd core dumps if unable to mmap() /var/db/statd.status file
Date: Mon, 13 Aug 2007 00:24:08 +0200

 On Sun, Aug 12, 2007 at 09:52:04PM +0000, truckman@FreeBSD.org wrote:
 > Synopsis: [rpc.statd] rpc.statd core dumps if unable to mmap() /var/db/statd.status file
 > 
 > State-Changed-Why: 
 > The mmap() failure is fixed in:
 >   usr.sbin/rpc.statd/statd.c 1.15 (Sun Aug 5 16:33:06 2007 UTC) -      HEAD
 >   usr.sbin/rpc.statd/statd.c 1.12.8.2 (Sun Aug 12 01:46:19 2007 UTC) - RELENG_6
 
 No, I don't think the bug is fixed. Your fix addressed the reason why
 mmap() fails to me, thanks. But the errorneous execution flow in a
 file.c still in place - should, by any other reason, mmap() fails for
 rpc.statd again - we'll get another perfect coredump to fix.
 
 Patching code around the faulty condition to prevent it to be trigged is
 never safe - it'll always be another reason for it to fail. If you so
 confident that your fix makes it impossible for mmap() to fail in the
 init_file() - replace:
 
 warn("unable to mmap() status file");
 
 with err(). Still I prefer cleaner solution, which just doesn't try to
 dereference bogus pointer.
 
 Regards,
 Timur.

From: Don Lewis <truckman@FreeBSD.org>
To: timur@FreeBSD.org
Cc: bug-followup@FreeBSD.org, maxim@macomnet.ru
Subject: Re: bin/115430: [rpc.statd] rpc.statd core dumps if unable to
 mmap() /var/db/statd.status file
Date: Sun, 12 Aug 2007 16:38:35 -0700 (PDT)

 On 13 Aug, Timur I. Bakeyev wrote:
 > On Sun, Aug 12, 2007 at 09:52:04PM +0000, truckman@FreeBSD.org wrote:
 >> Synopsis: [rpc.statd] rpc.statd core dumps if unable to mmap() /var/db/statd.status file
 >> 
 >> State-Changed-Why: 
 >> The mmap() failure is fixed in:
 >>   usr.sbin/rpc.statd/statd.c 1.15 (Sun Aug 5 16:33:06 2007 UTC) -      HEAD
 >>   usr.sbin/rpc.statd/statd.c 1.12.8.2 (Sun Aug 12 01:46:19 2007 UTC) - RELENG_6
 > 
 > No, I don't think the bug is fixed. Your fix addressed the reason why
 > mmap() fails to me, thanks. But the errorneous execution flow in a
 > file.c still in place - should, by any other reason, mmap() fails for
 > rpc.statd again - we'll get another perfect coredump to fix.
 > 
 > Patching code around the faulty condition to prevent it to be trigged is
 > never safe - it'll always be another reason for it to fail. If you so
 > confident that your fix makes it impossible for mmap() to fail in the
 > init_file() - replace:
 > 
 > warn("unable to mmap() status file");
 > 
 > with err(). Still I prefer cleaner solution, which just doesn't try to
 > dereference bogus pointer.
 
 I've already made a request to re@ to replace warn() with err(). There's
 no reason for execution to continue if mmap() were to somehow fail, and
 failure of mmap() is not a good reason to drop a core file.
 
 That said, I just looked through all the possible error returns on the
 mmap(2) man page, and none of the other failures look possible with the
 rpc.statd code.  I suppose mmap() could still fail if the sysadmin set 
 vm.max_proc_mmap to a small value, but that would likely break all sorts
 of other things.
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/115430: commit references a PR
Date: Mon, 13 Aug 2007 15:04:46 +0000 (UTC)

 truckman    2007-08-13 15:04:39 UTC
 
   FreeBSD src repository
 
   Modified files:
     usr.sbin/rpc.statd   file.c 
   Log:
   If the mmap() call in rpc.statd fails, rpc.statd prints a warning
   message and then dumps core because the subsequent code assumes that
   mmap() succeeded.  Since rpc.statd does not have fallback code to
   implement the functionality needed to operate on the status file if
   it is not memory mapped, rpc.statd should use err() to force the process
   to exit if the mmap() call fails.
   
   PR:             bin/115430 (mmap() failure previously fixed in statd.c 1.15)
   Approved by:    re (kensmith)
   MFC after:      1 week
   
   Revision  Changes    Path
   1.8       +1 -1      src/usr.sbin/rpc.statd/file.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/115430: commit references a PR
Date: Mon, 20 Aug 2007 13:00:52 +0000 (UTC)

 truckman    2007-08-20 13:00:48 UTC
 
   FreeBSD src repository
 
   Modified files:        (Branch: RELENG_6)
     usr.sbin/rpc.statd   file.c 
   Log:
   MFC file.c 1.8
   
     If the mmap() call in rpc.statd fails, rpc.statd prints a warning
     message and then dumps core because the subsequent code assumes that
     mmap() succeeded.  Since rpc.statd does not have fallback code to
     implement the functionality needed to operate on the status file if
     it is not memory mapped, rpc.statd should use err() to force the process
     to exit if the mmap() call fails.
   
   PR:             bin/115430 (mmap() failure previously fixed in statd.c 1.12.8.2)
   
   Revision  Changes    Path
   1.7.10.1  +1 -1      src/usr.sbin/rpc.statd/file.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 
>Unformatted:
