Skip site navigation (1)Skip section navigation (2)
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>