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

Fix typeset -l/-u crash on special vars (rhbz#1083713)

When using typeset -l or -u on a variable that cannot be changed
when the shell is in restricted mode, ksh crashed.

This fixed is inspired by this Red Hat fix, which is incomplete:
642af4d6/f/ksh-20120801-tpstl.patch

The crash was caused by the nv_shell() function. It walks though a
discipline function tree to get the pointer to the interpreter
associated with it. Evidently, the problem is that some pointer in
that walk is not set correctly for all special variables.

Thing is, ksh only has one shell language interpreter, and only one
global data structure (called 'sh') to keep its main state[*]. Yet,
the code is full of 'shp' pointers to that structure. Most (not
all) functions pass that pointer around to each other, accessing
that struct indirectly, ostensibly to account for the non-existent
possibility that there might be more than one interpreter state.
The "why" of that is an interesting cause for speculation that I
may get to sometime. For now, it is enough to know that, in the
code as it is, it matters not one iota what pointer to the shell
interpreter state is used; they all point to the same thing (unless
it's broken, as in this bug).

So, rather than fixing nv_shell() and/or associated pointer
assignments, this commit simply removes it, and replaces it with
calls to sh_getinterp(), which always returns a pointer to sh (see
init.c, where that function is defined as literally 'return &sh').

[*] Defined in shell.h, with the _SH_PRIVATE part in defs.h

src/cmd/ksh93/include/defs.h,
src/cmd/ksh93/sh/name.c:
- Remove nv_shell().

src/cmd/ksh93/sh/init.c:
- In all the discipline functions for special variables, initialise
  shp using sh_getinterp() instead of nv_shell().

src/cmd/ksh93/tests/variables.sh:
- Add regression test for typeset -l/-u on all special variables.
This commit is contained in:
Martijn Dekker 2020-09-23 19:15:45 +02:00
parent 843b546c1a
commit 3654ee73c0
5 changed files with 62 additions and 35 deletions

View file

@ -868,7 +868,7 @@ actual=$(env SHLVL="2#11+x[\$(env echo Exploited vuln CVE-2019-14868 >&2)0]" "$S
[[ $actual == $expect ]] || err_exit "expression allowed on env var import (expected '$expect', got '$actual')"
# ======
# Check unset and cleanup/restore behavior of special variables.
# Check unset, attribute 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.
@ -954,8 +954,8 @@ $SHELL -c '
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)"
(((e = $?) == 1)) || err_exit "Failure in unsetting one or more special variables" \
"(exit status $e$( ((e>128)) && print -n / && kill -l "$e"))"
# ... unset in virtual subshell inside of nested function
$SHELL -c '
@ -984,8 +984,8 @@ $SHELL -c '
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)"
(((e = $?) == 1)) || err_exit "Unset of special variable(s) in a virtual subshell within a nested function fails" \
"(exit status $e$( ((e>128)) && print -n / && kill -l "$e"))"
# ... readonly in subshell
$SHELL -c '
@ -1008,8 +1008,8 @@ $SHELL -c '
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)"
(((e = $?) == 1)) || err_exit "Failure in making one or more special variables readonly in a subshell" \
"(exit status $e$( ((e>128)) && print -n / && kill -l "$e"))"
# ... subshell leak test
$SHELL -c '
@ -1025,8 +1025,44 @@ $SHELL -c '
done
exit $((errors + 1))
' subshell_leak_test "$@"
e=$?
((e == 1)) || err_exit "One or more special variables leak out of a subshell (exit status $e)"
(((e = $?) == 1)) || err_exit "One or more special variables leak out of a subshell" \
"(exit status $e$( ((e>128)) && print -n / && kill -l "$e"))"
# ... upper/lowercase test
$SHELL -c '
typeset -u upper
typeset -l lower
errors=0
PS1=/dev/null/test_my_case_too
PS2=$PS1 PS3=$PS1 PS4=$PS1 OPTARG=$PS1 IFS=$PS1 FPATH=$PS1 FIGNORE=$PS1 CSWIDTH=$PS1
for var
do case $var in
RANDOM | HISTCMD | _ | SECONDS | LINENO | JOBMAX | .sh.stats)
# these are expected to fail below as their values change; just test against crashing
typeset -u "$var"
typeset -l "$var"
continue ;;
esac
nameref val=$var
upper=$val
lower=$val
typeset -u "$var"
if [[ $val != "$upper" ]]
then echo " $0: typeset -u does not work on special variable $var" \
"(expected $(printf %q "$upper"), got $(printf %q "$val"))" >&2
let errors++
fi
typeset -l "$var"
if [[ $val != "$lower" ]]
then echo " $0: typeset -l does not work on special variable $var" \
"(expected $(printf %q "$lower"), got $(printf %q "$val"))" >&2
let errors++
fi
done
exit $((errors + 1))
' changecase_test "$@" PATH # do include PATH here as well
(((e = $?) == 1)) || err_exit "typeset -l/-u doesn't work on special variables" \
"(exit status $e$( ((e>128)) && print -n / && kill -l "$e"))"
# ======
# ${.sh.pid} should be the forked subshell's PID