-
Notifications
You must be signed in to change notification settings - Fork 560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[engineering.redhat.com #385443][CVE-2016-2381] security issue with multiple environment entries with the same name #15118
Comments
From @stephane-chazelasHello, this is a follow-up on an issue I reported last year to the It is a security issue in that it offers a way for attackers to (issue tested on a current Debian testing system). The issue: The execve(file, argp[], envp[]) system call executes "file" and There is typically no sanitizing done by the libc or the kernel That envp[] may contain strings that don't follow that The essence of the problem is that when that happens, executed To test, you can compile this simple executable: #include <unistd.h> Which is just a wrapper around execve(2). Called as: $ ./execve /bin/bash -c 'echo "$a"; env' EOA a=1 a=2 a=3 You can see here that bash sets its "a" variable from the *last* Other shells, languages or libraries dealing with the The bash, dash, mksh, fish, rc, yash shells and perl use the Among shells, only zsh and yash preserve the other entries. yash and perl have a bug in that even though they use the $ ./execve /usr/bin/perl -le 'print $ENV{a}; $ENV{a} = "x";system("env")' EOA a=1 a=2 a=3 Other tools I tested are consistent on that aspect. When assigning a new value to an env var (for example with What that means for instance is that on those systems where sh setenv("PATH=/bin:/sbin",1); /* sane value for PATH */ Would be vulnerable, because if called with "PATH=/tmp/evil", In the case of perl, that allows bypassing the taint mode (set $ ln -s /usr/bin/whoami uname Good, perl didn't let us call uname with an unsafe PATH, but: $ ./execve /usr/bin/perl -Te '$ENV{PATH}="/bin";system("uname;")' EOA PATH="$PWD" PATH="$PWD" Here, our "evil" (a symlink to whoami) uname was called, because For sudo, that affected variables passed along by sudo (like IMO, here is what should be done: - fix perl and yash so they get the first entry for a variable Some more information as already given for the benefit of the - I've verified that while one can modify the source code of an - (only informational), the only case I know of an application foo() { echo foo; }; foo=bar; export foo; export -f foo; cmd bash would pass both foo=bar and foo="() { echo foo; }" to Since shellshock, bash now passes foo=bar and -- |
From tg@mirbsd.deOn Mon, 4 Jan 2016 23:21:21 GMT, stephane.chazelas@gmail.com wrote: [�] Ouch! Good point.
Sorry, that�s not going to happen. Assignment must stay If you run� foo() { echo $x; } � you expect it to show 3, not 1, too � independend of I think the divergence is here that pdksh-based shells I would suggest letting the kernel deduplicate environ
This is something that, indeed, should be done, yes.
Ah, okay. Anyway, thanks for uncovering this� �what fun� � bye, |
From tg@mirbsd.deDixi quod�
Yes, ARG_MAX protects us from this being a DoS vector.
Fun fact: making getenv/putenv read and set the last ~/execve /usr/bin/perl -le 'print $ENV{a}; $ENV{a} = "x"; print $ENV{a}; system("env")' EOA a=1 a=2 a=3 a=4 a=5 � always prints the second-to-last value. Similarily,
This cannot be done, thus, without breaking existing Then I see only one way out of this misery: make the In the meantime, I studied what POSIX has to say; it (Note: I looked at Perl 5.8.8; later versions may or Although, one thing that *could* be done is to set bye, |
From tg@mirbsd.deDixi quod�
No, this won�t work either; Perl with -DPERL_USE_SAFE_PUTENV So, short of normalising the environment before any (That being said, I found a couple of bugs in MirBSD bye, |
From @stephane-chazelas2016-01-05 15:57:57 +0000, Thorsten Glaser:
Hi Thorsten, That's something different. Of course in the shell command line: x=1 x=2 x=3 foo we've got 3 variable assignments for the same variable, so one execve("foo", ["foo"], ["x=3"]) not execve("foo", ["foo"], ["x=1", "x=2", "x=3"]) (note that the Bourne shell (and IIRC earlier versions of ash) What I'm talking of here is the processing of the environment zsh and ksh93 already do the right thing. The problem I'm talking of here (at least the particular attack If the problem is fixed (shells assign $foo from the *first* Now that you mention hash tables, I wonder if putenv/setenv -- |
From @tonycozOn Mon Jan 04 15:22:04 2016, stephane.chazelas@gmail.com wrote:
The first of the attached patches does that by reversing the order
The second patch attempts to remove duplicates of an environment variable Tony |
From @tonycoz0001-perl-127158-reverse-initialization-of-ENV.patchFrom 9db49ead97699afd2030ae0c121a9ae7eb4a2a2f Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Wed, 6 Jan 2016 10:30:08 +1100
Subject: [perl #127158] reverse initialization of %ENV
On most platforms, if there are duplicate environment variables,
getenv() and setenv() get/modify the first entry found, make %ENV
consistent with that.
---
perl.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/perl.c b/perl.c
index b8d98ff..d33def9 100644
--- a/perl.c
+++ b/perl.c
@@ -4319,8 +4319,11 @@ S_init_postdump_symbols(pTHX_ int argc, char **argv, char **env)
if (env) {
char *s, *old_var;
SV *sv;
- for (; *env; env++) {
- old_var = *env;
+ char **env_start = env;
+ while (*env)
+ ++env;
+ while (env > env_start) {
+ old_var = *--env;
if (!(s = strchr(old_var,'=')) || s == old_var)
continue;
@@ -4330,10 +4333,10 @@ S_init_postdump_symbols(pTHX_ int argc, char **argv, char **env)
(void)strupr(old_var);
*s = '=';
#endif
- sv = newSVpv(s+1, 0);
- (void)hv_store(hv, old_var, s - old_var, sv, 0);
- if (env_is_not_environ)
- mg_set(sv);
+ sv = newSVpv(s+1, 0);
+ (void)hv_store(hv, old_var, s - old_var, sv, 0);
+ if (env_is_not_environ)
+ mg_set(sv);
}
}
#endif /* USE_ENVIRON_ARRAY */
--
2.1.4
|
From @tonycoz0002-perl-127158-remove-duplicates-in-my_setenv.patchFrom 57bed4c34abe49405a03403cf3d4d26699ec0ad0 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Wed, 6 Jan 2016 11:43:18 +1100
Subject: [perl #127158] remove duplicates in my_setenv()
It's possible for environ to contain duplicate definitions of an
environment variable, to ensure a child process sees only the
definition we remove any duplicates when a given variable is set.
The implementations of unsetenv() I've tested removed all of the
definitions, but POSIX is silent on how duplicate names are handled,
so explicitly unsetenv() the name until we're sure it's gone.
For the PERL_USE_SAFE_PUTENV case without unsetenv there's not really
anything we can do.
This needs tests, assuming I can find a way to to them.
---
util.c | 74 ++++++++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 47 insertions(+), 27 deletions(-)
diff --git a/util.c b/util.c
index 17b62dd..8f4514b 100644
--- a/util.c
+++ b/util.c
@@ -2148,30 +2148,47 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
tmpenv[max] = NULL;
environ = tmpenv; /* tell exec where it is now */
}
- if (!val) {
- safesysfree(environ[i]);
- while (environ[i]) {
- environ[i] = environ[i+1];
- i++;
+ if (val) {
+ if (!environ[i]) { /* does not exist yet */
+ environ = (char**)safesysrealloc(environ, (i+2) * sizeof(char*));
+ environ[i+1] = NULL; /* make sure it's null terminated */
+ }
+ else
+ safesysfree(environ[i]);
+ nlen = strlen(nam);
+ vlen = strlen(val);
+
+ environ[i] = (char*)safesysmalloc((nlen+vlen+2) * sizeof(char));
+ /* all that work just for this */
+ my_setenv_format(environ[i], nam, nlen, val, vlen);
+
+ /* look for a duplicate entry, if any */
+ for (i++; environ[i]; i++) {
+ if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
+ break;
}
-#ifdef __amigaos4__
- goto my_setenv_out;
-#else
- return;
-#endif
- }
- if (!environ[i]) { /* does not exist yet */
- environ = (char**)safesysrealloc(environ, (i+2) * sizeof(char*));
- environ[i+1] = NULL; /* make sure it's null terminated */
}
- else
+
+ if (environ[i]) { /* environ[i] is a match */
+ I32 from = i+1;
+
+ assert(strnEQ(environ[i],nam,len) && environ[i][len] == '=');
+
safesysfree(environ[i]);
- nlen = strlen(nam);
- vlen = strlen(val);
- environ[i] = (char*)safesysmalloc((nlen+vlen+2) * sizeof(char));
- /* all that work just for this */
- my_setenv_format(environ[i], nam, nlen, val, vlen);
+ /* remove any duplicate definitions */
+ while (environ[from]) {
+ if (strnEQ(environ[from],nam,len) && environ[from][len] == '=') {
+ safesysfree(environ[from]);
+ ++from;
+ }
+ else {
+ environ[i++] = environ[from++];
+ }
+ }
+ /* copy the NULL */
+ environ[i] = environ[from];
+ }
} else {
# endif
/* This next branch should only be called #if defined(HAS_SETENV), but
@@ -2180,9 +2197,10 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
*/
# if defined(__CYGWIN__)|| defined(__SYMBIAN32__) || defined(__riscos__) || (defined(__sun) && defined(HAS_UNSETENV))
# if defined(HAS_UNSETENV)
- if (val == NULL) {
- (void)unsetenv(nam);
- } else {
+ /* ensure any duplicates are removed */
+ while (PerlEnv_getenv(nam))
+ unsetenv(nam);
+ if (val) {
(void)setenv(nam, val, 1);
}
# else /* ! HAS_UNSETENV */
@@ -2190,10 +2208,12 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
# endif /* HAS_UNSETENV */
# else
# if defined(HAS_UNSETENV)
- if (val == NULL) {
- if (environ) /* old glibc can crash with null environ */
- (void)unsetenv(nam);
- } else {
+ /* ensure any duplicates are removed */
+ if (environ) { /* old glibc can crash with null environ */
+ while (PerlEnv_getenv(nam))
+ unsetenv(nam);
+ }
+ if (val) {
const int nlen = strlen(nam);
const int vlen = strlen(val);
char * const new_env =
--
2.1.4
|
The RT System itself - Status changed from 'new' to 'open' |
From krahmer@suse.comOn Tue, Jan 05, 2016 at 10:03:47PM +0000, Stephane CHAZELAS wrote: [...]
Worse. putenv/setenv reallocate and move stuff across the heap, I think the only thing we can do is sticking to what glibc properly handles insecure dups on AT_SECURE. Maybe POSIX allows -s -- ~ perl self.pl |
From @stephane-chazelas2016-01-06 11:00:42 +0100, Sebastian Krahmer:
But can any of the env entries that a program *received* (as Can setenv("x", "value") update anything else than the *first*
Well, the problem is that in: setenv("PATH=sane-value"); setenv updates only one of the PATH entries (in my experience Here, if we were to cast blame, that would partly on setenv()
What do you mean? They don't seem to be removed here (Linux Mint 17.3) for a $ ll env (according to ltrace, that "env" uses putenv(3)). -- |
From krahmer@suse.comOn Wed, Jan 06, 2016 at 01:08:19PM +0000, Stephane CHAZELAS wrote:
Thats implementation dependend of corse, so we have to assume
Yes, see above about _removing_ dups. Also note that this example
Removing any and all occurences of insecure env vars, including TL;DR: I ack the problem of environment variable dups, but patching Sebastian -- ~ perl self.pl |
From tg@mirbsd.deSebastian Krahmer dixit:
POSIX says that:
POSIX doesn�t say a single word about duplicates (I looked). I also think fixing this in the startup (kernel, ld.so, crt0) As for the first-vs.-last debate: I asked a random selection Tony Cook via RT dixit:
Please do *not* do that! bye, |
From tg@mirbsd.deSebastian Krahmer dixit:
That�s possible, and I had that as next step after�
� this, which was very easy to do in MirBSD libc, but it
Exactly.
POSIX says envp[] is not available because it would be de-synched;
clearenv() is explicitly not in POSIX, but you can use execve()
Indeed, which is why the de-duplication must happen at application
POSIX doesn�t say anything about duplicates, and I�d say go, but bye, |
From @stephane-chazelas2016-01-06 13:40:11 +0000, Thorsten Glaser:
Not sure what you asked them exactly, but I'd expect if you ask That's a mute point as that's something that is not meant to And which one it is doesn't matter anyway as long as everyone Would that break things though? Until now, at least on -- |
From tg@mirbsd.destephane.chazelas@gmail.com via RT dixit:
I asked them that, when I pass x=1 x=2 x=3 to a program in the
This is probably either due to actually using getenv/setenv env = {} I fail to see why there ought to be a distinction between
Getting everyone to agree probably will be a hell of fun�
Right.
You mean environ and envp. They are interchangable until the first setenv() with a But look at how main() gets called. I�m using the MirBSD The kernel loads the ELF binary and jumps to its entry The implementation of __start then reads some arguments � set environ to envp That means that the envp main() sees is not the envp Furthermore, we only d̲e̲duplicate here, i.e. we don�t I remember looking at how Linux does things, and it also Of course, doing this in the kernel would fix this the bye, |
From @stephane-chazelas2016-01-06 18:30:07 +0000, Thorsten Glaser:
FWIW, I did mean argv[] and envp[], as in they are just two [...]
But environ would be the address of the first pointer to the
Just the content of the pointers, the duplicate env values would
Yes, see the bottom of the stack is: argc argv-pointers envp-pointers argv-strings envp-strings.
Yes. True. It can potentially break things though. On the other hand, changing bash,dash,yash,mksh,fish,perl so putenv("PATH=sane-value"); with a fixed "sh" (one behaving like zsh or ksh93) can be -- |
From tg@mirbsd.de(Why isn�t dgk (the Korn in ksh) in the Cc list, anyway?) stephane.chazelas@gmail.com via RT dixit:
Well POSIX doesn�t guarantee it anyway.
And that is not going to change when we deduplicate.
Exactly. Even better if the kernel deduplicates, of course. That
Right, and we just make the envp-pointers a bit shorter
Every change can potentially break things. This is the
I don�t currently see enough reasons to change mksh to give Furthermore, this would make 'sh' and '(env;cat)|sh' out of sync bye, |
From @hvds"Tony Cook via RT" <perl5-security-report@perl.org> wrote: Technically, this looks good to me, independent of the discussion on :> - one could argue that setenv, putenv, or assigning env vars in Other than minor comments below, this also looks good. I'm a bit worried [...] For later: note that this (and the same in alternate branches below) is the :+ if (environ[i]) { /* environ[i] is a match */ I think this could do with a clearer comment, maybe something like: : # if defined(__CYGWIN__)|| defined(__SYMBIAN32__) || defined(__riscos__) || (defined(__sun) && defined(HAS_UNSETENV)) Note this context line will conflict on rebase, since blead now has :+ /* ensure any duplicates are removed */ I'm nervous of infinite loops here and in the unsetenv+putenv case below. : # else /* ! HAS_UNSETENV */ I think this and the putenv() case below need to comment that they won't Hugo |
From @tonycozOn Wed Jan 06 06:13:54 2016, mirabilos wrote:
One problem with the current behaviour is that the internals of perl (and XS code) that use getenv() and perl code can see two different values for an environment variable, eg: $ execve ./perl -Ilib -MPOSIX -le 'print $ENV{LANG}; print setlocale("");' EOA LANG=en_US.UTF-8 LANG=en_AU.UTF-8 Reversing the order fixes that when getenv() works in what seems to me to be the most obvious way (a linear search from the start of environ.) Another change I'm considering is aborting under -T if a duplicate is found. I can see that causing problems if anyone is creating an envp[] for execve() by copying environ[] and appending new definitions to the end without removing duplicates. Tony |
From tg@mirbsd.deTony Cook via RT dixit:
Unless that has changed since Perl 5.8.8, if you enable putenv,
Another point in favour of last-one-wins, and another point in bye, |
From @stephane-chazelas2016-01-06 20:02:44 -0800, Tony Cook via RT:
Yes, I had already mentioned that in my initial report but
Yes, and one of the big questions is indeed "can we rely (in
Sounds reasonable. As I noted earlier though, pre-shellshock
If they do, they're broken already, as that duplicate entry -- |
From @stephane-chazelasMessage RFC822: Hello, this is not an issue with sudo, but I think something sudo Consider this little C program: #define _GNU_SOURCE to be used as: ./a.out cmd... (on non-GNU systems, replace execvpe with execvp and cmd with That calls cmd with LC_ALL=tr_TR.UTF-8 twice in the environment. If I run it as: ./a.out sudo cmd That variable is still passed twice. Now, if we have a variable passed twice like that, the behaviour Some shells $LC_ALL (zsh, AT&T ksh) will get the first one, setenv() and putenv() on GNU, like zsh, yash, perl, ruby, python What that means is that if I have a program that does: putenv("LC_ALL=C"); /* make sure we're in a sane locale / Or: #!/usr/bin/perl Or: #! /usr/bin/ruby Or: #!/bin/zsh If the "sh" called by system() is based on dash/bash/pdksh which I like the tr_TR.UTF-8 locale in examples, because at least on LC_ALL is one of the variables passed along by sudo at least on Basically, the vulnerability we have here is a way to bypass I've not made a review of what software may be impacted, but IMO, the libc and sudo should strip those duplicates at least One could also argue that putenv/setenv or assigning env vars PoC: $ cat a.c -- |
From @stephane-chazelasHello, this is not an issue with sudo, but I think something sudo Consider this little C program: #define _GNU_SOURCE to be used as: ./a.out cmd... (on non-GNU systems, replace execvpe with execvp and cmd with That calls cmd with LC_ALL=tr_TR.UTF-8 twice in the environment. If I run it as: ./a.out sudo cmd That variable is still passed twice. Now, if we have a variable passed twice like that, the behaviour Some shells $LC_ALL (zsh, AT&T ksh) will get the first one, setenv() and putenv() on GNU, like zsh, yash, perl, ruby, python What that means is that if I have a program that does: putenv("LC_ALL=C"); /* make sure we're in a sane locale */ Or: #!/usr/bin/perl Or: #! /usr/bin/ruby Or: #!/bin/zsh If the "sh" called by system() is based on dash/bash/pdksh which I like the tr_TR.UTF-8 locale in examples, because at least on LC_ALL is one of the variables passed along by sudo at least on Basically, the vulnerability we have here is a way to bypass I've not made a review of what software may be impacted, but IMO, the libc and sudo should strip those duplicates at least One could also argue that putenv/setenv or assigning env vars PoC: $ cat a.c -- |
From @rjbsIt seems to me like the sanest, simplest, and least confusing thing is to use Tony Cook's two patches to (a) make perl's env have the same contents you'd get from a linear search and (b) clean up dupes on set. Tony and I briefly discussed the possibility of cleaning up the environment itself on boot, but it didn't seem like a good way forward. As for barfing on ambiguous environments: * I'd love doing that always if I felt more sure that it was nearly never the case in sane operation (but I really don't feel that way) -- |
From @jhiOn Monday-201601-11 18:37, Ricardo SIGNES via RT wrote:
Croak by default but have an environment variable env PERL_ALLOW_DUP_ENV_FULL_SPEED_AHEAD_AND_DAMN_THE_TORPEDOES=1 ... would be playing on the "safe by default" side, while still allowing a |
From @tonycozOn Mon, Jan 11, 2016 at 06:42:36PM -0500, Jarkko Hietaniemi wrote:
Do you know if VMS can have multiple definitions of the same name in Tony |
From @jhiI don't know VMS that intimately but I would suspect it does not, If we don't have Craig in perl-security, we should. On Mon, Jan 11, 2016 at 6:49 PM, Tony Cook <tony@develop-help.com> wrote:
-- |
From @rjbsOn Mon Jan 11 15:43:05 2016, jhi wrote:
So, my concern with that is something like this: If ambiguous environments are created by (possibly half-baked programs written in) shells, and those are the only places where this is going to approach "common" in the wild, then we're going to see zero reports of failure until things are failing on production systems. Lots of people smoke their applications and libraries on bleadperl, but nobody "smokes" their production systems, cron jobs, glue, and so on. They also tend to run that stuff against system perl, meaning that they won't see the breakage when v5.x.0 comes out, but some years later when their scripts are ported to the new company standard, Excited Egret. Changes that will affect "the stuff sysadmins do" are the changes where I feel we must be the most careful. So, with that in mind, are we better off having perl bail or having it change to use the first value? It's not entirely clear. Either way (putting aside the case where (X=1) is found multiple times in env), the behavior changes. My gut says that we're better off having programs still run, although I'm not sure I have any strong argument to make in favor of it. -- |
From @rjbsOn Mon Jan 11 15:57:32 2016, jhi wrote:
Tony noted his absence and I sent him an invite earlier this evening. If he declines to join I'll at least get him to consult on this ticket. -- |
From @craigberryI've reflected a bit more on this and concluded that as far as handling duplicates in the C run-time's environ array, nothing special needs to be done for VMS. We don't currently run perl.c:S_init_postdump_symbols, but I think we should and will enable it shortly. At which point Tony's first patch to take the first entry passed in when there are duplicates will do the same for us as anybody else. VMS doesn't and mustn't use util.c:Perl_my_setenv because of all the special magic in vms.c:Perl_vmssetenv, so Tony's second patch won't have any effect on VMS. As of cda27dc, vms.c:Perl_vmssetenv now uses the CRTL's unsetenv when removing something from the environ array. unsetenv has been available for twenty years and is documented to remove all versions when there's more than one. I've tested it and it works as advertised, so we're ok there. Now to the fact that %ENV is concocted from multiple sources on VMS and one of those sources (logical names) has multiple layers, and that deleting a key in %ENV could thus leave another value for the same key visible. There are multiple problems with trying to change that to delete all versions: 1.) It breaks documented behavior. So I think I need to leave things as is for now, but at least there is nothing VMS-related that stands in the way of proceeding with other changes discussed here. |
From @stephane-chazelas2016-01-21 12:08:38 -0500, Red Hat Product Security:
perl is possibly the most severely impacted (bypass of taint From the discussion here, they've discussed changing their %ENV Once that's done that would probably fix it on most systems, Personaly, I'm happy for the discussion to go to libc-alpha as If anybody has any objection to the issue being made public, -- |
From @fweimer* Red Hat Product Security:
I agree with what Stefan wrote above. It's a local issue only, and And as I wrote, this has been documented as a source of security Thanks, |
From @jhiOn Thu Jan 21 10:22:44 2016, fw@deneb.enyo.de wrote:
glibc (and correspondingly, the libc-alpha mailing list) specific discussion might not be directly relevant (*) to the BSD folks (I see at least Todd Miller on the CC list, and @mirbsd) Anyone here from FreeBSD? NetBSD? Or Apple? (*) Though, of course, while any particular patches for glibc will not directly applicable to non-glibc lands, in spirit and intent they might be useful. Maybe there needs to be three different "forks" of this discussion: the glibc, the *BSD camp, and then the shells/perl. (Non-UNIX environments, which at least Perl covers, are then yet another dimension, each their own.) But until there's some sort of general overall plan and rough consensus (anyone care to attempt a summary?), such forking of discussion is probably premature.
|
From @rjbs* Stephane CHAZELAS <stephane.chazelas@gmail.com> [2016-01-21T12:39:08]
Yes, and I think we need to apply that. Also, because this affects the taint Tony Cook is producing an updated patch, which I'll be distributing downstream.
Although I wouldn't object to the immediate discussion of the problem in Thanks for your patience in waiting for a reply. I have been neglecting my -- |
From @craigberryOn Mon, Jan 18, 2016 at 12:47 PM, Craig A. Berry via RT
I've done further testing and now think the parts of Inline Patch--- vms/vms.c;-0 2016-01-16 18:36:16 -0600
+++ vms/vms.c 2016-01-21 15:51:27 -0600
@@ -1307,7 +1307,9 @@ prime_env_iter(void)
if (!str$case_blind_compare(env_tables[i],&crtlenv)) {
char *start;
int j;
- for (j = 0; environ[j]; j++) {
+ /* Start at the end, so if there is a duplicate we keep the first one. */
+ for (j = 0; environ[j]; j++);
+ for (j--; j >= 0; j--) {
if (!(start = strchr(environ[j],'='))) {
if (ckWARN(WARN_INTERNAL))
Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed
CRTL environ value \"%s\"\n",environ[j]); |
From @craigberryno_dup_env_vms.patch--- vms/vms.c;-0 2016-01-16 18:36:16 -0600
+++ vms/vms.c 2016-01-21 15:51:27 -0600
@@ -1307,7 +1307,9 @@ prime_env_iter(void)
if (!str$case_blind_compare(env_tables[i],&crtlenv)) {
char *start;
int j;
- for (j = 0; environ[j]; j++) {
+ /* Start at the end, so if there is a duplicate we keep the first one. */
+ for (j = 0; environ[j]; j++);
+ for (j--; j >= 0; j--) {
if (!(start = strchr(environ[j],'='))) {
if (ckWARN(WARN_INTERNAL))
Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed CRTL environ value \"%s\"\n",environ[j]);
|
From @stephane-chazelas2016-01-21 12:08:38 -0500, Red Hat Product Security:
Also note that doing it at the libc level means Also, if perl fixes it with a CVE, it's going to become very I'm under the impression that fixing bash and BSDs sh (and perl A deduplicating at the libc/kernel level would still be a good I suspect it may be difficult to get a consensus among Unix -- |
From tg@mirbsd.destephane.chazelas@gmail.com via RT dixit:
Linux: Hurd: I only know of glibc � plus at least one libc per BSD, but they also have one I�d *really* prefer this to be fixed in the various kernels Now my own stance: BSD OS developer PoV: I�m likely to fix it in the kernel mksh tool PoV: I�m not going to change mksh; it will always bye, |
From @stephane-chazelas2016-01-26 09:46:48 -0800, Thorsten Glaser via RT:
I'm not sure I understand that argument. mksh deduplicates the environment already. So if you dump the environmnet from mksh, you'll see only one Importing that dump will set the same variable. If you change that to be the first one, still deduplicated, you Can you please clarify what would break if you changed mksh? -- |
From tg@mirbsd.destephane.chazelas@gmail.com via RT dixit:
Yes, but you can dump it from a called program instead.
Consistency � the notation of the environment as a set of bye, |
From @jhi
I think we need to think of defense in depth here: libc/kernel *and* the It's not like every system will want to / will be able to / will ever |
From @tonycozOn Mon Jan 25 21:09:09 2016, perl.security@rjbs.manxome.org wrote:
It's not so much an updated patch, but a new patch. This uses a different approach, rather than de-dupping a given name in environ[] on my_setenv() it scans for duplicates when we load %ENV, and if it finds any, removes them. Unlike the previous patch, where every use of my_setenv() paid a cost for the possibility of duplicate entries, for this patch there's (mostly) only a cost when duplicate entries are found. ("mostly" because there's an extra hv_exists() call perl entry on the non-duplicates path.) Tony |
From @tonycoz0001-perl-127158-remove-duplicate-environment-variables-f.patchFrom 8a5c18363465c8ce7477dfa604afad6be02d8726 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Wed, 27 Jan 2016 11:52:15 +1100
Subject: [perl #127158] remove duplicate environment variables from environ
If we see duplicate environment variables while iterating over
environ[]:
a) make sure we use the same value in %ENV that getenv() returns.
Previously on a duplicate, %ENV would have the last entry for the name
from environ[], but a typical getenv() would return the first entry.
Rather than assuming all getenv() implementations return the first entry
explicitly call getenv() to ensure they agree.
b) remove duplicate entries from environ
Previously if there was a duplicate definition for a name in environ[]
setting that name in %ENV could result in an unsafe value being passed
to a child process, so ensure environ[] has no duplicates.
---
perl.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 49 insertions(+), 2 deletions(-)
diff --git a/perl.c b/perl.c
index c7c1fe6..f33222b 100644
--- a/perl.c
+++ b/perl.c
@@ -4320,23 +4320,70 @@ S_init_postdump_symbols(pTHX_ int argc, char **argv, char **env)
}
if (env) {
char *s, *old_var;
+ STRLEN nlen;
SV *sv;
+ HV *dups = newHV();
+
for (; *env; env++) {
old_var = *env;
if (!(s = strchr(old_var,'=')) || s == old_var)
continue;
+ nlen = s - old_var;
#if defined(MSDOS) && !defined(DJGPP)
*s = '\0';
(void)strupr(old_var);
*s = '=';
#endif
- sv = newSVpv(s+1, 0);
- (void)hv_store(hv, old_var, s - old_var, sv, 0);
+ if (hv_exists(hv, old_var, nlen)) {
+ const char *name = savepvn(old_var, nlen);
+
+ /* make sure we use the same value as getenv(), otherwise code that
+ uses getenv() (like setlocale()) might see a different value to %ENV
+ */
+ sv = newSVpv(PerlEnv_getenv(name), 0);
+
+ /* keep a count of the dups of this name so we can de-dup environ later */
+ if (hv_exists(dups, name, nlen))
+ ++SvIVX(*hv_fetch(dups, name, nlen, 0));
+ else
+ (void)hv_store(dups, name, nlen, newSViv(1), 0);
+
+ Safefree(name);
+ }
+ else {
+ sv = newSVpv(s+1, 0);
+ }
+ (void)hv_store(hv, old_var, nlen, sv, 0);
if (env_is_not_environ)
mg_set(sv);
}
+ if (HvKEYS(dups)) {
+ /* environ has some duplicate definitions, remove them */
+ HE *entry;
+ hv_iterinit(dups);
+ while ((entry = hv_iternext_flags(dups, 0))) {
+ STRLEN nlen;
+ const char *name = HePV(entry, nlen);
+ IV count = SvIV(HeVAL(entry));
+ IV i;
+ SV **valp = hv_fetch(hv, name, nlen, 0);
+
+ assert(valp);
+
+ /* try to remove any duplicate names, depending on the
+ * implementation used in my_setenv() the iteration might
+ * not be necessary, but let's be safe.
+ */
+ for (i = 0; i < count; ++i)
+ my_setenv(name, 0);
+
+ /* and set it back to the value we set $ENV{name} to */
+ my_setenv(name, SvPV_nolen(*valp));
+ }
+ }
+ SvREFCNT_dec_NN(dups);
}
#endif /* USE_ENVIRON_ARRAY */
#endif /* !PERL_MICRO */
--
2.1.4
|
From @rjbs* Jarkko Hietaniemi <jhi@iki.fi> [2016-01-26T13:45:07]
This is my position as well. Of course I would like everyone to have all the -- |
From @rjbs* Stephane CHAZELAS <stephane.chazelas@gmail.com> [2016-01-26T12:27:02]
Yes. I suppose we can try to coordinate at least *some* of the many affected Chet, would you, at any rate, like to do that? I have not yet started notification for this problem, as we just got another -- |
From chet.ramey@case.edu-----BEGIN PGP SIGNED MESSAGE----- On 1/26/16 10:57 PM, Ricardo Signes wrote:
I'm not enthusiastic about any of the proposed `solutions'. Stephane's I'm sympathetic to Thorsten's argument that the environment is an ordered The question is whether `fixing' shells and other programs to behave like Chet iEYEARECAAYFAlao8zQACgkQu1hp8GTqdKvIeACfcaZhMJrrEIHkAxSlNooz/e01 |
From @stephane-chazelas2016-01-27 11:41:34 -0500, Chet Ramey:
The argument is that if we do it differently from perl's latest approach to actually call getenv to assign %ENV
both of which are pathological cases. (And for the first case, Again changing bash won't break anything. Two env variables with
One consideration is that "fixing" bash once now will fix it I agree we should fix the root case, but "fixing" bash won't do -- |
From @rjbs* Stephane CHAZELAS <stephane.chazelas@gmail.com> [2016-01-27T12:20:17]
I agree with Stephane here, but let me put that agreement aside for a moment: So, perl has to make a change. We can hold off a bit on making the change in -- |
From @stephane-chazelas2016-01-27 17:20:17 +0000, Stephane CHAZELAS:
For the record, it would seem the "issue" was "fixed" (though it http://www.zsh.org/mla/workers/1997/msg00555.html (while importing variables from the environment, don't import -- |
From @stephane-chazelasOn 28 January 2016 at 10:44, Stephane CHAZELAS
Sorry, my bad. That commit actually did mention that it was doing the It was actually fixed by this commit: (again not specifically to address the vulnerability) -- |
From @rjbs* Tony Cook via RT <perl5-security-report@perl.org> [2016-01-26T20:04:03]
This got a bit derailled by a failed attempt to coordinate disclosure. Nothing Craig: this also includes your vms.c patch. I made matching branches for 5.22 and 5.20. -- |
From @rjbsThe Perl ENV problems have been assigned CVE-2016-2381. -- |
From @fweimer* Florian Weimer:
Now that the issue is public, I filed a glibc bug for it: <https://sourceware.org/bugzilla/show_bug.cgi?id=19749> Thanks, |
From @tonycozOn Tue Mar 01 07:47:40 2016, fw@deneb.enyo.de wrote:
Is there anything that's been discussed in this thread that anyone doesn't want public yet? Tony |
From @tonycozOn Wed Mar 02 15:19:13 2016, tonyc wrote:
Now public. Tony |
@tonycoz - Status changed from 'open' to 'pending release' |
From @khwilliamsonThank you for submitting this report. You have helped make Perl better. Perl 5.24.0 may be downloaded via https://metacpan.org/release/RJBS/perl-5.24.0 |
@khwilliamson - Status changed from 'pending release' to 'resolved' |
Migrated from rt.perl.org#127158 (status was 'resolved')
Searchable as RT127158$
The text was updated successfully, but these errors were encountered: