Date: Sun, 1 Mar 1998 18:53:30 -0800 (PST) From: dwimsey@rtci.com To: freebsd-gnats-submit@FreeBSD.ORG Subject: kern/5895: Kernal dumps caused by fork? Message-ID: <199803020253.SAA22224@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 5895
>Category: kern
>Synopsis: Kernal dumps caused by fork?
>Confidential: no
>Severity: critical
>Priority: high
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Sun Mar 1 19:00:01 PST 1998
>Last-Modified:
>Originator: David Wimsey
>Organization:
>Release: 2.2.5-STABLE
>Environment:
FreeBSD oldwarez.com 2.2.5-STABLE FreeBSD 2.2.5-STABLE #0: Sun Mar 1 21:23:52 EST 1998 root@oldwarez.com:/usr/src/sys/compile/ChaosKern i386
>Description:
This description is not confirmed... it it simple the best I can figure from what I have to go by.
When a process forks, and the spawn dies unexpectedly, it doesn't properly remove the entry from the process list, and then the kernel attempts to run the process. Which causes a page fault.
There was no pattern to this until recently when I begain working on a tcp echo server. The server simply forks off a new process for each incoming connection, and goes on about its business. However, if I open a connection to the echo server, and close it abruptly (i.e. telnet 0 5000, <esc char> quit) after a few of these... the machine is well on its way to rebooting.
>How-To-Repeat:
Below is the source to the program that seems to have a good chance of causing it... it will reboot no matter what by the tenth closed connection on this program. Which I run as a normal user, nothing special about it.
> cat sock.c
#include <errno.h> /* obligatory includes */
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netdb.h>
#define MAXHOSTNAME 256
/* code to establish a socket; originally from bzs@bu-cs.bu.edu
*/
int establish(unsigned short portnum)
{ char myname[MAXHOSTNAME+1];
int s;
struct sockaddr_in sa;
struct hostent *hp;
memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */
gethostname(myname, MAXHOSTNAME); /* who are we? */
hp= gethostbyname(myname); /* get our address info */
if (hp == NULL) /* we don't exist !? */
return(-1);
sa.sin_family= hp->h_addrtype; /* this is our host address */
sa.sin_port= htons(portnum); /* this is our port number */
if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) /* create socket */
return(-1);
if (bind(s,&sa,sizeof(struct sockaddr_in)) < 0) {
close(s);
return(-1); /* bind address to socket */
}
listen(s, 3); /* max # of queued connects */
return(s);
}
/* wait for a connection to occur on a socket created with establish()
*/
int get_connection(int s)
{ int t; /* socket of connection */
if ((t = accept(s,NULL,NULL)) < 0) /* accept connection if there is one */
return(-1);
return(t);
}
#define PORTNUM 5000 /* random port number, we need something */
void fireman(void);
void do_something(int);
main()
{ int s, t;
if ((s= establish(PORTNUM)) < 0) { /* plug in the phone */
perror("establish");
exit(1);
}
signal(SIGCHLD, fireman); /* this eliminates zombies */
for (;;) { /* loop for phone calls */
if ((t= get_connection(s)) < 0) { /* get a connection */
if (errno == EINTR) /* EINTR might happen on accept(), */
continue; /* try again */
perror("accept"); /* bad */
exit(1);
}
switch(fork()) { /* try to handle connection */
case -1 : /* bad news. scream and die */
perror("fork");
close(s);
close(t);
exit(1);
case 0 : /* we're the child, do something */
close(s);
do_something(t);
exit(0);
default : /* we're the parent so look for */
close(t); /* another connection */
continue;
}
}
}
/* as children die we should get catch their returns or else we get
* zombies, A Bad Thing. fireman() catches falling children.
*/
void fireman(void)
{
while (waitpid(-1, NULL, WNOHANG) > 0)
;
printf( "Socket lost!" );
}
/* this is the function that plays with the socket. it will be called
* after getting a connection.
*/
//quicktag
void do_something(int s)
{
char buf[257];
char buf2[257];
int webint, count=0;
printf( "Socket %d connected!\r\n", s );
send( s, "Sup fucko\r\n\0\0", 12, MSG_PEEK );
while(1)
{
memcpy( buf, "\0\0\0\0\0\0\0\0\0\0\0", 10);
read(s, &buf, 1);
send( s, buf, strlen(buf), 0 );
printf( buf );
if( strcmp( buf, "W" ) )
{
webint = call_socket( "noc.rtci.com", 80 );
send( webint, "GET /index.html HTTP1.0\n\n", 25, 0 );
while( count < 100 )
{
count++;
read( webint, buf2, 64 );
send( s, buf2, strlen( buf2 ), 0 );
}
close( webint );
}
}
}
int call_socket(char *hostname, unsigned short portnum)
{ struct sockaddr_in sa;
struct hostent *hp;
int a, s;
if ((hp= gethostbyname(hostname)) == NULL) { /* do we know the host's */
errno= ECONNREFUSED; /* address? */
return(-1); /* no */
}
memset(&sa,0,sizeof(sa));
memcpy((char *)&sa.sin_addr,hp->h_addr,hp->h_length); /* set address */
sa.sin_family= hp->h_addrtype;
sa.sin_port= htons((u_short)portnum);
if ((s= socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) /* get socket */
return(-1);
if (connect(s,&sa,sizeof sa) < 0) { /* connect */
close(s);
return(-1);
}
return(s);
}
int read_data(int s, /* connected socket */
char *buf, /* pointer to the buffer */
int n /* number of characters (bytes) we want */
)
{ int bcount; /* counts bytes read */
int br; /* bytes read this pass */
bcount= 0;
br= 0;
while (bcount < n) { /* loop until full buffer */
if ((br= read(s,buf,n-bcount)) > 0) {
bcount += br; /* increment byte counter */
buf += br; /* move buffer ptr for next read */
}
else if (br < 0) /* signal an error to the caller */
return(-1);
}
return(bcount);
}
/*
i= htonl(i);
write_data(s, &i, sizeof(i));
and after reading data you should convert it back with ntohl():
read_data(s, &i, sizeof(i));
i= ntohl(i);
*/
>Fix:
>Audit-Trail:
>Unformatted:
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199803020253.SAA22224>
