bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: declare a="$b" if $a previously set as array


From: Stephane Chazelas
Subject: Re: declare a="$b" if $a previously set as array
Date: Tue, 16 Dec 2014 21:49:58 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

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.GA5345@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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]