COMMAND

    gzip (GNU zip)

SYSTEMS AFFECTED

    Systems using gzip

PROBLEM

    firebug@atlantic.net found  a bug  in gzip  that can  allow a file
    that is  being compressed  or uncompressed  to be  read by  anyone
    with search access to the  directory it is in. Before  unlink()ing
    the  original  file  (when  compressing  or  uncompressing), it is
    chmod()ed to 0777.   It looks like  someone didn't understand  the
    behavior of unlink(2) vs rm(1).

    The problem code is in gzip.c, in copy_stat(), on line 1636:

        (void) chmod(ifname, 0777);
        if (unlink(ifname)) {

    There is also a similar bug when overwriting an existing file,  in
    check_ofname(), on line 1576:

        (void) chmod(ofname, 0777);
        if (unlink(ofname)) {

    In both cases, the chmod()  is not necessary, and only  introduces
    a security hole. The solution is trivial - remove the chmod()s.

    gzip will  not normally  touch a  file with  a link  count greater
    than 1. With -f it will. If you know that a file you want to  read
    will be gzip -f'd, that makes this easy - make a hard link to  it,
    and wait for your link to be the only copy, mode 777.

    Without -f, there  are two race  conditions, an easier  one if you
    can make a hard link to the  file, and a hard one if you  can not.
    There's also a possibility  for a minor denial-of-service  attack,
    not caused by this bug.

    For the denial-of-service attack, make  a hard link to a  file you
    know  will  be  gzipped  either  automatically  or by a person who
    won't  understand  what  the  "gzip:  foo  has  1  other  link  --
    unchanged" message means.  This is also  what happens if  you make
    the link too early for the 'easy' race. This is not really a  gzip
    issue,  however,  but  does  serve  as  yet another example of why
    there should be some way to  restrict a user from adding links  to
    a file he does not own.

    For the hard race, open() the file in between the chmod() and  the
    unlink().  This is possible, but difficult.

    For the easier race, make a  hard link to the file in  between the
    lstat() (which is before the  open(), so you have the  entire time
    it takes to compress the file) and the unlink(). The problem  with
    this race  is that  if you  lose, you  lose for  good. You get one
    chance, if you do  it too soon, gzip  complains, if you do  it too
    late, the file is gone.

SOLUTION

    This isn't really  a serious bug,  but it does  show that software
    should always be  written with race  conditions in mind,  and that
    even local  non-suid utilities  must be  written with  security in
    mind.  As said before, remove chmod()s.