mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-13 03:32:24 +00:00
-o posix: don't import/export variable attributes thru environment
When exporting variables, ksh exports their attributes (such as 'integer' or 'readonly') in a magic environment variable called "A__z" (string defined in e_envmarker[] in data/msg.c). Child shells recognise that variable and restore the attributes. This little-known feature is risky; the environment cannot necessarily be trusted and that A__z variable is easy to manipulate before or between ksh invocations, so you can cause a script's variables to be of the wrong type, or readonly. Backwards compatibility requires keeping it, at least for now. But it should be disabled in the posix mode, as it violates POSIX. To do this, we have to solve a catch-22 in init.c. We must parse options to know whether to turn on posix mode; it may be specified as '-o posix' on the command line. The option parsing loop depends on an initialised environment[*], while environment initialisation (i.e., importing attributes) should depend on the posix option. The catch-22 can be solved because initialising just the values before option parsing is enough to avoid regressions. Importing the attributes can be delayed until after option parsing. That involves basically splitting env_init() into two parts while keeping a local static state variable between them. src/cmd/ksh93/sh/init.c: - env_init(): * Split the function in two stages based on a new 'import_attributes' parameter. Import values in the first stage; import attributes from A__z in the second (if ever). Make the 'next' variable static as it keeps a state needed for the attributes import stage. * Single point of truth, greppability: don't hardcode "A__z" in separate character comparisons, but use e_envmarker[]. * Fix an indentation error. - sh_init(): When initialising the environment (env_init), don't import the attributes from A__z yet; parse options first, then import attributes only if posix option is not set. src/cmd/ksh93/sh/name.c: - sh_envgen(): Don't export variable attributes to A__z if the posix option is set. src/cmd/ksh93/tests/attributes.sh: - Check that variable attributes aren't imported or exported if the POSIX option is set. src/cmd/ksh93/sh.1: - Update. This was the last item on the TODO list for -o posix for now. Closes: #20 [*] If environment initialisation is delayed until after option parsing, bin/shtests shows various regressions, including: restricted mode breaks; the locale is not initialised properly so that multibyte variable names break; $SHLVL breaks.
This commit is contained in:
parent
20fcf22973
commit
00d439605f
5 changed files with 51 additions and 19 deletions
2
NEWS
2
NEWS
|
@ -27,6 +27,8 @@ Any uppercase BUG_* names are modernish shell bug IDs.
|
|||
(this keeps the 2020-05-13 BUG_REDIRIO fix for the POSIX mode while
|
||||
restoring traditional ksh93 behaviour for backwards compatibility)
|
||||
* disables a noncompliant 'test -t' == 'test -t 1' compatibility hack
|
||||
* disables passing an exported variable's attributes (such as integer or
|
||||
readonly) to a new ksh process through the environment
|
||||
|
||||
2020-08-19:
|
||||
|
||||
|
|
|
@ -980,8 +980,9 @@ The attributes supported by the shell are described
|
|||
later with the
|
||||
.B typeset\^
|
||||
special built-in command.
|
||||
Exported variables pass values and attributes to
|
||||
the environment.
|
||||
Exported variables pass their attributes to the environment so that a newly
|
||||
invoked ksh that is a child or exec'ed process of the current shell will
|
||||
automatically import them, unless the \fBposix\fR shell option is on.
|
||||
.PP
|
||||
The shell supports both indexed and associative arrays.
|
||||
An element of an array variable is referenced by a
|
||||
|
@ -7040,6 +7041,7 @@ to fail or zero if no command has failed.
|
|||
.B posix
|
||||
Enable full POSIX standard compliance mode. This option
|
||||
is on by default if ksh is invoked as \fBsh\fR. It
|
||||
disables passing exported variables' attributes (such as integer or readonly) to a new ksh process through the environment,
|
||||
causes file descriptors > 2 to be left open when invoking another program,
|
||||
makes the \fB<>\fR redirection operator default to standard input,
|
||||
disables a hack that makes \fBtest -t\fR (\fB[ -t ]\fR) equivalent to \fBtest -t 1\fR (\fB[ -t 1 ]\fR),
|
||||
|
|
|
@ -199,7 +199,7 @@ typedef struct _init_
|
|||
static Init_t *ip;
|
||||
static int lctype;
|
||||
static int nbltins;
|
||||
static void env_init(Shell_t*);
|
||||
static void env_init(Shell_t*,int);
|
||||
static Init_t *nv_init(Shell_t*);
|
||||
static Dt_t *inittree(Shell_t*,const struct shtable2*);
|
||||
static int shlvl;
|
||||
|
@ -1285,7 +1285,7 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
|
|||
stakinstall(NIL(Stak_t*),nospace);
|
||||
/* set up memory for name-value pairs */
|
||||
shp->init_context = nv_init(shp);
|
||||
/* read the environment */
|
||||
/* initialize shell type */
|
||||
if(argc>0)
|
||||
{
|
||||
type = sh_type(*argv);
|
||||
|
@ -1294,7 +1294,8 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
|
|||
if(type&SH_TYPE_POSIX)
|
||||
sh_onoption(SH_POSIX);
|
||||
}
|
||||
env_init(shp);
|
||||
/* read the environment; don't import attributes yet */
|
||||
env_init(shp,0);
|
||||
if(!ENVNOD->nvalue.cp)
|
||||
{
|
||||
sfprintf(shp->strbuf,"%s/.kshrc",nv_getval(HOME));
|
||||
|
@ -1395,6 +1396,9 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
|
|||
beenhere = 2;
|
||||
}
|
||||
}
|
||||
/* import variable attributes from environment */
|
||||
if(!sh_isoption(SH_POSIX))
|
||||
env_init(shp,1);
|
||||
#if SHOPT_PFSH
|
||||
if (sh_isoption(SH_PFSH))
|
||||
{
|
||||
|
@ -1876,16 +1880,24 @@ static Dt_t *inittree(Shell_t *shp,const struct shtable2 *name_vals)
|
|||
/*
|
||||
* read in the process environment and set up name-value pairs
|
||||
* skip over items that are not name-value pairs
|
||||
*
|
||||
* Must be called with import_attributes == 0 first, then again with
|
||||
* import_attributes == 1 if variable attributes are to be imported
|
||||
* from the environment.
|
||||
*/
|
||||
|
||||
static void env_init(Shell_t *shp)
|
||||
static void env_init(Shell_t *shp, int import_attributes)
|
||||
{
|
||||
register char *cp;
|
||||
register Namval_t *np,*mp;
|
||||
register char **ep=environ;
|
||||
char *dp,*next=0;
|
||||
char *dp;
|
||||
int nenv=0,k=0,size=0;
|
||||
Namval_t *np0;
|
||||
static char *next=0; /* next variable whose attributes to import */
|
||||
|
||||
if(import_attributes)
|
||||
goto import_attributes;
|
||||
if(!ep)
|
||||
goto skip;
|
||||
while(*ep++)
|
||||
|
@ -1902,10 +1914,10 @@ static void env_init(Shell_t *shp)
|
|||
mp->nvenv = (char*)cp;
|
||||
dp[-1] = '=';
|
||||
}
|
||||
else if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]==0)
|
||||
else if(strcmp(cp,e_envmarker)==0)
|
||||
{
|
||||
dp[-1] = '=';
|
||||
next = cp+4;
|
||||
next = cp + strlen(e_envmarker);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
@ -1915,7 +1927,7 @@ static void env_init(Shell_t *shp)
|
|||
mp->nvname = cp;
|
||||
size += strlen(cp);
|
||||
}
|
||||
nv_onattr(mp,NV_IMPORT);
|
||||
nv_onattr(mp,NV_IMPORT);
|
||||
if(mp->nvfun || nv_isattr(mp,NV_INTEGER))
|
||||
nv_putval(mp,dp,0);
|
||||
else
|
||||
|
@ -1937,6 +1949,18 @@ static void env_init(Shell_t *shp)
|
|||
dp += size+1;
|
||||
dtinsert(shp->var_base,np++);
|
||||
}
|
||||
skip:
|
||||
if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED))
|
||||
{
|
||||
nv_offattr(PWDNOD,NV_TAGGED);
|
||||
path_pwd(shp,0);
|
||||
}
|
||||
if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED))
|
||||
sh_onoption(SH_RESTRICTED); /* restricted shell */
|
||||
return;
|
||||
|
||||
/* Import variable attributes from environment (from variable named by e_envmarker) */
|
||||
import_attributes:
|
||||
while(cp=next)
|
||||
{
|
||||
if(next = strchr(++cp,'='))
|
||||
|
@ -1978,14 +2002,6 @@ static void env_init(Shell_t *shp)
|
|||
else
|
||||
cp += 2;
|
||||
}
|
||||
skip:
|
||||
if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED))
|
||||
{
|
||||
nv_offattr(PWDNOD,NV_TAGGED);
|
||||
path_pwd(shp,0);
|
||||
}
|
||||
if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED))
|
||||
sh_onoption(SH_RESTRICTED); /* restricted shell */
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2179,8 +2179,10 @@ char **sh_envgen(void)
|
|||
memcpy((void*)er,environ,shp->nenv*sizeof(char*));
|
||||
nv_scan(shp->var_tree, pushnam,&data,NV_EXPORT, NV_EXPORT);
|
||||
*data.argnam = (char*)stakalloc(data.attsize);
|
||||
/* Export variable attributes into env var named by e_envmarker, unless POSIX mode is on */
|
||||
cp = data.attval = strcopy(*data.argnam,e_envmarker);
|
||||
nv_scan(shp->var_tree, attstore,&data,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
|
||||
if(!sh_isoption(SH_POSIX))
|
||||
nv_scan(shp->var_tree, attstore,&data,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
|
||||
*data.attval = 0;
|
||||
if(cp!=data.attval)
|
||||
data.argnam++;
|
||||
|
|
|
@ -86,6 +86,16 @@ fi
|
|||
if [[ $($SHELL -c 'xi=xi+4;echo $xi') != 24 ]]
|
||||
then err_exit export attributes fails
|
||||
fi
|
||||
if [[ -o ?posix && $(set -o posix; "$SHELL" -c 'xi=xi+4;echo $xi') != "xi+4" ]]
|
||||
then err_exit "attributes exported despite posix mode (-o posix)"
|
||||
fi
|
||||
if [[ -o ?posix && $("$SHELL" -o posix -c 'xi=xi+4;echo $xi') != "xi+4" ]]
|
||||
then err_exit "attributes imported despite posix mode (-o posix)"
|
||||
fi
|
||||
ln -s "$SHELL" "$tmp/sh"
|
||||
if [[ $("$tmp/sh" -c 'xi=xi+4;echo $xi') != "xi+4" ]]
|
||||
then err_exit "attributes imported despite posix mode (invoked as sh)"
|
||||
fi
|
||||
x=$(foo=abc $SHELL <<!
|
||||
foo=bar
|
||||
$SHELL -c 'print \$foo'
|
||||
|
|
Loading…
Reference in a new issue