changeset 17337:a72ac603a92f

putenv: fix heap corruption with mixed putenv/_putenv Problem reported by Michael Goffioul in <http://lists.gnu.org/archive/html/bug-gnulib/2013-02/msg00061.html>. * lib/putenv.c (putenv) [HAVE__PUTENV]: Rely on _putenv to allocate the new environment. * m4/putenv.m4 (gl_PREREQ_PUTENV): New macro. * modules/putenv (configure.ac): Use it.
author Paul Eggert <eggert@cs.ucla.edu>
date Thu, 14 Feb 2013 13:14:18 -0800
parents 603aa5fbb298
children 6f8d1926ece8
files ChangeLog lib/putenv.c m4/putenv.m4 modules/putenv
diffstat 4 files changed, 49 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2013-02-14  Paul Eggert  <eggert@cs.ucla.edu>
+
+	putenv: fix heap corruption with mixed putenv/_putenv
+	Problem reported by Michael Goffioul in
+	<http://lists.gnu.org/archive/html/bug-gnulib/2013-02/msg00061.html>.
+	* lib/putenv.c (putenv) [HAVE__PUTENV]:
+	Rely on _putenv to allocate the new environment.
+	* m4/putenv.m4 (gl_PREREQ_PUTENV): New macro.
+	* modules/putenv (configure.ac): Use it.
+
 2013-02-11  Paul Eggert  <eggert@cs.ucla.edu>
 
 	unsetenv etc.: port to Solaris 11 + GNU Emacs
--- a/lib/putenv.c
+++ b/lib/putenv.c
@@ -115,6 +115,37 @@
 
   if (*ep == NULL)
     {
+#if HAVE__PUTENV
+      /* Rely on _putenv to allocate the new environment.  If other
+         parts of the application use _putenv, the !HAVE__PUTENV code
+         would fight over who owns the environ vector, causing a crash.  */
+      if (name_end[1])
+        return _putenv (string);
+      else
+        {
+          /* _putenv ("NAME=") unsets NAME, so invoke _putenv ("NAME=x")
+             to allocate the environ vector and then replace the new
+             entry with "NAME=".  */
+          int putenv_result, putenv_errno;
+          char *name_x = malloc (name_end - string + sizeof "=x");
+          if (!name_x)
+            return -1;
+          memcpy (name_x, string, name_end - string + 1);
+          name_x[name_end - string + 1] = 'x';
+          name_x[name_end - string + 2] = 0;
+          putenv_result = _putenv (name_x);
+          putenv_errno = errno;
+          for (ep = environ; *ep; ep++)
+            if (*ep == name_x)
+              {
+                *ep = string;
+                break;
+              }
+          free (name_x);
+          __set_errno (putenv_errno);
+          return putenv_result;
+        }
+#else
       static char **last_environ = NULL;
       char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
       if (new_environ == NULL)
@@ -126,6 +157,7 @@
       free (last_environ);
       last_environ = new_environ;
       environ = new_environ;
+#endif
     }
   else
     *ep = string;
--- a/m4/putenv.m4
+++ b/m4/putenv.m4
@@ -48,3 +48,9 @@
       ;;
   esac
 ])
+
+# Prerequisites of lib/putenv.c.
+AC_DEFUN([gl_PREREQ_PUTENV],
+[
+  AC_CHECK_FUNCS([_putenv])
+])
--- a/modules/putenv
+++ b/modules/putenv
@@ -14,6 +14,7 @@
 gl_FUNC_PUTENV
 if test $REPLACE_PUTENV = 1; then
   AC_LIBOBJ([putenv])
+  gl_PREREQ_PUTENV
 fi
 gl_STDLIB_MODULE_INDICATOR([putenv])
 
@@ -27,4 +28,3 @@
 
 Maintainer:
 Jim Meyering, glibc
-