2014-12-15 22:00:54 -0500, Chet Ramey: > On 12/14/14 4:44 PM, Stephane Chazelas wrote: > > > There's still a (security) issue with > > > > declare -x/-l/-r > > that may still be used in non-function contexts (not "export" or > > "readonly"), and as result for things like: > > > > saved=$(export -p var) > > ... > > eval "$saved" > > > > And with declare -g in functions, so probably still worth > > addressing. > > What's your proposal? Let's see if we can get to something concrete. > Something like what I proposed in one of my previous messages would > probably work to make
I believe my proposal in Message-ID: <20141214204845.ga5...@chaz.gmail.com> http://thread.gmane.org/gmane.comp.shells.bash.bugs/22737/focus=22789 would be the most consistent syntax. But that breaks compatibility especially as it means the output of declare -p on arrays would no longer work. Now, like Dan, I think we can have a middle ground that doesn't break backward compatibility as much but would remove most of the security concerns. I'm not sure I understood Dan's proposal correctly and we may very well mean the same thing. If we make it that: 1- words that form valid assignments are parsed as such, like 1.1 litteral array assignment. x=1 y=2 z='[7]' declare a=([x+y]=c $z=foo) treats it like a=([x+y]=c $z=foo) That is, if "a" was previously not an array or hash, it promotes it to an array and is like: a=([3]=c [4]=a [5]='[7]=foo') And if "a" was previously declared as a hash, we get a syntax error. And: declare a=(x) a[1]=(1 2 3) gives a "bash: a[1]: cannot assign list to array member" error, 1.2 litteral scalar assignment x="a b" y='($(uname))' declare $options a=$x b=~ c='(1 2)' d='($a)' e=$y those are *parsed* as scalar assignments in that ~ is expanded and $x doesn't undergo split+glob, but after that parsing and expansion is done, depending on whether -a/-A was passed or not, those "a=a b" "b=/home/stephane" "c=(1 2)" "d=($a)" "e=($(uname))" arguments are interpreted differently. If -a is passed, that becomes: a=([0]="a b") b=([0]="/home/stephane") c=([0]=1 [1]=2) d=([0]=a [1]=b) e=([0]=Linux) # second round of evaluation but if you didn't # want that you could still do e=("$y") (all variables promoted to arrays (or "cannot convert associative to indexed array" error if they were hashes)). If -A is passed, you get a syntax error because of the wrong c=(...) syntax. If none of those is passed, that's scalar assignment regardless of the current types of the variable. So setting $a or $a[0], so is like: a='a b' (or a[0]='a b' if a is an array or hash) b='/home/stephane' (or ...) c='(1 2)' (or c[0]='(1 2)'). d='($a)' e='($(uname))' declare $options a[1]='(1 2)' however sets a[1] to '(1 2)' regardless of whether -a, -A or neither is passed. 2. words that don't form valid assignments. Those are parsed as normal command line arguments. declare \a=(...) would get a syntax error because of the unexpected ( like with echo \a=(...). And the resulting words after expansion are treated like in 1.1 above. So, the main difference with the current behaviour would be that declare a='(1 2 3)' or: declare 'a=(1 2 3)' or declare a='([0]=a [1]=b)' would not be an array (or hash) assignment if a was previously declared as a hash or array. declare -a a='(1 2)' would still be but be deprecated in favour of: declare -a a=(1 2) or declare a=(1 2) declare -a a=$external_input would still be a command injection contrary to my earlier proposal, but in this case, it's unlikely one would do that (doesn't really make sense), or if they did (for instance because they did actually mean: eval "declare -a a=$external_input" then it's quite obvious that the input should be sanitised. declare a=([$external_input]=foo) declare a=([external_input]=foo) are also command injection vulnerabilities, but that's the same story with all arithmetic evaluation. -- Stephane