find-maint: Security
1
1 12 Security
1 ***********
1
1 See ⇒Security Considerations (find)Security Considerations, for a
1 full description of the findutils approach to security considerations
1 and discussion of particular tools.
1
1 If someone reports a security bug publicly, we should fix this as
1 rapidly as possible. If necessary, this can mean issuing a fixed
1 release containing just the one bug fix. We try to avoid issuing
1 releases which include both significant security fixes and functional
1 changes.
1
1 Where someone reports a security problem privately, we generally try
1 to construct and test a patch without pushing the intermediate code to
1 the public repository.
1
1 Once everything has been tested, this allows us to make a release and
1 push the patch. The advantage of doing things this way is that we avoid
1 situations where people watching for git commits can figure out and
1 exploit a security problem before a fixed release is available.
1
1 It's important that security problems be fixed promptly, but don't
1 rush so much that things go wrong. Make sure the new release really
1 fixes the problem. It's usually best not to include functional changes
1 in your security-fix release.
1
1 If the security problem is serious, send an alert to
1 <vendor-sec@lst.de>. The members of the list include most GNU/Linux
1 distributions. The point of doing this is to allow them to prepare to
1 release your security fix to their customers, once the fix becomes
1 available. Here is an example alert:-
1
1 GNU findutils heap buffer overrun (potential privilege escalation)
1
1
1
1 I. BACKGROUND
1 =============
1
1 GNU findutils is a set of programs which search for files on Unix-like
1 systems. It is maintained by the GNU Project of the Free Software
1 Foundation. For more information, see
1 <http://www.gnu.org/software/findutils>.
1
1
1 II. DESCRIPTION
1 ===============
1
1 When GNU locate reads filenames from an old-format locate database,
1 they are read into a fixed-length buffer allocated on the heap.
1 Filenames longer than the 1026-byte buffer can cause a buffer overrun.
1 The overrunning data can be chosen by any person able to control the
1 names of filenames created on the local system. This will normally
1 include all local users, but in many cases also remote users (for
1 example in the case of FTP servers allowing uploads).
1
1 III. ANALYSIS
1 =============
1
1 Findutils supports three different formats of locate database, its
1 native format "LOCATE02", the slocate variant of LOCATE02, and a
1 traditional ("old") format that locate uses on other Unix systems.
1
1 When locate reads filenames from a LOCATE02 database (the default
1 format), the buffer into which data is read is automatically extended
1 to accommodate the length of the filenames.
1
1 This automatic buffer extension does not happen for old-format
1 databases. Instead a 1026-byte buffer is used. When a longer
1 pathname appears in the locate database, the end of this buffer is
1 overrun. The buffer is allocated on the heap (not the stack).
1
1 If the locate database is in the default LOCATE02 format, the locate
1 program does perform automatic buffer extension, and the program is
1 not vulnerable to this problem. The software used to build the
1 old-format locate database is not itself vulnerable to the same
1 attack.
1
1 Most installations of GNU findutils do not use the old database
1 format, and so will not be vulnerable.
1
1
1 IV. DETECTION
1 =============
1
1 Software
1 --------
1 All existing releases of findutils are affected.
1
1
1 Installations
1 -------------
1
1 To discover the longest path name on a given system, you can use the
1 following command (requires GNU findutils and GNU coreutils):
1
1 find / -print0 | tr -c '\0' 'x' | tr '\0' '\n' | wc -L
1
1 V. EXAMPLE
1 ==========
1
1 This section includes a shell script which determines which of a list
1 of locate binaries is vulnerable to the problem. The shell script has
1 been tested only on glibc based systems having a mktemp binary.
1
1 NOTE: This script deliberately overruns the buffer in order to
1 determine if a binary is affected. Therefore running it on your
1 system may have undesirable effects. We recommend that you read the
1 script before running it.
1
1 #! /bin/sh
1 set +m
1 if vanilla_db="$(mktemp nicedb.XXXXXX)" ; then
1 if updatedb --prunepaths="" --old-format --localpaths="/tmp" \
1 --output="$@{vanilla_db@}" ; then
1 true
1 else
1 rm -f "$@{vanilla_db@}"
1 vanilla_db=""
1 echo "Failed to create old-format locate database; skipping the sanity checks" >&2
1 fi
1 fi
1
1 make_overrun_db() @{
1 # Start with a valid database
1 cat "$@{vanilla_db@}"
1 # Make the final entry really long
1 dd if=/dev/zero bs=1 count=1500 2>/dev/null | tr '\000' 'x'
1 @}
1
1
1
1 ulimit -c 0
1
1 usage() @{ echo "usage: $0 binary [binary...]" >&2; exit $1; @}
1 [ $# -eq 0 ] && usage 1
1
1 bad=""
1 good=""
1 ugly=""
1 if dbfile="$(mktemp nasty.XXXXXX)"
1 then
1 make_overrun_db > "$dbfile"
1 for locate ; do
1 ver="$locate = $("$locate" --version | head -1)"
1 if [ -z "$vanilla_db" ] || "$locate" -d "$vanilla_db" "" >/dev/null ; then
1 "$locate" -d "$dbfile" "" >/dev/null
1 if [ $? -gt 128 ] ; then
1 bad="$bad
1 vulnerable: $ver"
1 else
1 good="$good
1 good: $ver"
1 fi
1 else
1 # the regular locate failed
1 ugly="$ugly
1 buggy, may or may not be vulnerable: $ver"
1 fi
1 done
1 rm -f "$@{dbfile@}" "$@{vanilla_db@}"
1 # good: unaffected. bad: affected (vulnerable).
1 # ugly: doesn't even work for a normal old-format database.
1 echo "$good"
1 echo "$bad"
1 echo "$ugly"
1 else
1 exit 1
1 fi
1
1
1
1
1 VI. VENDOR RESPONSE
1 ===================
1
1 The GNU project discovered the problem while 'locate' was being worked
1 on; this is the first public announcement of the problem.
1
1 The GNU findutils mantainer has issued a patch as p[art of this
1 announcement. The patch appears below.
1
1 A source release of findutils-4.2.31 will be issued on 2007-05-30.
1 That release will of course include the patch. The patch will be
1 committed to the public CVS repository at the same time. Public
1 announcements of the release, including a description of the bug, will
1 be made at the same time as the release.
1
1 A release of findutils-4.3.x will follow and will also include the
1 patch.
1
1
1 VII. PATCH
1 ==========
1
1 This patch should apply to findutils-4.2.23 and later.
1 Findutils-4.2.23 was released almost two years ago.
1 Index: locate/locate.c
1 ===================================================================
1 RCS file: /cvsroot/findutils/findutils/locate/locate.c,v
1 retrieving revision 1.58.2.2
1 diff -u -p -r1.58.2.2 locate.c
1 --- locate/locate.c 22 Apr 2007 16:57:42 -0000 1.58.2.2
1 +++ locate/locate.c 28 May 2007 10:18:16 -0000
1 @@@@ -124,9 +124,9 @@@@ extern int errno;
1
1 #include "locatedb.h"
1 #include <getline.h>
1 -#include "../gnulib/lib/xalloc.h"
1 -#include "../gnulib/lib/error.h"
1 -#include "../gnulib/lib/human.h"
1 +#include "xalloc.h"
1 +#include "error.h"
1 +#include "human.h"
1 #include "dirname.h"
1 #include "closeout.h"
1 #include "nextelem.h"
1 @@@@ -468,10 +468,36 @@@@ visit_justprint_unquoted(struct process_
1 return VISIT_CONTINUE;
1 @}
1
1 +static void
1 +toolong (struct process_data *procdata)
1 +@{
1 + error (EXIT_FAILURE, 0,
1 + _("locate database %s contains a "
1 + "filename longer than locate can handle"),
1 + procdata->dbfile);
1 +@}
1 +
1 +static void
1 +extend (struct process_data *procdata, size_t siz1, size_t siz2)
1 +@{
1 + /* Figure out if the addition operation is safe before performing it. */
1 + if (SIZE_MAX - siz1 < siz2)
1 + @{
1 + toolong (procdata);
1 + @}
1 + else if (procdata->pathsize < (siz1+siz2))
1 + @{
1 + procdata->pathsize = siz1+siz2;
1 + procdata->original_filename = x2nrealloc (procdata->original_filename,
1 + &procdata->pathsize,
1 + 1);
1 + @}
1 +@}
1 +
1 static int
1 visit_old_format(struct process_data *procdata, void *context)
1 @{
1 - register char *s;
1 + register size_t i;
1 (void) context;
1
1 /* Get the offset in the path where this path info starts. */
1 @@@@ -479,20 +505,35 @@@@ visit_old_format(struct process_data *pr
1 procdata->count += getw (procdata->fp) - LOCATEDB_OLD_OFFSET;
1 else
1 procdata->count += procdata->c - LOCATEDB_OLD_OFFSET;
1 + assert(procdata->count > 0);
1
1 - /* Overlay the old path with the remainder of the new. */
1 - for (s = procdata->original_filename + procdata->count;
1 + /* Overlay the old path with the remainder of the new. Read
1 + * more data until we get to the next filename.
1 + */
1 + for (i=procdata->count;
1 (procdata->c = getc (procdata->fp)) > LOCATEDB_OLD_ESCAPE;)
1 - if (procdata->c < 0200)
1 - *s++ = procdata->c; /* An ordinary character. */
1 - else
1 - @{
1 - /* Bigram markers have the high bit set. */
1 - procdata->c &= 0177;
1 - *s++ = procdata->bigram1[procdata->c];
1 - *s++ = procdata->bigram2[procdata->c];
1 - @}
1 - *s-- = '\0';
1 + @{
1 + if (procdata->c < 0200)
1 + @{
1 + /* An ordinary character. */
1 + extend (procdata, i, 1u);
1 + procdata->original_filename[i++] = procdata->c;
1 + @}
1 + else
1 + @{
1 + /* Bigram markers have the high bit set. */
1 + extend (procdata, i, 2u);
1 + procdata->c &= 0177;
1 + procdata->original_filename[i++] = procdata->bigram1[procdata->c];
1 + procdata->original_filename[i++] = procdata->bigram2[procdata->c];
1 + @}
1 + @}
1 +
1 + /* Consider the case where we executed the loop body zero times; we
1 + * still need space for the terminating null byte.
1 + */
1 + extend (procdata, i, 1u);
1 + procdata->original_filename[i] = 0;
1
1 procdata->munged_filename = procdata->original_filename;
1
1
1 VIII. THANKS
1 ============
1
1 Thanks to Rob Holland <rob@inversepath.com> and Tavis Ormandy.
1
1
1 VIII. CVE INFORMATION
1 =====================
1
1 No CVE candidate number has yet been assigned for this vulnerability.
1 If someone provides one, I will include it in the public announcement
1 and change logs.
1
1 The original announcement above was sent out with a cleartext PGP
1 signature, of course, but that has been omitted from the example.
1
1 Once a fixed release is available, announce the new release using the
1 normal channels. Any CVE number assigned for the problem should be
1 included in the 'ChangeLog' and 'NEWS' entries. See
1 <http://cve.mitre.org/> for an explanation of CVE numbers.
1