Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 12 Aug 2007 21:00:10 GMT
From:      Maxim Konovalov <maxim@macomnet.ru>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: bin/115430: rpc.statd core dumps if unable to mmap() /var/db/statd.status file
Message-ID:  <200708122100.l7CL0AxR090118@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/115430; it has been noted by GNATS.

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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200708122100.l7CL0AxR090118>