Subject: kern/3170: NFS server can crash the system
To: None <gnats-bugs@gnats.netbsd.org>
From: None <mhitch@gemini.oscs.montana.edu>
List: netbsd-bugs
Date: 01/30/1997 19:25:50
>Number: 3170
>Category: kern
>Synopsis: NFS server can crash due to incorrect loop test
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Jan 30 18:35:03 1997
>Last-Modified:
>Originator: Michael L. Hitch
>Organization:
Montana State University
>Release: 1.2_BETA
>Environment:
System: NetBSD amiga2.oscs.montana.edu 1.2B NetBSD 1.2B (ZEUS) #970120X-0: Mon Jan 20 17:56:34 MST 1997 mhitch@amiga2.oscs.montana.edu:/work/tmp/src/sys/arch/amiga/compile/ZEUS amiga
>Description:
The NFS server can crash in nfs_readdir() under the right condition. A
buffer is allocated for reading the requested directory. If the buffer
happens to end on a page boundary and the following page is invalid,
nfs_readdir() may attempt to access the invalid page at the end of the
buffer. This occurs because a reference through a pointer to the buffer
is done before doing a test for the end of the buffer.
>How-To-Repeat:
Do the right NFS directory read at the right time :-). I do not know how
to duplicate the problem; I was doing a find on an nfs-mounted file system
when the nfs server crashed. The server continued to crash after rebooting
until I rebooted the client. After locating where the crash occurred and
examining the code, I was able to fix the problem and added a check to
print a message when the original code would have referenced the invalid
page. I am able to reliably hit the right conditions which would have
caused the crash.
>Fix:
Change the code sequence in the while loop to test for the end of the loop
before accessing the directory data:
--- /usr/src/sys/nfs/nfs_serv.c Wed Dec 11 05:21:15 1996
+++ ./nfs_serv.c Thu Jan 30 18:56:40 1997
@@ -2804,8 +2804,8 @@
dp = (struct dirent *)cpos;
cookiep = cookies;
- while ((dp->d_fileno == 0 || dp->d_type == DT_WHT)
- && cpos < cend && ncookies > 0) {
+ while (cpos < cend && ncookies > 0
+ && (dp->d_fileno == 0 || dp->d_type == DT_WHT)) {
cpos += dp->d_reclen;
dp = (struct dirent *)cpos;
cookiep++;
>Audit-Trail:
>Unformatted: