Subject: kern/5080: f_count panic (et al.)
To: None <gnats-bugs@gnats.netbsd.org>
From: David Holland <dholland@eecs.harvard.edu>
List: netbsd-bugs
Date: 02/27/1998 21:30:56
>Number: 5080
>Category: kern
>Synopsis: panic on f_count (in struct file) negative
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Feb 27 18:35:01 1998
>Last-Modified:
>Originator: dholland@eecs.harvard.edu (David A. Holland)
>Organization:
- David A. Holland | VINO project home page:
dholland@eecs.harvard.edu | http://www.eecs.harvard.edu/vino
>Release: 1.3
>Environment:
System: NetBSD chianti.eecs.harvard.edu 1.2.1 NetBSD 1.2.1 (CHIANTI) #1: Tue Sep 9 16:52:39 EDT 1997 root@chianti.eecs.harvard.edu:/usr/src/sys/arch/i386/compile/CHIANTI i386
Note: also tested with the 1.3 distribution kernel from ftp.netbsd.org.
>Description:
The reference count on struct file is a signed short, so if
one can construct more than 32767 references it overflows.
This can be done with a combination of dup() and fork().
Additional unexplained behavior occurs if you set NDUPS to 60
and NFORKS to 550: in 1.2.1, it reliably crashes with a page
fault in wdcstart(), and in 1.3, it hangs (cannot create any
more processes) and once I got it to reference 0xdeadbeef in
m_freem() [but only once] by trying to telnet in.
Since this seems to happen on fork #50, long before the ref
count should overflow, it may be an additional unrelated
problem.
>How-To-Repeat:
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define NDUPS 1600
#define NFORKS 22
static void child() {
sleep(1000);
}
static void openem() {
int i,r;
int fd = open("/etc/passwd", O_RDONLY);
if (fd<0) { perror("open /etc/passwd"); exit(1); }
for (i=0; i<NDUPS; i++) {
r = dup(fd);
if (r<0) { perror("dup"); exit(1); }
}
}
static void forkus() {
int i;
int r;
write(1, "forking\n", 8);
for (i=0; i<NFORKS; i++) {
r = fork();
if (r<0) { perror("fork"); exit(1); }
if (r==0) child();
write(1, ".-", 2);
}
}
int main() {
int status;
openem();
forkus();
while (wait(&status)>=0);
return 0;
}
>Fix:
fork() needs to check and make sure that f_count doesn't overflow.
(dup already seems to.)
>Audit-Trail:
>Unformatted: