Avoid symlink attack in localcharset module. Use fcntl_h.m4 from gnulib.

This commit is contained in:
Bruno Haible 2009-10-18 17:17:48 +02:00
parent e487ecf4c9
commit 8c4ff981d5
15 changed files with 249 additions and 70 deletions

View File

@ -1,3 +1,8 @@
2009-10-18 Bruno Haible <bruno@clisp.org>
* Makefile.am (distcheck-hook): Compare fcntl_h.m4.
* PACKAGING: Mention also fcntl_h.m4.
2009-09-27 Bruno Haible <bruno@clisp.org>
* NEWS: Mention configure options --without-cvs and --with-git.

View File

@ -43,6 +43,7 @@ distcheck-hook:
cmp -s gettext-runtime/po/remove-potcdate.sin gettext-tools/po/remove-potcdate.sin
cmp -s gettext-runtime/po/remove-potcdate.sin gettext-tools/examples/po/remove-potcdate.sin
cmp -s gettext-runtime/m4/codeset.m4 gettext-tools/gnulib-m4/codeset.m4
cmp -s gettext-runtime/m4/fcntl_h.m4 gettext-tools/gnulib-m4/fcntl_h.m4
cmp -s gettext-runtime/m4/gettext.m4 gettext-tools/gnulib-m4/gettext.m4
cmp -s gettext-runtime/m4/glibc2.m4 gettext-tools/gnulib-m4/glibc2.m4
cmp -s gettext-runtime/m4/glibc21.m4 gettext-tools/gnulib-m4/glibc21.m4

View File

@ -117,6 +117,7 @@ following file list.
$prefix/share/gettext/archive.git.tar.gz (only installed if --with-git specified)
$prefix/share/gettext/archive.dir.tar.gz (only installed if --without-cvs specified)
$prefix/share/aclocal/codeset.m4
$prefix/share/aclocal/fcntl_h.m4
$prefix/share/aclocal/gettext.m4
$prefix/share/aclocal/glibc2.m4
$prefix/share/aclocal/glibc21.m4

View File

@ -1,3 +1,11 @@
2009-10-18 Bruno Haible <bruno@clisp.org>
Avoid symlink attack in localcharset module.
* localcharset.c: Include <fcntl.h>, <unistd.h>.
(O_NOFOLLOW): Define fallback.
(get_charset_aliases): Don't open the file if it is a symbolic link.
Reported by Fergal Glynn <fglynn@veracode.com>.
2009-08-20 Eric Blake <ebb9@byu.net>
* vasnprintf.c (decimal_point_char): Avoid warning on old-style

View File

@ -24,6 +24,7 @@
/* Specification. */
#include "localcharset.h"
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
@ -45,6 +46,7 @@
#endif
#if !defined WIN32_NATIVE
# include <unistd.h>
# if HAVE_LANGINFO_CODESET
# include <langinfo.h>
# else
@ -76,6 +78,11 @@
# include "configmake.h"
#endif
/* Define O_NOFOLLOW to 0 on platforms where it does not exist. */
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0
#endif
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
/* Win32, Cygwin, OS/2, DOS */
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
@ -118,7 +125,6 @@ get_charset_aliases (void)
if (cp == NULL)
{
#if !(defined DARWIN7 || defined VMS || defined WIN32_NATIVE || defined __CYGWIN__)
FILE *fp;
const char *dir;
const char *base = "charset.alias";
char *file_name;
@ -144,77 +150,105 @@ get_charset_aliases (void)
}
}
if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL)
/* Out of memory or file not found, treat it as empty. */
if (file_name == NULL)
/* Out of memory. Treat the file as empty. */
cp = "";
else
{
/* Parse the file's contents. */
char *res_ptr = NULL;
size_t res_size = 0;
int fd;
for (;;)
{
int c;
char buf1[50+1];
char buf2[50+1];
size_t l1, l2;
char *old_res_ptr;
c = getc (fp);
if (c == EOF)
break;
if (c == '\n' || c == ' ' || c == '\t')
continue;
if (c == '#')
{
/* Skip comment, to end of line. */
do
c = getc (fp);
while (!(c == EOF || c == '\n'));
if (c == EOF)
break;
continue;
}
ungetc (c, fp);
if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
break;
l1 = strlen (buf1);
l2 = strlen (buf2);
old_res_ptr = res_ptr;
if (res_size == 0)
{
res_size = l1 + 1 + l2 + 1;
res_ptr = (char *) malloc (res_size + 1);
}
else
{
res_size += l1 + 1 + l2 + 1;
res_ptr = (char *) realloc (res_ptr, res_size + 1);
}
if (res_ptr == NULL)
{
/* Out of memory. */
res_size = 0;
if (old_res_ptr != NULL)
free (old_res_ptr);
break;
}
strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
strcpy (res_ptr + res_size - (l2 + 1), buf2);
}
fclose (fp);
if (res_size == 0)
/* Open the file. Reject symbolic links on platforms that support
O_NOFOLLOW. This is a security feature. Without it, an attacker
could retrieve parts of the contents (namely, the tail of the
first line that starts with "* ") of an arbitrary file by placing
a symbolic link to that file under the name "charset.alias" in
some writable directory and defining the environment variable
CHARSETALIASDIR to point to that directory. */
fd = open (file_name,
O_RDONLY | (HAVE_WORKING_O_NOFOLLOW ? O_NOFOLLOW : 0));
if (fd < 0)
/* File not found. Treat it as empty. */
cp = "";
else
{
*(res_ptr + res_size) = '\0';
cp = res_ptr;
}
}
FILE *fp;
if (file_name != NULL)
free (file_name);
fp = fdopen (fd, "r");
if (fp == NULL)
{
/* Out of memory. Treat the file as empty. */
close (fd);
cp = "";
}
else
{
/* Parse the file's contents. */
char *res_ptr = NULL;
size_t res_size = 0;
for (;;)
{
int c;
char buf1[50+1];
char buf2[50+1];
size_t l1, l2;
char *old_res_ptr;
c = getc (fp);
if (c == EOF)
break;
if (c == '\n' || c == ' ' || c == '\t')
continue;
if (c == '#')
{
/* Skip comment, to end of line. */
do
c = getc (fp);
while (!(c == EOF || c == '\n'));
if (c == EOF)
break;
continue;
}
ungetc (c, fp);
if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
break;
l1 = strlen (buf1);
l2 = strlen (buf2);
old_res_ptr = res_ptr;
if (res_size == 0)
{
res_size = l1 + 1 + l2 + 1;
res_ptr = (char *) malloc (res_size + 1);
}
else
{
res_size += l1 + 1 + l2 + 1;
res_ptr = (char *) realloc (res_ptr, res_size + 1);
}
if (res_ptr == NULL)
{
/* Out of memory. */
res_size = 0;
if (old_res_ptr != NULL)
free (old_res_ptr);
break;
}
strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
strcpy (res_ptr + res_size - (l2 + 1), buf2);
}
fclose (fp);
if (res_size == 0)
cp = "";
else
{
*(res_ptr + res_size) = '\0';
cp = res_ptr;
}
}
}
free (file_name);
}
#else

View File

@ -1,3 +1,9 @@
2009-10-18 Bruno Haible <bruno@clisp.org>
* fcntl_h.m4: New file, from gnulib.
* intl.m4 (AM_INTL_SUBDIR): Require gl_FCNTL_O_FLAGS.
* Makefile.am (EXTRA_DIST): Add fcntl_h.m4.
2009-08-14 Bruno Haible <bruno@clisp.org>
* eoverflow.m4: Remove file. Obsoleted by gnulib's 'errno' module.

View File

@ -5,6 +5,7 @@
EXTRA_DIST = README \
ansi-c++.m4 \
codeset.m4 \
fcntl_h.m4 \
gettext.m4 \
glibc2.m4 \
glibc21.m4 \

View File

@ -0,0 +1,108 @@
# serial 6
# Configure fcntl.h.
dnl Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl Written by Paul Eggert.
AC_DEFUN([gl_FCNTL_H],
[
AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
AC_REQUIRE([gl_FCNTL_O_FLAGS])
gl_CHECK_NEXT_HEADERS([fcntl.h])
FCNTL_H='fcntl.h'
AC_SUBST([FCNTL_H])
])
# Test whether the flags O_NOATIME and O_NOFOLLOW actually work.
# Define HAVE_WORKING_O_NOATIME to 1 if O_NOATIME works, or to 0 otherwise.
# Define HAVE_WORKING_O_NOFOLLOW to 1 if O_NOFOLLOW works, or to 0 otherwise.
AC_DEFUN([gl_FCNTL_O_FLAGS],
[
dnl Persuade glibc <fcntl.h> to define O_NOATIME and O_NOFOLLOW.
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
AC_CACHE_CHECK([for working fcntl.h], [gl_cv_header_working_fcntl_h],
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[[#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#ifndef O_NOATIME
#define O_NOATIME 0
#endif
#ifndef O_NOFOLLOW
#define O_NOFOLLOW 0
#endif
static int const constants[] =
{
O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, O_APPEND,
O_NONBLOCK, O_SYNC, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY
};
]],
[[
int status = !constants;
{
static char const sym[] = "conftest.sym";
if (symlink (".", sym) != 0
|| close (open (sym, O_RDONLY | O_NOFOLLOW)) == 0)
status |= 32;
unlink (sym);
}
{
static char const file[] = "confdefs.h";
int fd = open (file, O_RDONLY | O_NOATIME);
char c;
struct stat st0, st1;
if (fd < 0
|| fstat (fd, &st0) != 0
|| sleep (1) != 0
|| read (fd, &c, 1) != 1
|| close (fd) != 0
|| stat (file, &st1) != 0
|| st0.st_atime != st1.st_atime)
status |= 64;
}
return status;]])],
[gl_cv_header_working_fcntl_h=yes],
[case $? in #(
32) gl_cv_header_working_fcntl_h='no (bad O_NOFOLLOW)';; #(
64) gl_cv_header_working_fcntl_h='no (bad O_NOATIME)';; #(
96) gl_cv_header_working_fcntl_h='no (bad O_NOATIME, O_NOFOLLOW)';; #(
*) gl_cv_header_working_fcntl_h='no';;
esac],
[gl_cv_header_working_fcntl_h=cross-compiling])])
case $gl_cv_header_working_fcntl_h in #(
*O_NOATIME* | no | cross-compiling) ac_val=0;; #(
*) ac_val=1;;
esac
AC_DEFINE_UNQUOTED([HAVE_WORKING_O_NOATIME], [$ac_val],
[Define to 1 if O_NOATIME works.])
case $gl_cv_header_working_fcntl_h in #(
*O_NOFOLLOW* | no | cross-compiling) ac_val=0;; #(
*) ac_val=1;;
esac
AC_DEFINE_UNQUOTED([HAVE_WORKING_O_NOFOLLOW], [$ac_val],
[Define to 1 if O_NOFOLLOW works.])
])
AC_DEFUN([gl_FCNTL_MODULE_INDICATOR],
[
dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
GNULIB_[]m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./-],[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])=1
])
AC_DEFUN([gl_FCNTL_H_DEFAULTS],
[
GNULIB_OPEN=0; AC_SUBST([GNULIB_OPEN])
GNULIB_OPENAT=0; AC_SUBST([GNULIB_OPENAT])
dnl Assume proper GNU behavior unless another module says otherwise.
HAVE_OPENAT=1; AC_SUBST([HAVE_OPENAT])
REPLACE_OPEN=0; AC_SUBST([REPLACE_OPEN])
REPLACE_OPENAT=0; AC_SUBST([REPLACE_OPENAT])
])

View File

@ -1,4 +1,4 @@
# intl.m4 serial 13 (gettext-0.18)
# intl.m4 serial 14 (gettext-0.18)
dnl Copyright (C) 1995-2009 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@ -40,6 +40,7 @@ AC_DEFUN([AM_INTL_SUBDIR],
AC_REQUIRE([gt_PRINTF_POSIX])
AC_REQUIRE([gl_GLIBC21])dnl
AC_REQUIRE([gl_XSIZE])dnl
AC_REQUIRE([gl_FCNTL_O_FLAGS])dnl
AC_REQUIRE([gt_INTL_MACOSX])dnl
dnl Support for automake's --enable-silent-rules.

View File

@ -1,3 +1,7 @@
2009-10-18 Bruno Haible <bruno@clisp.org>
* gettext.texi (aclocal): Add fcntl_h.m4 to the file list.
2009-09-20 Bruno Haible <bruno@clisp.org>
* gettext.texi (src/Makefile): Update recommendations for autoconf

View File

@ -7934,7 +7934,7 @@ automake 1.9.
@cindex @file{aclocal.m4} file
If you do not have an @file{aclocal.m4} file in your distribution,
the simplest is to concatenate the files @file{codeset.m4},
the simplest is to concatenate the files @file{codeset.m4}, @file{fcntl_h.m4},
@file{gettext.m4}, @file{glibc2.m4}, @file{glibc21.m4}, @file{iconv.m4},
@file{intdiv0.m4}, @file{intl.m4}, @file{intldir.m4}, @file{intlmacosx.m4},
@file{intmax.m4}, @file{inttypes_h.m4}, @file{inttypes-pri.m4},

View File

@ -1,3 +1,7 @@
2009-10-18 Bruno Haible <bruno@clisp.org>
* Makefile.am (aclocal_DATA): Add fcntl_h.m4.
2009-08-15 Bruno Haible <bruno@clisp.org>
Stop using gnulib module 'strdup'.

View File

@ -8,6 +8,7 @@ aclocal_DATA = \
../../autoconf-lib-link/m4/lib-link.m4 \
../../autoconf-lib-link/m4/lib-prefix.m4 \
../../gettext-runtime/m4/codeset.m4 \
../../gettext-runtime/m4/fcntl_h.m4 \
../../gettext-runtime/m4/gettext.m4 \
../../gettext-runtime/m4/glibc2.m4 \
../../gettext-runtime/m4/glibc21.m4 \

View File

@ -1,3 +1,8 @@
2009-10-18 Bruno Haible <bruno@clisp.org>
* gettextize.in (m4filelist): Add fcntl_h.m4 to the list.
(func_version): Bump copyright year.
2009-09-27 Bruno Haible <bruno@clisp.org>
* add-to-archive: Pass option -fPIC to gcc. Clean up cvsuser.so.

View File

@ -1,6 +1,6 @@
#! /bin/sh
#
# Copyright (C) 1995-1998, 2000-2008 Free Software Foundation, Inc.
# Copyright (C) 1995-1998, 2000-2009 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -174,7 +174,7 @@ Report bugs to <bug-gnu-gettext@gnu.org>."
func_version ()
{
echo "$progname (GNU $package) $version"
echo "Copyright (C) 1995-1998, 2000-2008 Free Software Foundation, Inc.
echo "Copyright (C) 1995-1998, 2000-2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."
@ -768,8 +768,8 @@ m4filelist='gettext.m4 iconv.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 nls.m4
min_automake_version=1.9
if test -n "$intldir" || test -z "$have_automake19"; then
# Add intldir.m4, intl.m4 and its dependencies.
m4filelist=$m4filelist' codeset.m4 glibc2.m4 glibc21.m4 intdiv0.m4 intl.m4
intldir.m4 intlmacosx.m4 intmax.m4 inttypes_h.m4 inttypes-pri.m4
m4filelist=$m4filelist' codeset.m4 fcntl_h.m4 glibc2.m4 glibc21.m4 intdiv0.m4
intl.m4 intldir.m4 intlmacosx.m4 intmax.m4 inttypes_h.m4 inttypes-pri.m4
lcmessage.m4 lock.m4 longlong.m4 printf-posix.m4 size_max.m4 stdint_h.m4
threadlib.m4 uintmax_t.m4 visibility.m4 wchar_t.m4 wint_t.m4 xsize.m4'
min_automake_version=1.8