Skip to content

Commit 960a1a9

Browse files
committed
Avoid importing env vars with invalid names (rhbz#1147645)
This imports a new version of the code to import environment variable values that was sent to Red Hat from upstream in 2014. It avoids importing environment variables whose names are not valid in the shell language, as it would be impossible to change or unset them. However, they stay in the environment to be passed to child processes. Prior discussion: https://bugzilla.redhat.com/1147645 Original patch: https://src.fedoraproject.org/rpms/ksh/blob/642af4d6/f/ksh-20120801-oldenvinit.patch src/cmd/ksh93/sh/init.c: - env_init(): Import new, simplified code to import environment variable name/value pairs. Instead of doing the heavy lifting itself, this version uses nv_open(), passing the NV_IDENT flag to reject and skip invalid names. - Get rid of gotos and a static var by splitting off the code to import attributes into a new env_import_attributes() function. This is a better way to avoid importing attributes when initialising the shell in POSIX mode (re: 00d4396 - Remove an nv_mapchar() call that was based on some unclear flaggery which was also removed by upstream as sent to Red Hat. I don't know what that did, if anything; looks like it might have had something to do with typeset -u/-l, but those particular attributes have never been successfully inherited through the environment. (Maybe that's another bug, or maybe I just don't care as inheriting attributes is a misfeature anyway; we have to put up with it because legacy scripts might use it. Maybe someone can prove it's an unacceptable security risk to import attributes like readonly from an environment variable that is inherently vulnerable to manipulation. That would be nice, as a CVE ID would give us a solid reason to get rid of this nonsense.) - Remove an 'else cp += 2;' that was very clearly a no-op; 'cp' is immediately overwritten on the next loop iteration and not used past the loop. src/cmd/ksh93/tests/variables.sh: - Test.
1 parent 8a34fc4 commit 960a1a9

3 files changed

Lines changed: 48 additions & 72 deletions

File tree

‎NEWS‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ Any uppercase BUG_* names are modernish shell bug IDs.
77

88
- 'whence -f' now completely ignores the existence of functions, as documented.
99

10+
- ksh now does not import environment variables whose names are not valid in
11+
the shell language, as it would be impossible to change or unset them.
12+
However, they stay in the environment to be passed to child processes.
13+
1014
2020-09-25:
1115

1216
- whence -v/-a now reports the path to the file that an "undefined" (i.e.

‎src/cmd/ksh93/sh/init.c‎

Lines changed: 37 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ typedef struct _init_
199199
static Init_t *ip;
200200
static int lctype;
201201
static int nbltins;
202-
static void env_init(Shell_t*,int);
202+
static char *env_init(Shell_t*);
203+
static void env_import_attributes(Shell_t*,char*);
203204
static Init_t *nv_init(Shell_t*);
204205
static int shlvl;
205206

@@ -1179,6 +1180,7 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
11791180
Shell_t *shp;
11801181
register int n;
11811182
int type;
1183+
char *save_envmarker;
11821184
static char *login_files[3];
11831185
memfatal();
11841186
n = strlen(e_version);
@@ -1293,8 +1295,8 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
12931295
if(type&SH_TYPE_POSIX)
12941296
sh_onoption(SH_POSIX);
12951297
}
1296-
/* read the environment; don't import attributes yet */
1297-
env_init(shp,0);
1298+
/* read the environment; don't import attributes yet, but save pointer to them */
1299+
save_envmarker = env_init(shp);
12981300
if(!ENVNOD->nvalue.cp)
12991301
{
13001302
sfprintf(shp->strbuf,"%s/.kshrc",nv_getval(HOME));
@@ -1397,7 +1399,7 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
13971399
}
13981400
/* import variable attributes from environment */
13991401
if(!sh_isoption(SH_POSIX))
1400-
env_init(shp,1);
1402+
env_import_attributes(shp,save_envmarker);
14011403
#if SHOPT_PFSH
14021404
if (sh_isoption(SH_PFSH))
14031405
{
@@ -1883,86 +1885,53 @@ Dt_t *sh_inittree(Shell_t *shp,const struct shtable2 *name_vals)
18831885
* read in the process environment and set up name-value pairs
18841886
* skip over items that are not name-value pairs
18851887
*
1886-
* Must be called with import_attributes == 0 first, then again with
1887-
* import_attributes == 1 if variable attributes are to be imported
1888-
* from the environment.
1888+
* Returns pointer to A__z env var from which to import attributes, or 0.
18891889
*/
18901890

1891-
static void env_init(Shell_t *shp, int import_attributes)
1891+
static char *env_init(Shell_t *shp)
18921892
{
18931893
register char *cp;
1894-
register Namval_t *np,*mp;
1894+
register Namval_t *np;
18951895
register char **ep=environ;
1896-
char *dp;
1897-
int nenv=0,k=0,size=0;
1898-
Namval_t *np0;
1899-
static char *next=0; /* next variable whose attributes to import */
1900-
1901-
if(import_attributes)
1902-
goto import_attributes;
1903-
if(!ep)
1904-
goto skip;
1905-
while(*ep++)
1906-
nenv++;
1907-
np = newof(0,Namval_t,nenv,0);
1908-
for(np0=np,ep=environ;cp= *ep; ep++)
1896+
char *next = 0; /* pointer to A__z env var */
1897+
if(ep)
19091898
{
1910-
dp = strchr(cp,'=');
1911-
if(!dp)
1912-
continue;
1913-
*dp++ = 0;
1914-
if(mp = dtmatch(shp->var_base,cp))
1915-
{
1916-
mp->nvenv = (char*)cp;
1917-
dp[-1] = '=';
1918-
}
1919-
else if(strcmp(cp,e_envmarker)==0)
1920-
{
1921-
dp[-1] = '=';
1922-
next = cp + strlen(e_envmarker);
1923-
continue;
1924-
}
1925-
else
1926-
{
1927-
k++;
1928-
mp = np++;
1929-
mp->nvname = cp;
1930-
size += strlen(cp);
1931-
}
1932-
nv_onattr(mp,NV_IMPORT);
1933-
if(mp->nvfun || nv_isattr(mp,NV_INTEGER))
1934-
nv_putval(mp,dp,0);
1935-
else
1899+
while(cp = *ep++)
19361900
{
1937-
mp->nvalue.cp = dp;
1938-
nv_onattr(mp,NV_NOFREE);
1901+
/* The magic A__z env var is an invention of ksh88. See e_envmarker[]. */
1902+
if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]=='=')
1903+
next = cp + 4;
1904+
else if(np = nv_open(cp,shp->var_tree,(NV_EXPORT|NV_IDENT|NV_ASSIGN|NV_NOFAIL)))
1905+
{
1906+
nv_onattr(np,NV_IMPORT);
1907+
np->nvenv = cp;
1908+
nv_close(np);
1909+
}
1910+
else /* swap with front */
1911+
{
1912+
ep[-1] = environ[shp->nenv];
1913+
environ[shp->nenv++] = cp;
1914+
}
19391915
}
1940-
nv_onattr(mp,NV_EXPORT|NV_IMPORT);
1941-
}
1942-
np = (Namval_t*)realloc((void*)np0,k*sizeof(Namval_t));
1943-
dp = (char*)malloc(size+k);
1944-
while(k-->0)
1945-
{
1946-
size = strlen(np->nvname);
1947-
memcpy(dp,np->nvname,size+1);
1948-
np->nvname[size] = '=';
1949-
np->nvenv = np->nvname;
1950-
np->nvname = dp;
1951-
dp += size+1;
1952-
dtinsert(shp->var_base,np++);
19531916
}
1954-
skip:
19551917
if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED))
19561918
{
19571919
nv_offattr(PWDNOD,NV_TAGGED);
19581920
path_pwd(shp,0);
19591921
}
19601922
if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED))
19611923
sh_onoption(SH_RESTRICTED); /* restricted shell */
1962-
return;
1924+
return(next);
1925+
}
19631926

1964-
/* Import variable attributes from environment (from variable named by e_envmarker) */
1965-
import_attributes:
1927+
/*
1928+
* Import variable attributes from magic A__z env var pointed to by 'next'.
1929+
* If next == 0, this function does nothing.
1930+
*/
1931+
static void env_import_attributes(Shell_t *shp, char *next)
1932+
{
1933+
register char *cp;
1934+
register Namval_t *np;
19661935
while(cp=next)
19671936
{
19681937
if(next = strchr(++cp,'='))
@@ -1975,7 +1944,7 @@ static void env_init(Shell_t *shp, int import_attributes)
19751944
if((flag&NV_INTEGER) && size==0)
19761945
{
19771946
/* check for floating*/
1978-
char *val = nv_getval(np);
1947+
char *dp, *val = nv_getval(np);
19791948
strtol(val,&dp,10);
19801949
if(*dp=='.' || *dp=='e' || *dp=='E')
19811950
{
@@ -1998,11 +1967,7 @@ static void env_init(Shell_t *shp, int import_attributes)
19981967
}
19991968
}
20001969
nv_newattr(np,flag|NV_IMPORT|NV_EXPORT,size);
2001-
if((flag&(NV_INTEGER|NV_UTOL|NV_LTOU))==(NV_UTOL|NV_LTOU))
2002-
nv_mapchar(np,(flag&NV_UTOL)?e_tolower:e_toupper);
20031970
}
2004-
else
2005-
cp += 2;
20061971
}
20071972
return;
20081973
}

‎src/cmd/ksh93/tests/variables.sh‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,5 +1123,12 @@ do for word in '(word)' 'w(or)d' '(wor)d' 'w(ord)' 'w(ord' 'wor)d'
11231123
done
11241124
done
11251125

1126+
# ======
1127+
# https://bugzilla.redhat.com/1147645
1128+
case $'\n'$(env 'BASH_FUNC_a%%=() { echo test; }' "$SHELL" -c set) in
1129+
*$'\nBASH_FUNC_a%%='* )
1130+
err_exit 'ksh imports environment variables with invalid names' ;;
1131+
esac
1132+
11261133
# ======
11271134
exit $((Errors<125?Errors:125))

0 commit comments

Comments
 (0)