(find-maint.info)Security


Next: Making Releases Prev: Internationalisation Up: Top
Enter node , (file) or (file)node

12 Security
***********

See Note: Security Considerations, for a
full description of the findutils approach to security considerations
and discussion of particular tools.

   If someone reports a security bug publicly, we should fix this as
rapidly as possible.  If necessary, this can mean issuing a fixed
release containing just the one bug fix.  We try to avoid issuing
releases which include both significant security fixes and functional
changes.

   Where someone reports a security problem privately, we generally try
to construct and test a patch without pushing the intermediate code to
the public repository.

   Once everything has been tested, this allows us to make a release and
push the patch.  The advantage of doing things this way is that we avoid
situations where people watching for git commits can figure out and
exploit a security problem before a fixed release is available.

   It's important that security problems be fixed promptly, but don't
rush so much that things go wrong.  Make sure the new release really
fixes the problem.  It's usually best not to include functional changes
in your security-fix release.

   If the security problem is serious, send an alert to
<vendor-sec@lst.de>.  The members of the list include most GNU/Linux
distributions.  The point of doing this is to allow them to prepare to
release your security fix to their customers, once the fix becomes
available.  Here is an example alert:-

     GNU findutils heap buffer overrun (potential privilege escalation)



     I. BACKGROUND
     =============

     GNU findutils is a set of programs which search for files on Unix-like
     systems.  It is maintained by the GNU Project of the Free Software
     Foundation.  For more information, see
     <https://www.gnu.org/software/findutils>.


     II. DESCRIPTION
     ===============

     When GNU locate reads filenames from an old-format locate database,
     they are read into a fixed-length buffer allocated on the heap.
     Filenames longer than the 1026-byte buffer can cause a buffer overrun.
     The overrunning data can be chosen by any person able to control the
     names of filenames created on the local system.  This will normally
     include all local users, but in many cases also remote users (for
     example in the case of FTP servers allowing uploads).

     III. ANALYSIS
     =============

     Findutils supports three different formats of locate database, its
     native format "LOCATE02", the slocate variant of LOCATE02, and a
     traditional ("old") format that locate uses on other Unix systems.

     When locate reads filenames from a LOCATE02 database (the default
     format), the buffer into which data is read is automatically extended
     to accommodate the length of the filenames.

     This automatic buffer extension does not happen for old-format
     databases.  Instead a 1026-byte buffer is used.  When a longer
     pathname appears in the locate database, the end of this buffer is
     overrun.  The buffer is allocated on the heap (not the stack).

     If the locate database is in the default LOCATE02 format, the locate
     program does perform automatic buffer extension, and the program is
     not vulnerable to this problem.  The software used to build the
     old-format locate database is not itself vulnerable to the same
     attack.

     Most installations of GNU findutils do not use the old database
     format, and so will not be vulnerable.


     IV. DETECTION
     =============

     Software
     --------
     All existing releases of findutils are affected.


     Installations
     -------------

     To discover the longest path name on a given system, you can use the
     following command (requires GNU findutils and GNU coreutils):

     find / -print0 | tr -c '\0' 'x' | tr '\0' '\n' | wc -L

     V. EXAMPLE
     ==========

     This section includes a shell script which determines which of a list
     of locate binaries is vulnerable to the problem.  The shell script has
     been tested only on glibc based systems having a mktemp binary.

     NOTE: This script deliberately overruns the buffer in order to
     determine if a binary is affected.  Therefore running it on your
     system may have undesirable effects.  We recommend that you read the
     script before running it.

     #! /bin/sh
     set +m
     if vanilla_db="$(mktemp nicedb.XXXXXX)" ; then
         if updatedb --prunepaths="" --old-format --localpaths="/tmp" \
     	--output="$@{vanilla_db@}" ; then
     	true
         else
     	rm -f "$@{vanilla_db@}"
     	vanilla_db=""
     	echo "Failed to create old-format locate database; skipping the sanity checks" >&2
         fi
     fi
     
     make_overrun_db() @{
         # Start with a valid database
         cat "$@{vanilla_db@}"
         # Make the final entry really long
         dd if=/dev/zero  bs=1 count=1500 2>/dev/null | tr '\000' 'x'
     @}
     
     
     
     ulimit -c 0
     
     usage() @{ echo "usage: $0 binary [binary...]" >&2; exit $1; @}
     [ $# -eq 0 ] && usage 1
     
     bad=""
     good=""
     ugly=""
     if dbfile="$(mktemp nasty.XXXXXX)"
     then
         make_overrun_db > "$dbfile"
         for locate ; do
           ver="$locate = $("$locate"  --version | head -1)"
           if [ -z "$vanilla_db" ] || "$locate" -d "$vanilla_db" "" >/dev/null ; then
     	  "$locate" -d "$dbfile" "" >/dev/null
     	  if [ $? -gt 128 ] ; then
     	      bad="$bad
     vulnerable: $ver"
     	  else
     	      good="$good
     good: $ver"
     	  fi
            else
     	  # the regular locate failed
     	  ugly="$ugly
     buggy, may or may not be vulnerable: $ver"
            fi
         done
         rm -f "$@{dbfile@}" "$@{vanilla_db@}"
         # good: unaffected.  bad: affected (vulnerable).
         # ugly: doesn't even work for a normal old-format database.
         echo "$good"
         echo "$bad"
         echo "$ugly"
     else
       exit 1
     fi




     VI. VENDOR RESPONSE
     ===================

     The GNU project discovered the problem while 'locate' was being worked
     on; this is the first public announcement of the problem.

     The GNU findutils mantainer has issued a patch as p[art of this
     announcement.  The patch appears below.

     A source release of findutils-4.2.31 will be issued on 2007-05-30.
     That release will of course include the patch.  The patch will be
     committed to the public CVS repository at the same time.  Public
     announcements of the release, including a description of the bug, will
     be made at the same time as the release.

     A release of findutils-4.3.x will follow and will also include the
     patch.


     VII. PATCH
     ==========

     This patch should apply to findutils-4.2.23 and later.
     Findutils-4.2.23 was released almost two years ago.
     Index: locate/locate.c
     ===================================================================
     RCS file: /cvsroot/findutils/findutils/locate/locate.c,v
     retrieving revision 1.58.2.2
     diff -u -p -r1.58.2.2 locate.c
     --- locate/locate.c	22 Apr 2007 16:57:42 -0000	1.58.2.2
     +++ locate/locate.c	28 May 2007 10:18:16 -0000
     @@@@ -124,9 +124,9 @@@@ extern int errno;
     
      #include "locatedb.h"
      #include <getline.h>
     -#include "../gnulib/lib/xalloc.h"
     -#include "../gnulib/lib/error.h"
     -#include "../gnulib/lib/human.h"
     +#include "xalloc.h"
     +#include "error.h"
     +#include "human.h"
      #include "dirname.h"
      #include "closeout.h"
      #include "nextelem.h"
     @@@@ -468,10 +468,36 @@@@ visit_justprint_unquoted(struct process_
        return VISIT_CONTINUE;
      @}
     
     +static void
     +toolong (struct process_data *procdata)
     +@{
     +  error (EXIT_FAILURE, 0,
     +	 _("locate database %s contains a "
     +	   "filename longer than locate can handle"),
     +	 procdata->dbfile);
     +@}
     +
     +static void
     +extend (struct process_data *procdata, size_t siz1, size_t siz2)
     +@{
     +  /* Figure out if the addition operation is safe before performing it. */
     +  if (SIZE_MAX - siz1 < siz2)
     +    @{
     +      toolong (procdata);
     +    @}
     +  else if (procdata->pathsize < (siz1+siz2))
     +    @{
     +      procdata->pathsize = siz1+siz2;
     +      procdata->original_filename = x2nrealloc (procdata->original_filename,
     +						&procdata->pathsize,
     +						1);
     +    @}
     +@}
     +
      static int
      visit_old_format(struct process_data *procdata, void *context)
      @{
     -  register char *s;
     +  register size_t i;
        (void) context;
     
        /* Get the offset in the path where this path info starts.  */
     @@@@ -479,20 +505,35 @@@@ visit_old_format(struct process_data *pr
          procdata->count += getw (procdata->fp) - LOCATEDB_OLD_OFFSET;
        else
          procdata->count += procdata->c - LOCATEDB_OLD_OFFSET;
     +  assert(procdata->count > 0);
     
     -  /* Overlay the old path with the remainder of the new.  */
     -  for (s = procdata->original_filename + procdata->count;
     +  /* Overlay the old path with the remainder of the new.  Read
     +   * more data until we get to the next filename.
     +   */
     +  for (i=procdata->count;
             (procdata->c = getc (procdata->fp)) > LOCATEDB_OLD_ESCAPE;)
     -    if (procdata->c < 0200)
     -      *s++ = procdata->c;		/* An ordinary character.  */
     -    else
     -      @{
     -	/* Bigram markers have the high bit set. */
     -	procdata->c &= 0177;
     -	*s++ = procdata->bigram1[procdata->c];
     -	*s++ = procdata->bigram2[procdata->c];
     -      @}
     -  *s-- = '\0';
     +    @{
     +      if (procdata->c < 0200)
     +	@{
     +	  /* An ordinary character. */
     +	  extend (procdata, i, 1u);
     +	  procdata->original_filename[i++] = procdata->c;
     +	@}
     +      else
     +	@{
     +	  /* Bigram markers have the high bit set. */
     +	  extend (procdata, i, 2u);
     +	  procdata->c &= 0177;
     +	  procdata->original_filename[i++] = procdata->bigram1[procdata->c];
     +	  procdata->original_filename[i++] = procdata->bigram2[procdata->c];
     +	@}
     +    @}
     +
     +  /* Consider the case where we executed the loop body zero times; we
     +   * still need space for the terminating null byte.
     +   */
     +  extend (procdata, i, 1u);
     +  procdata->original_filename[i] = 0;
     
        procdata->munged_filename = procdata->original_filename;


     VIII. THANKS
     ============

     Thanks to Rob Holland <rob@inversepath.com> and Tavis Ormandy.


     VIII. CVE INFORMATION
     =====================

     No CVE candidate number has yet been assigned for this vulnerability.
     If someone provides one, I will include it in the public announcement
     and change logs.

   The original announcement above was sent out with a cleartext PGP
signature, of course, but that has been omitted from the example.

   Once a fixed release is available, announce the new release using the
normal channels.  Any CVE number assigned for the problem should be
included in the 'ChangeLog' and 'NEWS' entries.  See
<https://cve.mitre.org/> for an explanation of CVE numbers.


automatically generated by info2www version 1.2.2.9