kern/54331: shutdown() on a socket registered in a kqueue locks up the machine (test code attached)

Ben freebsdbug at slimyhorror.com
Thu Jul 10 10:20:04 PDT 2003


>Number:         54331
>Category:       kern
>Synopsis:       shutdown() on a socket registered in a kqueue locks up the machine (test code attached)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jul 10 10:20:02 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator:     Ben
>Release:        FreeBSD 5.1-RELEASE i386
>Organization:
none
>Environment:
System: FreeBSD demeter.cam.zeus.com 5.1-RELEASE FreeBSD 5.1-RELEASE #0: Thu Jul 10 16:59:37 BST 2003 root at demeter
.cam.zeus.com:/usr/obj/usr/src/sys/GENERIC i386

Also possibly 5.0 as well - but not able to test that now.
>Description:
When you shutdown( SHUT_RDWR ) a TCP listen socket which has been
added into a kqueue for EVFILT_READ events, the entire machine will
lock up. No error messages appear in the logs.

>How-To-Repeat:

The following code will trigger the crash on the machine (5.1-RELEASE/GENERIC,
compiled with '-O'. (Other configurations of the kernel seem to have the same
problem).

The only other FreeBSD box which I have access to is 4.2-RELEASE, and that
appears to work fine. I suspect the bug may also be present in 5.0 (similar
symptoms occured, but I had not written this test case then).

#include <stdio.h>
#include <sys/types.h>
#include <sys/event.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>


int
main( int argc, char **argv )
{
   int queue, sock, i;
   struct sockaddr_in addr;
   struct kevent events[ 10 ];
   struct timespec ktime;

   queue = kqueue();
   if( queue == -1 ) {
      perror( "kqueue() failure" );
      exit( 1 );
   }

   sock = socket( AF_INET, SOCK_STREAM, 0 );
   /* NOTE: None of this bind() and listen() code is necessary for the crash,
    * I'm including it to show the crash in 'normal operation'
    */
   memset( &addr, 0, sizeof( addr ));
   addr.sin_family = AF_INET;
   addr.sin_port = htons( 3456 );
   addr.sin_addr.s_addr = INADDR_ANY;
   if( bind( sock, (struct sockaddr *) &addr, sizeof( addr )) < 0 ) {
      perror( "bind" );
      exit( 1 );
   }
   if( listen( sock, 32 ) < 0 ) {
      perror( "listen" );
      exit( 1 );
   }

   /* Must add the socket to the kqueue for it to crash */
   events[ 0 ].ident  = sock;
   events[ 0 ].udata  = 0;
   events[ 0 ].filter = EVFILT_READ;
   events[ 0 ].flags  = EV_ADD;

   ktime.tv_sec = 1;
   ktime.tv_nsec = 0;
   i = kevent( queue, events, 1, events, 10, &ktime );
   printf( "kevent() returned %d\n", i );

   printf( "Closing socket\n" );

   /* CRASH!!! Must be a shutdown() call, close() alone won't do it. */
   shutdown( sock, SHUT_RDWR );
   close( sock );

   /* Cleanup if we survive */
   printf( "Closing queue\n" );
   close( queue );

   return 0;
}

>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list