1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

Fix unreliable behavior when special vars are readonly or unset (#27)

src/cmd/ksh93/data/variables.c:
 - Running 'unset .sh.lineno' creates a memory fault, so fix that
   by giving it the NV_NOFREE attribute. This crash was happening
   because ${.sh.lineno} is an integer that cannot be freed from
   memory with free(3).

src/cmd/ksh93/sh/init.c:
 - Tell _nv_unset to ignore NV_RDONLY when $RANDOM and $LINENO are
   restored from the subshell scope. This is required to fully
   restore the original state of these variables after a virtual
   subshell finishes.

src/cmd/ksh93/bltins/typeset.c,
src/cmd/ksh93/sh/subshell.c:
 - Disabled some optimizations for two instances of 'sh_assignok' to
   fix 'readonly' in virtual subshells and '(unset .sh.level)' in
   nested functions. This fixes the following variables when
   '(readonly $varname); enum varname=' is run:

   $_
   ${.sh.name}
   ${.sh.subscript}
   ${.sh.level}

   The optimization in question prevents sh_assignok from saving the
   original state of these variables by making the sh_assignok call
   a no-op. Ksh needs the original state of a variable for it to be
   properly restored after a virtual subshell has run, otherwise ksh
   will simply carry over any new flags (being NV_RDONLY in this case)
   from the subshell into the main shell.

src/cmd/ksh93/tests/variables.sh:
 - Add regression tests from Martijn Dekker for setting special
   variables as readonly in virtual subshells and for unsetting
   special variables in general.

Fixes #4
This commit is contained in:
Johnothan King 2020-06-20 10:08:41 -07:00 committed by GitHub
parent ee698e89d5
commit bd3e2a8001
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 174 additions and 9 deletions

View file

@ -795,5 +795,148 @@ expect=1
actual=$(env SHLVL="2#11+x[\$(env echo Exploited vuln CVE-2019-14868 >&2)0]" "$SHELL" -c 'echo $SHLVL' 2>&1)
[[ $actual == $expect ]] || err_exit "expression allowed on env var import (expected '$expect', got '$actual')"
# ======
# Check unset and cleanup/restore behavior of special variables.
# Keep the list in sync (minus ".sh") with shtab_variables[] in src/cmd/ksh93/data/variables.c
# Note: as long as changing $PATH forks a virtual subshell, "PATH" should also be excluded below.
set -- \
"PS1" \
"PS2" \
"IFS" \
"PWD" \
"HOME" \
"MAIL" \
"REPLY" \
"SHELL" \
"EDITOR" \
"MAILCHECK" \
"RANDOM" \
"ENV" \
"HISTFILE" \
"HISTSIZE" \
"HISTEDIT" \
"HISTCMD" \
"FCEDIT" \
"CDPATH" \
"MAILPATH" \
"PS3" \
"OLDPWD" \
"VISUAL" \
"COLUMNS" \
"LINES" \
"PPID" \
"_" \
"TMOUT" \
"SECONDS" \
"LINENO" \
"OPTARG" \
"OPTIND" \
"PS4" \
"FPATH" \
"LANG" \
"LC_ALL" \
"LC_COLLATE" \
"LC_CTYPE" \
"LC_MESSAGES" \
"LC_NUMERIC" \
"FIGNORE" \
"KSH_VERSION" \
"JOBMAX" \
".sh.edchar" \
".sh.edcol" \
".sh.edtext" \
".sh.edmode" \
".sh.name" \
".sh.subscript" \
".sh.value" \
".sh.version" \
".sh.dollar" \
".sh.match" \
".sh.command" \
".sh.file" \
".sh.fun" \
".sh.lineno" \
".sh.subshell" \
".sh.level" \
".sh.stats" \
".sh.math" \
".sh.pool" \
"SHLVL" \
"CSWIDTH"
# ... unset
$SHELL -c '
errors=0
unset -v "$@" || let errors++
for var
do if [[ $var != "_" ]] && # only makes sense that $_ is immediately set again
{ [[ -v $var ]] || eval "[[ -n \${$var+s} ]]"; }
then echo " $0: special variable $var still set" >&2
let errors++
elif eval "[[ -n \${$var} ]]"
then echo " $0: special variable $var has value, though unset" >&2
let errors++
fi
done
exit $((errors + 1)) # a possible erroneous asynchronous fork would cause exit status 0
' unset_test "$@"
e=$?
((e == 1)) || err_exit "Failure in unsetting one or more special variables (exit status $e)"
# ... unset in virtual subshell inside of nested function
$SHELL -c '
errors=0
fun1()
{
fun2()
{
(
unset -v "$@" || let errors++
for var
do if [[ $var != "_" ]] && # only makes sense that $_ is immediately set again
{ [[ -v $var ]] || eval "[[ -n \${$var+s} ]]"; }
then echo " $0: special variable $var still set" >&2
let errors++
elif eval "[[ -n \${$var} ]]"
then echo " $0: special variable $var has value, though unset" >&2
let errors++
fi
done
exit $errors
) || errors=$?
}
fun2 "$@"
}
fun1 "$@"
exit $((errors + 1)) # a possible erroneous asynchronous fork would cause exit status 0
' unset_subsh_fun_test "$@"
e=$?
((e == 1)) || err_exit "Unset of special variable(s) in a virtual subshell within a nested function fails (exit status $e)"
# ... readonly in subshell
$SHELL -c '
errors=0
(
readonly "$@"
for var
do if (eval "$var=") 2>/dev/null
then echo " $0: special variable $var not made readonly in subshell" >&2
let errors++
fi
done
exit $errors
) || errors=$?
for var
do if ! (eval "$var=")
then echo " $0: special variable $var still readonly outside subshell" >&2
let errors++
fi
done
exit $((errors + 1)) # a possible erroneous asynchronous fork would cause exit status 0
' readonly_test "$@"
e=$?
((e == 1)) || err_exit "Failure in making one or more special variables readonly in a subshell (exit status $e)"
# ======
exit $((Errors<125?Errors:125))