about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Biggers <ebiggers3@gmail.com>2015-01-07 12:10:52 +0530
committerSiddhesh Poyarekar <siddhesh@redhat.com>2015-01-07 12:10:52 +0530
commitd5b1c5ed8bd9515505d4177f105c19ea375106ae (patch)
tree5e7164983b8a3e4f3a16e8069495a46c8c33d7b3
parentfb87ee96d7dd0714d52004e4676629f8d9db732f (diff)
downloadglibc-d5b1c5ed8bd9515505d4177f105c19ea375106ae.tar.gz
glibc-d5b1c5ed8bd9515505d4177f105c19ea375106ae.tar.xz
glibc-d5b1c5ed8bd9515505d4177f105c19ea375106ae.zip
setenv fix memory leak when setting large, duplicate string (BZ #17658)
glibc maintains a binary tree of environment strings it malloc()ed
itself.  However, it's possible for it to malloc() a string, then find
that an identical string is already in the tree.  In this case, the
memory is leaked and is not freed if the application later calls
__libc_freeres().  Fix this by freeing 'new_value' when it's unneeded.

Test case:
	#include <stdlib.h>
	#include <string.h>

	int main()
	{
		char *p = calloc(100000, 1);
		memset(p, 'A', 99999);
		setenv("TESTVAR", p, 1);
		setenv("TESTVAR", p, 1);
		free(p);
	}

Leak that was reported by valgrind:
	100,008 bytes in 1 blocks are definitely lost in loss record 1 of 1
	   at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
	   by 0x4E6B3D4: __add_to_environ (setenv.c:176)
	   by 0x4C31B8F: setenv (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
	   by 0x400642: main (in /mnt/tmpfs/a.out)
-rw-r--r--ChangeLog6
-rw-r--r--NEWS8
-rw-r--r--stdlib/setenv.c7
3 files changed, 17 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 9ca4f27338..653dfdd389 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2015-01-07  Eric Biggers  <ebiggers3@gmail.com>
+
+	[BZ #17658]
+	* stdlib/setenv.c: Fix memory leak when setting large,
+	duplicate string.
+
 2015-01-06  Vladimir A. Nazarenko  <naszar@ya.ru>
 
 .	[BZ #17273]
diff --git a/NEWS b/NEWS
index 85828857a0..bec70dc04c 100644
--- a/NEWS
+++ b/NEWS
@@ -14,10 +14,10 @@ Version 2.21
   17273, 17344, 17363, 17370, 17371, 17411, 17460, 17475, 17485, 17501,
   17506, 17508, 17522, 17555, 17570, 17571, 17572, 17573, 17574, 17581,
   17582, 17583, 17584, 17585, 17589, 17594, 17601, 17608, 17616, 17625,
-  17630, 17633, 17634, 17635, 17647, 17653, 17657, 17664, 17665, 17668,
-  17682, 17717, 17719, 17722, 17723, 17724, 17725, 17732, 17733, 17744,
-  17745, 17746, 17747, 17775, 17777, 17780, 17781, 17782, 17793, 17796,
-  17797, 17806
+  17630, 17633, 17634, 17635, 17647, 17653, 17657, 17658, 17664, 17665,
+  17668, 17682, 17717, 17719, 17722, 17723, 17724, 17725, 17732, 17733,
+  17744, 17745, 17746, 17747, 17775, 17777, 17780, 17781, 17782, 17793,
+  17796, 17797, 17806
 
 * i386 memcpy functions optimized with SSE2 unaligned load/store.
 
diff --git a/stdlib/setenv.c b/stdlib/setenv.c
index 710da1383c..b60c4f0151 100644
--- a/stdlib/setenv.c
+++ b/stdlib/setenv.c
@@ -217,6 +217,13 @@ __add_to_environ (name, value, combined, replace)
 	      /* And remember the value.  */
 	      STORE_VALUE (np);
 	    }
+#ifdef USE_TSEARCH
+	  else
+	    {
+	      if (__glibc_unlikely (! use_alloca))
+		free (new_value);
+	    }
+#endif
 	}
 
       *ep = np;