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: