[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
localcharset: fix security problem
From: |
Bruno Haible |
Subject: |
localcharset: fix security problem |
Date: |
Sun, 18 Oct 2009 16:58:22 +0200 |
User-agent: |
KMail/1.9.9 |
This fixes a possible symlink attack in localcharset module. The security
hole was probably small, but that's not a reason for not making it even
smaller.
2009-10-18 Bruno Haible <address@hidden>
Avoid symlink attack in localcharset module.
* lib/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.
* m4/fcntl_h.m4 (gl_FCNTL_O_FLAGS): New macro, extracted from
gl_FCNTL_H.
(gl_FCNTL_H): Require it.
* m4/localcharset.m4 (gl_LOCALCHARSET): Likewise.
* modules/localcharset (Files): Add m4/fcntl_h.m4.
Reported by Fergal Glynn <address@hidden>.
*** lib/localcharset.c.orig 2009-10-18 16:53:18.000000000 +0200
--- lib/localcharset.c 2009-10-18 16:50:57.000000000 +0200
***************
*** 23,28 ****
--- 23,29 ----
/* Specification. */
#include "localcharset.h"
+ #include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
***************
*** 44,49 ****
--- 45,51 ----
#endif
#if !defined WIN32_NATIVE
+ # include <unistd.h>
# if HAVE_LANGINFO_CODESET
# include <langinfo.h>
# else
***************
*** 75,80 ****
--- 77,87 ----
# 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) == '\\')
***************
*** 117,123 ****
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;
--- 124,129 ----
***************
*** 143,219 ****
}
}
! if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL)
! /* Out of memory or file not found, treat it as empty. */
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;
- }
- }
! if (file_name != NULL)
! free (file_name);
#else
--- 149,253 ----
}
}
! if (file_name == NULL)
! /* Out of memory. Treat the file as empty. */
cp = "";
else
{
! int fd;
! /* 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
{
! FILE *fp;
!
! 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
*** m4/fcntl_h.m4.orig 2009-10-18 16:53:19.000000000 +0200
--- m4/fcntl_h.m4 2009-10-18 16:37:25.000000000 +0200
***************
*** 1,4 ****
! # serial 5
# Configure fcntl.h.
dnl Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
--- 1,4 ----
! # 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
***************
*** 10,15 ****
--- 10,26 ----
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],
***************
*** 77,86 ****
esac
AC_DEFINE_UNQUOTED([HAVE_WORKING_O_NOFOLLOW], [$ac_val],
[Define to 1 if O_NOFOLLOW works.])
-
- gl_CHECK_NEXT_HEADERS([fcntl.h])
- FCNTL_H='fcntl.h'
- AC_SUBST([FCNTL_H])
])
AC_DEFUN([gl_FCNTL_MODULE_INDICATOR],
--- 88,93 ----
*** m4/localcharset.m4.orig 2009-10-18 16:53:19.000000000 +0200
--- m4/localcharset.m4 2009-10-18 16:37:43.000000000 +0200
***************
*** 1,4 ****
! # localcharset.m4 serial 6
dnl Copyright (C) 2002, 2004, 2006, 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,
--- 1,4 ----
! # localcharset.m4 serial 7
dnl Copyright (C) 2002, 2004, 2006, 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,
***************
*** 8,13 ****
--- 8,14 ----
[
dnl Prerequisites of lib/localcharset.c.
AC_REQUIRE([AM_LANGINFO_CODESET])
+ AC_REQUIRE([gl_FCNTL_O_FLAGS])
AC_CHECK_DECLS_ONCE([getc_unlocked])
dnl Prerequisites of the lib/Makefile.am snippet.
*** modules/localcharset.orig 2009-10-18 16:53:19.000000000 +0200
--- modules/localcharset 2009-10-18 16:37:07.000000000 +0200
***************
*** 14,19 ****
--- 14,20 ----
lib/ref-add.sin
lib/ref-del.sin
m4/codeset.m4
+ m4/fcntl_h.m4
m4/glibc21.m4
m4/localcharset.m4
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- localcharset: fix security problem,
Bruno Haible <=