1
0
Fork 0
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:
Martijn Dekker 2020-09-05 10:33:50 +02:00
parent 20fcf22973
commit 00d439605f
5 changed files with 51 additions and 19 deletions

2
NEWS
View file

@ -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:

View file

@ -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),

View file

@ -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;
}

View file

@ -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++;

View file

@ -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'