Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Sun, 13 Mar 2016 21:53:49 +0300
From: Alexander Monakov <amonakov@...ras.ru>
To: musl@...ts.openwall.com
Subject: [PATCH 2/3] env: remove duplicates when adding to environment

Potential presence of multiple entries for the same name in the
environment can be problematic for applications that mix libc calls
and direct lookups via 'environ'. Removing duplicates of the entry
being set via setenv/putenv is a simple partial mitigation.
---
This was raised recently on the glibc bugzilla, and Rich commented on IRC that
removing all duplicates in the environment at startup is costly, but we could
consider changing setenv/putenv to remove the duplicates of the entry being
set. I'm afraid that wouldn't help the applications that are actually
affected. However, since both setenv and putenv work via __putenv, the
corresponding patch is not too big, so here's one possible approach.

 src/env/putenv.c   |  3 ++-
 src/env/unsetenv.c | 21 +++++++++++++--------
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/src/env/putenv.c b/src/env/putenv.c
index 39a71be..facae1d 100644
--- a/src/env/putenv.c
+++ b/src/env/putenv.c
@@ -3,6 +3,7 @@
 #include "libc.h"
 
 char *__strchrnul(const char *, int);
+int __unsetenv(const char *, size_t, char **);
 
 static void dummy(char *p, char *r) {}
 weak_alias(dummy, __env_change);
@@ -16,7 +17,7 @@ int __putenv(char *s, size_t l, char *r)
 				char *tmp = __environ[i];
 				__environ[i] = s;
 				__env_change(tmp, r);
-				return 0;
+				return __unsetenv(s, l, __environ+i+1);
 			}
 	static char **oldenv;
 	char **newenv;
diff --git a/src/env/unsetenv.c b/src/env/unsetenv.c
index 86873cd..5e5727f 100644
--- a/src/env/unsetenv.c
+++ b/src/env/unsetenv.c
@@ -8,15 +8,9 @@ char *__strchrnul(const char *, int);
 static void dummy(char *p, char *r) {}
 weak_alias(dummy, __env_change);
 
-int unsetenv(const char *name)
+int __unsetenv(const char *name, size_t l, char **e)
 {
-	size_t l = __strchrnul(name, '=') - name;
-	if (!l || name[l]) {
-		errno = EINVAL;
-		return -1;
-	}
-	if (!__environ) return 0;
-	for (char **e = __environ; *e; e++)
+	for (; *e; e++)
 		while (*e && !strncmp(name, *e, l) && l[*e] == '=') {
 			char **ee = e, *tmp = *e;
 			do *ee = *(ee+1);
@@ -25,3 +19,14 @@ int unsetenv(const char *name)
 		}
 	return 0;
 }
+
+int unsetenv(const char *name)
+{
+	size_t l = __strchrnul(name, '=') - name;
+	if (!l || name[l]) {
+		errno = EINVAL;
+		return -1;
+	}
+	if (!__environ) return 0;
+	return __unsetenv(name, l, __environ);
+}
-- 
2.1.3

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.