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

Don't allow 'enum' and 'typeset -T' to override special built-ins

Special builtins are undeleteable for a reason. But 'enum' and
'typeset -T' allow overriding them, causing an inconsistent state.

@JohnoKing writes:
| The behavior is rather buggy, as it appears to successfully
| override normal builtins but fails to delete the special
| builtins, leading to scenarios where both the original builtin
| and type are run:
|
| $ typeset -T eval=(typeset BAD; typeset TYPE)  # This should have failed
| $ eval foo=BAD
| /usr/bin/ksh: eval: line 1: foo: not found
| $ enum trap=(BAD TYPE)   # This also should have failed
| $ trap foo=BAD
| /usr/bin/ksh: trap: condition(s) required
| $ enum umask=(BAD TYPE)
| $ umask foo=BAD
| $ echo $foo
| BAD
|
| # Examples of general bugginess
| $ trap bar=TYPE
| /usr/bin/ksh: trap: condition(s) required
| $ echo $bar
| TYPE
| $ eval var=TYPE
| /usr/bin/ksh: eval: line 1: var: not found
| $ echo $var
| TYPE

This commit fixes the following:

The 'enum' and 'typeset -T' commands are no longer allowed to
override and replace special built-in commands, except for type
definition commands previously created by these commands; these
are already (dis)allowed elsewhere.

A command like 'typeset -T foo_t' without any assignments no longer
creates an incompletely defined 'foo_t' built-in comamnd. Instead,
it is now silently ignored for backwards compatibility. This did
have a regression test checking for it, but I'm changing it because
that's just not a valid use case. An incomplete type definition
command does nothing useful and only crashes the shell when run.

src/cmd/ksh93/bltins/enum.c: b_enum():
- Do not allow overriding non-type special built-ins.

src/cmd/ksh93/sh/name.c: nv_setlist():
- Do not allow 'typeset -T' to override non-type special built-ins.
  To avoid an inconsistent state, this must be checked for while
  processing the assignments list before typeset is really invoked.

src/cmd/ksh93/bltins_typeset.c: b_typeset():
- Only create a type command if sh.envlist is set, i.e., if some
  shell assignment(s) were passed to the 'typeset -T' command.

Progresses: https://github.com/ksh93/ksh/issues/350
This commit is contained in:
Martijn Dekker 2022-02-08 18:33:44 +00:00
parent a36b96f9a4
commit e6d0187dd8
8 changed files with 50 additions and 4 deletions

11
NEWS
View file

@ -3,6 +3,17 @@ For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0
Any uppercase BUG_* names are modernish shell bug IDs. Any uppercase BUG_* names are modernish shell bug IDs.
2022-02-08:
- To avoid an inconsistent state, the 'enum' and 'typeset -T' commands are
no longer allowed to replace special built-in commands. For instance,
'enum trap=(a b c)' is now an error because 'trap' is a special built-in.
The ability of 'typeset -T' to redefine a type is not affected.
- A command like 'typeset -T foo_t' without any assignment no longer creates
an incompletely defined 'foo_t' built-in comamnd that will crash the shell
when used. Instead, it is now silently ignored for backwards compatibility.
2022-02-05: 2022-02-05:
- Fixed: for indexed arrays, given an unset array member a[i] with i > 0, - Fixed: for indexed arrays, given an unset array member a[i] with i > 0,

View file

@ -168,6 +168,10 @@ For more details, see the NEWS file and for complete details, see the git log.
return value that fits in a signed integer, typically a 32-bit value. return value that fits in a signed integer, typically a 32-bit value.
Note that $? is truncated to 8 bits when the current (sub)shell exits. Note that $? is truncated to 8 bits when the current (sub)shell exits.
31. The 'enum' and 'typeset -T' commands are no longer allowed to
override and replace special built-in commands, except for type
definition commands previously created by these commands.
____________________________________________________________________________ ____________________________________________________________________________
KSH-93 VS. KSH-88 KSH-93 VS. KSH-88

View file

@ -88,6 +88,8 @@ static const char enum_type[] =
"[+SEE ALSO?\benum\b(1), \btypeset\b(1)]" "[+SEE ALSO?\benum\b(1), \btypeset\b(1)]"
; ;
extern const char is_spcbuiltin[];
struct Enum struct Enum
{ {
Namfun_t hdr; Namfun_t hdr;
@ -243,6 +245,13 @@ int b_enum(int argc, char** argv, Shbltin_t *context)
#endif #endif
while(cp = *argv++) while(cp = *argv++)
{ {
/* Do not allow 'enum' to override special built-ins -- however, exclude
* previously created type commands from this search as that is handled elsewhere. */
if((tp=nv_search(cp,sh.bltin_tree,0)) && nv_isattr(tp,BLT_SPC) && !nv_search(cp,sh.typedict,0))
{
errormsg(SH_DICT,ERROR_exit(1),"%s:%s",cp,is_spcbuiltin);
UNREACHABLE();
}
if(!(np = nv_open(cp, (void*)0, NV_VARNAME|NV_NOADD)) || !(ap=nv_arrayptr(np)) || ap->fun || (sz=ap->nelem&(((1L<<ARRAY_BITS)-1))) < 2) if(!(np = nv_open(cp, (void*)0, NV_VARNAME|NV_NOADD)) || !(ap=nv_arrayptr(np)) || ap->fun || (sz=ap->nelem&(((1L<<ARRAY_BITS)-1))) < 2)
{ {
error(ERROR_exit(1), "%s must name an array containing at least two elements",cp); error(ERROR_exit(1), "%s must name an array containing at least two elements",cp);

View file

@ -536,7 +536,7 @@ endargs:
errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix); errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix);
UNREACHABLE(); UNREACHABLE();
} }
else if(nv_isnull(tdata.tp)) else if(nv_isnull(tdata.tp) && sh.envlist) /* only create a type command if there were assignment(s) */
nv_newtype(tdata.tp); nv_newtype(tdata.tp);
tdata.tp->nvenv = tdata.help; tdata.tp->nvenv = tdata.help;
flag &= ~NV_TYPE; flag &= ~NV_TYPE;

View file

@ -21,7 +21,7 @@
#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
#define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */ #define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */
#define SH_RELEASE_DATE "2022-02-05" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_DATE "2022-02-08" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_CPYR "(c) 2020-2022 Contributors to ksh " SH_RELEASE_FORK #define SH_RELEASE_CPYR "(c) 2020-2022 Contributors to ksh " SH_RELEASE_FORK
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */ /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */

View file

@ -319,6 +319,13 @@ void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ)
cp = sh_mactrim(fp->fornam,-1); cp = sh_mactrim(fp->fornam,-1);
else else
cp = fp->fornam; cp = fp->fornam;
/* Do not allow 'typeset -T' to override special built-ins -- however, exclude
* previously created type commands from this search as that is handled elsewhere. */
if(maketype && (np=nv_search(cp,sh.bltin_tree,0)) && nv_isattr(np,BLT_SPC) && !nv_search(cp,sh.typedict,0))
{
errormsg(SH_DICT,ERROR_exit(1),"%s:%s",cp,is_spcbuiltin);
UNREACHABLE();
}
error_info.line = fp->fortyp-sh.st.firstline; error_info.line = fp->fortyp-sh.st.firstline;
if(!array && tp->tre.tretyp!=TLST && tp->com.comset && !tp->com.comarg && tp->com.comset->argval[0]==0 && tp->com.comset->argval[1]=='[') if(!array && tp->tre.tretyp!=TLST && tp->com.comset && !tp->com.comarg && tp->com.comset->argval[0]==0 && tp->com.comset->argval[1]=='[')
array |= (tp->com.comset->argflag&ARG_MESSAGE)?NV_IARRAY:NV_ARRAY; array |= (tp->com.comset->argflag&ARG_MESSAGE)?NV_IARRAY:NV_ARRAY;

View file

@ -161,5 +161,12 @@ then enum PARSER2_t=(a b)
fi fi
PATH=/dev/null command -v PARSER2_t >/dev/null && err_exit "PARSER2_t incompletely defined though definition was never executed" PATH=/dev/null command -v PARSER2_t >/dev/null && err_exit "PARSER2_t incompletely defined though definition was never executed"
# ======
# https://github.com/ksh93/ksh/issues/350#issuecomment-982168684
got=$("$SHELL" -c 'enum trap=(BAD TYPE)' 2>&1)
exp=': trap: is a special shell builtin'
[[ $got == *"$exp" ]] || err_exit "enum overrides special builtin" \
"(expected match of *$(printf %q "$exp"); got $(printf %q "$got"))"
# ====== # ======
exit $((Errors<125?Errors:125)) exit $((Errors<125?Errors:125))

View file

@ -565,8 +565,9 @@ unset z
u_t -a x | read z u_t -a x | read z
[[ $z == unset ]] && err_exit 'unset discipline called on type creation' [[ $z == unset ]] && err_exit 'unset discipline called on type creation'
{ z=$($SHELL 2> /dev/null 'typeset -T foo; typeset -T') ;} 2> /dev/null got=$("$SHELL" -c 'typeset -T foo; typeset -T' 2>&1)
[[ $z == 'typeset -T foo' ]] || err_exit '"typeset -T foo; typeset -T" failed' [[ -z $got ]] || err_exit '"typeset -T foo; typeset -T" exposed incomplete type builtin' \
"(got $(printf %q "$got"))"
{ z=$($SHELL 2> /dev/null 'typeset -T foo=bar; typeset -T') ;} 2> /dev/null { z=$($SHELL 2> /dev/null 'typeset -T foo=bar; typeset -T') ;} 2> /dev/null
[[ $z ]] && err_exit '"typeset -T foo=bar" should not creates type foo' [[ $z ]] && err_exit '"typeset -T foo=bar" should not creates type foo'
@ -657,5 +658,12 @@ exp='Subsh_t -a v=((typeset -i x=1) (typeset -i x=2) (typeset -i x=3))'
"(expected $(printf %q "$exp"), got $(printf %q "$got"))" "(expected $(printf %q "$exp"), got $(printf %q "$got"))"
PATH=/dev/null command -v Subsh_t >/dev/null && err_exit "Subsh_t leaked out of subshell" PATH=/dev/null command -v Subsh_t >/dev/null && err_exit "Subsh_t leaked out of subshell"
# ======
# https://github.com/ksh93/ksh/issues/350#issuecomment-982168684
got=$("$SHELL" -c 'typeset -T trap=( typeset -i i )' 2>&1)
exp=': trap: is a special shell builtin'
[[ $got == *"$exp" ]] || err_exit "typeset -T overrides special builtin" \
"(expected match of *$(printf %q "$exp"); got $(printf %q "$got"))"
# ====== # ======
exit $((Errors<125?Errors:125)) exit $((Errors<125?Errors:125))