Bug 1147645

Summary: Bash fix for CVE-2014-7169 breaks ksh scripts that try to clear the environment
Product: Red Hat Enterprise Linux 6 Reporter: Karl Hastings <kasmith>
Component: kshAssignee: Michal Hlavinka <mhlavink>
Status: CLOSED ERRATA QA Contact: Martin Kyral <mkyral>
Severity: urgent Docs Contact:
Priority: urgent    
Version: 6.5CC: dkutalek, dsulliva, eblake, fkrska, fweimer, henk, jonstanley, kdudka, mhlavink, mkyral, ovasik
Target Milestone: rcKeywords: ZStream
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: ksh-20120801-23.el6 Doc Type: Bug Fix
Doc Text:
Previously, the ksh shell did not filter environment variables it inherited. As a result, the ksh environment contained variables that ksh was not able to use or unset. This updated version filters variables during initialization, and thus no longer inherits variables that are invalid for ksh. As a result, ksh functions can now use all variables present in the environment. Note that this filtering does not alter the environment passed to the processes started from ksh.
Story Points: ---
Clone Of:
: 1148036 1195647 1195648 1195655 1211538 (view as bug list) Environment:
Last Closed: 2015-07-22 06:56:03 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1075802, 1148036, 1148070, 1159926, 1195647, 1195648, 1211538    

Description Karl Hastings 2014-09-29 17:01:18 UTC
Description of problem:
ksh scripts that try to unset the BASH_FUNC_*() variables fail.

Version-Release number of selected component (if applicable):
01211354

How reproducible:
100%

Steps to Reproduce:
[user@hose ~]$ a() { 
> echo test
> }
[user@host ~]$ set | fgrep BASH_FUNC
[user@host ~]$ export -f a
[user@host ~]$ ksh
$ set | fgrep BASH_FUNC
BASH_FUNC_a()=$'() {  echo test\n}'
BASH_FUNC_module()=$'() {  eval `/usr/bin/modulecmd bash $*`\n}'
$ 

This might not be an issue, except if you try to unset it to clean up your environment:

$ unset 'BASH_FUNC_a()'
ksh: unset: BASH_FUNC_a(): invalid variable name
$ 


Actual results:
If perhaps you are being careful and use 'set -e' the entire script dies causing significant issues...

Expected results:
ksh should be able to clear it's environment...

Additional info:
'man ksh' describes that metacharacters are not valid in variable names:
 ;   &   (   )   |   <   >   new-line   space   tab

The upstream bash fix is using %% for the fix (perhaps for this reason?)...
http://ftp.gnu.org/gnu/bash/bash-4.3-patches/bash43-027

Comment 3 Florian Weimer 2014-09-29 17:28:55 UTC
(In reply to Karl Hastings from comment #0)
> The upstream bash fix is using %% for the fix (perhaps for this reason?)...
> http://ftp.gnu.org/gnu/bash/bash-4.3-patches/bash43-027

As far as I can tell, this makes no difference.

$ unset a%%
ksh: unset: a%%: invalid variable name

Comment 4 Eric Blake 2014-09-29 17:38:04 UTC
Why is ksh exposing variables through 'set' that it then will not allow to be unset? That sounds like a problem in ksh that existed prior to the bash fix.  Bash intentionally refuses to expose any inherited name/value pair from the environment through 'set' if the name does not match what bash is able to handle.

Comment 5 Eric Blake 2014-09-29 17:40:02 UTC
As proof that bash refuses to expose garbage through 'set':

$ env 'a|b=c' bash -c 'set | grep a.b'
BASH_EXECUTION_STRING='set | grep a.b'
$ env 'a|b=c' ksh -c 'set | grep a.b'
a|b=c

Comment 6 Michal Hlavinka 2014-09-30 08:46:44 UTC
Removed Regression keyword - this never worked in ksh.

This is not a bug, as it's not a proper variable from ksh's point of view.

Excerpt from POSIX (http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html):

Environment variable names used by the utilities in the Shell and Utilities volume of IEEE Std 1003.1-2001 consist solely of uppercase letters, digits, and the '_' (underscore) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names.

And tolerate it's existence is exactly what ksh does, nothing more, nothing less.

Anyway, I will ask upstream if they want to change this.

Comment 7 Michal Hlavinka 2014-09-30 08:50:01 UTC
PS: There won't be any visible change anyway. As per posix request, those variables are tolerated, but as they are not recognized by ksh, you won't be able to print them, change them or unset them. Even if they won't be listed in set's output, they will still be passed to children.

Comment 8 Jon Stanley 2014-09-30 12:11:18 UTC
(In reply to Michal Hlavinka from comment #6)
> This is not a bug, as it's not a proper variable from ksh's point of view.

It seems to be a bug to me to expose something via a shell built-in that you will not then allow to be undone using the reverse shell built-in, e.g. unset. The user visible change from suppressing the output from 'set' would be that something like the following would work and not cause a shell script to bomb.

bash$ ksh
ksh$  envkeep="^PATH|^LOGNAME|^PS1"
ksh$ export envkeep
ksh$ set -e
ksh$  for var in $(set | egrep -v $envkeep |  awk -F= '{print $1}') ; do echo $var ; unset $var ; done
_
BASH_FUNC_a()
ksh: unset: BASH_FUNC_a(): invalid variable name
bash$

Comment 9 Jon Stanley 2014-09-30 12:20:57 UTC
(In reply to Jon Stanley from comment #8)
> The user visible change from suppressing the output from 'set' would
> be that something like the following would work and not cause a shell script
> to bomb.

Of course, in this example BASH_FUNC_a() would continue to be exported to children, and that's fine and expected. If that's what you meant by no user-visible change, then I agree with that :)

Comment 10 Michal Hlavinka 2014-09-30 12:41:26 UTC
The "bomb" is a little strong wording here imho :)

The fact is that such variable would stay in the environment either way.

So you can't expect that the example you've pasted would clear everything. Which is equal to unset failure (for whatever reason). If you use something like 'env' instead of 'set' you would get that unwanted variable even in case that set would change its behavior. So, from my point of view that change would not achieve much (I would say anything at all).

Anyway, the patch itself is not a problem, it'd be really simple, but upstream's opinion is what matters here - whether that patch would be accepted or not. I've asked them already. Waiting for answer. (Beware, it can take a while.)

Comment 11 Eric Blake 2014-09-30 14:55:01 UTC
dash has a similar problem.  By the way, POSIX further requires that 'set' used without parameters shall have the following property:
"The output shall be suitable for reinput to the shell, setting or resetting, as far as possible, the variables that are currently set;"

which means 'eval $(set)' should be safe; but trying to eval "a|b=''" tries to invoke the command named 'a', which is NOT safe.

Comment 12 Jon Stanley 2014-09-30 21:30:45 UTC
Actually, it looks to me like this *is* a regression in ksh.

From ksh-20100621-19.el6_4.3.x86_64:

$ set|fgrep BASH_FUNC
BASH_FUNC_module()=$'() {  eval `/usr/bin/modulecmd bash $*`\n}'

From ksh-20100621-6.el6.x86_64 on the same box (I just rpm2cpio'ed the rpm and ran bin/ksh93):

$ set | fgrep BASH_FUNC
$ exit

Also, Eric's 'a|b' test above in comment #5 also delivers the expected result. The only reason I noticed that was I was scratching my head as to why I couldn't reproduce on another, older box.

Comment 13 Michal Hlavinka 2014-10-01 08:49:00 UTC
Seems upstream agrees with fixing this.

Comment 24 errata-xmlrpc 2015-07-22 06:56:03 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://rhn.redhat.com/errata/RHBA-2015-1450.html