-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
problems with associative arrays in arithmetic expressions #152
Comments
Additional two examples: $ var='1$(uname>&2)' ksh -c 'typeset -A a; ((a[$var]++)); typeset -p a'
Darwin
typeset -A a=([1]=1)
$ var='1$(uname>&2)' ksh -c 'typeset -A a; ((a[\$var]++)); typeset -p a'
typeset -A a=(['1$(uname>&2)']=1)
$ var='1$(uname>&2)' ksh -c 'typeset -A a; ((a["$var"]++)); typeset -p a'
typeset -A a=(['1$(uname>&2)']=1) |
Another couple of examples: $ var='1$(uname>&2)' ksh -c 'typeset -A a; ((a[$var]++)); typeset -p a'
Darwin
typeset -A a=([1]=1)
$ var='1$(uname>&2)' ksh -c 'typeset -A a; ((a["\$var"]++)); typeset -p a'
typeset -A a=(['1$(uname>&2)']=1)
$
$ var='$0`uname>&2`' ksh -c 'typeset -A a; ((a[$var]++)); typeset -p a'
Darwin
typeset -A a=([ksh]=1)
$ var='$0`uname>&2`' ksh -c 'typeset -A a; ((a["\$var"]++)); typeset -p a'
typeset -A a=(['$0`uname>&2`']=1) |
Here are some examples using ((arithmetic)) instead of let: $ var='' ksh -c "typeset -A a; ((a[\$var]++)); typeset -p a"
typeset -A a=(['']=1)
$ var='\' ksh -c "typeset -A a; ((a[\$var]++)); typeset -p a"
typeset -A a=(['\']=1)
$ var=']' ksh -c "typeset -A a; ((a[\$var]++)); typeset -p a"
typeset -A a=([']']=1)
$ var='x]foo' ksh -c "typeset -A a; ((a[\$var]++)); typeset -p a"
typeset -A a=(['x]foo']=1) |
Here are some examples that have escaped the special characters in $ var="x\]+b\[\$(uname>&2)" ksh -c 'typeset -A a; ((a[$var]++)); typeset -p a'
Darwin
typeset -A a=(['x]+b[']=1)
$ var="x\]+b\[\$(uname>&2)" ksh -c 'typeset -A a; ((a[\$var]++)); typeset -p a'
typeset -A a=(['x]+b[$(uname>&2)']=1)
$ var="x\]+b\[\$(uname>&2)" ksh -c 'typeset -A a; ((a["$var"]++)); typeset -p a'
typeset -A a=(['x]+b[$(uname>&2)']=1)
$ var="x\]+b\[\$(uname>&2)" ksh -c 'typeset -A a; ((a["\$var"]++)); typeset -p a'
typeset -A a=(['x]+b[$(uname>&2)']=1) |
As a note, one can use $ var='x]+b[$(uname>&2)' ksh -c 'var=${ printf "%q" "$var" }; typeset -A a; ((a[$var]++)); typeset -p a var'
typeset -A a=(['x]+b[$(uname>&2)']=1)
typeset -x var=$'\'x]+b[$(uname>&2)\''
$
$ var='x]+b[$(uname>&2)' ksh -c 'var=$( printf "%q" "$var" ); typeset -A a; ((a[$var]++)); typeset -p a var'
typeset -A a=(['x]+b[$(uname>&2)']=1)
typeset -x var=$'\'x]+b[$(uname>&2)\''
$
$ var='x]+b[$(uname>&2)' zsh -c 'var=$( printf "%q" "$var" ); typeset -A a; ((a[$var]++)); typeset -p a var'
typeset -A a=( ['x]+b[$(uname\>\&2)']=1 )
export var='x\]+b\[\$\(uname\>\&2\)'
$
$ var='x]+b[$(uname>&2)' bash -c 'var=$( printf "%q" "$var" ); typeset -A a; ((a[$var]++)); typeset -p a var'
declare -A a=(["x]+b[\$(uname>&2)"]="1" )
declare -x var="x\\]+b\\[\\\$\\(uname\\>\\&2\\)"
$ |
No, that's not reliable either. See:
Still an ACE vulnerability:
It doesn't work in More generally, I wouldn't trust the output of |
I thought this was a sorta known issue. I attempted to describe it (tersely) here long ago and brought it up on bug-bash a few times, back around the time the (IMO wrong)
ksh93 has a lot more going on with its parsing of array indicies because:
Proper interpretation of issues such as this should bear in mind that proper implementation was probably supposed to be contingent upon completion of the sadly half-baked afterthought that is the |
If we make the diff --git a/src/cmd/ksh93/bltins/print.c b/src/cmd/ksh93/bltins/print.c
index 814f9fb8..8137b23f 100644
--- a/src/cmd/ksh93/bltins/print.c
+++ b/src/cmd/ksh93/bltins/print.c
@@ -109,6 +109,7 @@ static char* nullarg[] = { 0, 0 };
prdata.raw = prdata.echon = 0;
prdata.sh = context->shp;
NOT_USED(argc);
+abort();
/* This mess is because /bin/echo on BSD is different */
if(!prdata.sh->universe)
{ ...and then execute a version of Stéphane's reproducer that uses
...the resulting crash dump can probably give us an idea of where to look for a fix.
This quickly shows us that Sure enough, those lines are: Lines 164 to 165 in a61430f
It only looks for I find that if I comment those two lines out or delete them, I get zero regression test failures upon running
And regular variable expansions continue to work just fine for subscripts, as they are evidently handled elsewhere:
So, it looks like this is case number I-lost-count where a ksh93 bug is fixed by removing some evidently misguided code. I should find those again and make a list. diff --git a/src/cmd/ksh93/sh/arith.c b/src/cmd/ksh93/sh/arith.c
index 93de13cd..c78d5c37 100644
--- a/src/cmd/ksh93/sh/arith.c
+++ b/src/cmd/ksh93/sh/arith.c
@@ -161,8 +161,6 @@ static Namval_t *scope(register Namval_t *np,register struct lval *lvalue,int as
sfprintf(shp->strbuf,"%s%s%c",nv_name(np),sub,0);
sub = sfstruse(shp->strbuf);
}
- if(strchr(sub,'$'))
- sub = sh_mactrim(shp,sub,0);
*cp = flag;
if(c || hasdot)
{ |
These reproducers are not actually valid, because you're using double quotes for the |
This one appears to be fixed by the patch above: $ var='1$(uname>&2)' arch/*/bin/ksh -c 'typeset -A a; ((a[\$var]++)); typeset -p a'
typeset -A a=(['$var']=1)
This is the expected result. A variable in double quotes is expanded, and that is not different within an arithmetic command or arithmetic expansion. Unfortunately, the patch inserts some extra backslashes in the result: $ var='1$(uname>&2)' arch/*/bin/ksh -c 'typeset -A a; ((a["$var"]++)); typeset -p a'
typeset -A a=(['1$\(uname>\&2\)']=1) |
Wow! You have been busy. I experimented with those two lines deleted as described by your diff above. Seems like promising progress. |
This problem is fixed by removing the In fact I wonder if anything would break if we remove that So that's my theory/hypothesis now, let's see how that pans out... |
Sure enough: with the patch below, I get zero regression test failures. This includes all the reproducers in this thread, which I've turned into regression tests by now, and which will be committed along with the fix. diff --git a/src/cmd/ksh93/include/name.h b/src/cmd/ksh93/include/name.h
index f2fef412..bd727dfb 100644
--- a/src/cmd/ksh93/include/name.h
+++ b/src/cmd/ksh93/include/name.h
@@ -150,8 +150,6 @@ struct Ufunction
#define nv_funtree(n) ((n)->nvalue.rp->ptree)
#define funptr(n) ((n)->nvalue.bfp)
-#define NV_SUBQUOTE (NV_ADD<<1) /* used with nv_endsubscript */
-
/* NAMNOD MACROS */
/* ... for attributes */
diff --git a/src/cmd/ksh93/sh/arith.c b/src/cmd/ksh93/sh/arith.c
index 93de13cd..cfdbf747 100644
--- a/src/cmd/ksh93/sh/arith.c
+++ b/src/cmd/ksh93/sh/arith.c
@@ -161,8 +161,6 @@ static Namval_t *scope(register Namval_t *np,register struct lval *lvalue,int as
sfprintf(shp->strbuf,"%s%s%c",nv_name(np),sub,0);
sub = sfstruse(shp->strbuf);
}
- if(strchr(sub,'$'))
- sub = sh_mactrim(shp,sub,0);
*cp = flag;
if(c || hasdot)
{
@@ -171,9 +169,9 @@ static Namval_t *scope(register Namval_t *np,register struct lval *lvalue,int as
}
#if SHOPT_FIXEDARRAY
ap = nv_arrayptr(np);
- cp = nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE|(ap&&ap->fixed?NV_FARRAY:0));
+ cp = nv_endsubscript(np,sub,NV_ADD|(ap&&ap->fixed?NV_FARRAY:0));
#else
- cp = nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE);
+ cp = nv_endsubscript(np,sub,NV_ADD);
#endif /* SHOPT_FIXEDARRAY */
if(*cp!='[')
break;
@@ -270,7 +268,7 @@ static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdoubl
dot=NV_NOADD;
if((c = *++str) !='[')
continue;
- str = nv_endsubscript((Namval_t*)0,cp=str,NV_SUBQUOTE)-1;
+ str = nv_endsubscript((Namval_t*)0,cp=str,0)-1;
if(sh_checkid(cp+1,(char*)0))
str -=2;
}
diff --git a/src/cmd/ksh93/sh/array.c b/src/cmd/ksh93/sh/array.c
index 777c140d..4317bd00 100644
--- a/src/cmd/ksh93/sh/array.c
+++ b/src/cmd/ksh93/sh/array.c
@@ -1480,7 +1480,7 @@ char *nv_endsubscript(Namval_t *np, register char *cp, int mode)
/* first find matching ']' */
while(count>0 && (c= *++cp))
{
- if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@'))
+ if(c=='\\')
{
quoted=1;
cp++; |
For the historical record, now that we have @JohnoKing's ksh93-history repo, we can see that this vulnerability was introduced in version 2010-06-05 ksh93u-. The most relevant changelog entry seems to be:
Not very informative, particularly since no relevant regression test seems to have been committed along with it. |
The
uname
command was run, or in other words((a[$var]++))
is an arbitrary command execution vulnerability.That problem also affects
bash
andzsh
and is kind of known already.Yet in ksh93 (not bash nor zsh), this is OK:
Which suggests that some form of work around for that sort of issue is (partly) implemented in ksh93. It seems, it's the presence of
$
characters that cause the second interpretation:In bash and zsh, a work around is to use:
instead (note the single quotes).
But, in ksh93, it appears to be buggy for the empty key or for keys that contain
]
or\
characters:See more details at https://unix.stackexchange.com/questions/627474/how-to-use-associative-arrays-safely-inside-arithmetic-expressions
The text was updated successfully, but these errors were encountered: