54181, 54331: remove support for restricted shell

This is in response to a security report. There are too many potential ways
to break out of a restricted shell and more secure, modern alternatives exist.
This commit is contained in:
Oliver Kiddle
2026-04-14 03:14:23 +02:00
parent 51c1ad361c
commit e73499b372
22 changed files with 79 additions and 321 deletions

View File

@@ -1,3 +1,14 @@
2026-04-14 Oliver Kiddle <opk@zsh.org>
* 54181, 54331: Completion/Zsh/Command/_set,
Doc/Makefile.in, Doc/Zsh/builtins.yo, Doc/Zsh/compat.yo,
Doc/Zsh/grammar.yo, Doc/Zsh/invoke.yo, Doc/Zsh/manual.yo,
Doc/Zsh/options.yo, Doc/Zsh/restricted.yo, README,
Src/Modules/db_gdbm.c, Src/Modules/parameter.c, Src/builtin.c,
Src/exec.c, Src/init.c, Src/jobs.c, Src/options.c, Src/params.c,
Src/signals.c, Test/E01options.ztst, configure.ac:
remove support for restricted shell
2026-04-13 dana <dana@dana.is>
* dana + Jun T: 54329 + 54339: Doc/Makefile.in, Doc/intro.ms:

View File

@@ -21,5 +21,5 @@ noglob _arguments -s -S \
{-,+}d[no-globalrcs] {-,+}e[errexit] {-,+}f[no-rcs] {-,+}g[histignorespace] \
{-,+}h[histignoredups] {-,+}i[interactive] {-,+}k[interactivecomments] \
{-,+}l[login] {-,+}m[monitor] {-,+}n[no-exec] {-,+}p[privileged] \
{-,+}r[restricted] {-,+}t[singlecommand] {-,+}u[no-unset] {-,+}v[verbose] \
{-,+}t[singlecommand] {-,+}u[no-unset] {-,+}v[verbose] \
{-,+}w[chaselinks] {-,+}x[xtrace] {-,+}y[shwordsplit]

View File

@@ -84,7 +84,7 @@ Zsh/filelist.yo Zsh/files.yo \
Zsh/func.yo Zsh/grammar.yo Zsh/manual.yo \
Zsh/index.yo Zsh/intro.yo Zsh/invoke.yo Zsh/jobs.yo Zsh/metafaq.yo \
Zsh/modules.yo Zsh/modlist.yo Zsh/modmenu.yo Zsh/manmodmenu.yo $(MODDOCSRC) \
Zsh/options.yo Zsh/params.yo Zsh/prompt.yo Zsh/redirect.yo Zsh/restricted.yo \
Zsh/options.yo Zsh/params.yo Zsh/prompt.yo Zsh/redirect.yo \
Zsh/seealso.yo Zsh/tcpsys.yo Zsh/zftpsys.yo Zsh/zle.yo
# ========== DEPENDENCIES FOR BUILDING ==========
@@ -219,7 +219,7 @@ $(MAN): zmacros.yo zman.yo
zsh.1 zshall.1: Zsh/intro.yo Zsh/metafaq.yo Zsh/invoke.yo Zsh/files.yo \
Zsh/filelist.yo Zsh/filelist.yo Zsh/seealso.yo \
Zsh/compat.yo Zsh/restricted.yo
Zsh/compat.yo
zshbuiltins.1: Zsh/builtins.yo

View File

@@ -570,8 +570,7 @@ change.
The var(flags) may be any of the invocation-time flags described in
sectref(Invocation)(zsh),
except that `tt(-o EMACS)' and `tt(-o VI)' may not be used. Flags such
as `tt(+r)'/`tt(+o RESTRICTED)' may be prohibited in some circumstances.
except that `tt(-o EMACS)' and `tt(-o VI)' may not be used.
If tt(-c) var(arg) appears in var(flags), var(arg) is evaluated while the
requested emulation is temporarily in effect. In this case the emulation

View File

@@ -1,12 +1,11 @@
texinode(Compatibility)(Restricted Shell)()(Invocation)
texinode(Compatibility)()()(Invocation)
sect(Compatibility)
cindex(compatibility)
cindex(sh compatibility)
cindex(ksh compatibility)
Zsh tries to emulate bf(sh) or bf(ksh) when it is invoked as
tt(sh) or tt(ksh) respectively; more precisely, it looks at the first
letter of the name by which it was invoked, excluding any initial `tt(r)'
(assumed to stand for `restricted'), and if that is `tt(b)', `tt(s)' or `tt(k)' it
letter of the name by which it was invoked, and if that is `tt(b)', `tt(s)' or `tt(k)' it
will emulate bf(sh) or bf(ksh). Furthermore, if invoked as tt(su) (which
happens on certain systems when the shell is executed by the tt(su)
command), the shell will try to find an alternative name from the tt(SHELL)

View File

@@ -531,7 +531,6 @@ itemiz(Execution of incorrectly positioned loop control structures
(tt(continue), tt(break)))
itemiz(Attempts to use regular expression with no regular expression
module available)
itemiz(Disallowed operations when the tt(RESTRICTED) options is set)
itemiz(Failure to create a pipe needed for a pipeline)
itemiz(Failure to create a multio)
itemiz(Failure to autoload a module needed for a declared shell feature)

View File

@@ -105,8 +105,6 @@ can be stacked after the `tt(-b)' and will take effect as normal.
startmenu()
menu(Compatibility)
menu(Restricted Shell)
endmenu()
includefile(Zsh/compat.yo)
includefile(Zsh/restricted.yo)

View File

@@ -64,7 +64,6 @@ menu(See Also)
Invocation
menu(Compatibility)
menu(Restricted Shell)
Shell Grammar

View File

@@ -1837,8 +1837,8 @@ pindex(NOLOCALOPTIONS)
item(tt(LOCAL_OPTIONS) <K>)(
If this option is set at the point of return from a shell function,
most options (including this one) which were in force upon entry to
the function are restored; options that are not restored are
tt(PRIVILEGED) and tt(RESTRICTED). Otherwise, only this option,
the function are restored; the tt(PRIVILEGED) option is not restored.
Otherwise, only this option,
and the tt(LOCAL_LOOPS), tt(XTRACE) and tt(PRINT_EXIT_VALUE) options are
restored. Hence if this is explicitly unset by a shell function the
other options in force at the point of return will remain so.
@@ -2466,16 +2466,6 @@ tt(-m) option of tt(setopt) and tt(unsetopt), and changing it inside a
function always changes it globally regardless of the tt(LOCAL_OPTIONS)
option.
)
pindex(RESTRICTED)
pindex(NO_RESTRICTED)
pindex(NORESTRICTED)
cindex(restricted shell)
item(tt(RESTRICTED) (tt(-r)))(
Enables restricted mode. This option cannot be changed using
tt(unsetopt), and setting it inside a function always changes it
globally regardless of the tt(LOCAL_OPTIONS) option. See
sectref(Restricted Shell)(zsh).
)
pindex(SHIN_STDIN)
pindex(NO_SHIN_STDIN)
pindex(SHINSTDIN)

View File

@@ -1,84 +0,0 @@
texinode(Restricted Shell)()(Compatibility)(Invocation)
sect(Restricted Shell)
cindex(restricted shell)
pindex(RESTRICTED)
When the basename of the command used to invoke zsh starts with the letter
`tt(r)' or the `tt(-r)' command line option is supplied at invocation, the
shell becomes restricted. Emulation mode is determined after stripping the
letter `tt(r)' from the invocation name. The following are disabled in
restricted mode:
startitemize()
itemiz(changing directories with the tt(cd) builtin)
itemiz(changing or unsetting the tt(EGID), tt(EUID), tt(GID),
tt(HISTFILE), tt(HISTSIZE), tt(IFS), tt(LD_AOUT_LIBRARY_PATH),
tt(LD_AOUT_PRELOAD), tt(LD_LIBRARY_PATH), tt(LD_PRELOAD),
tt(MODULE_PATH), tt(module_path), tt(PATH), tt(path), tt(SHELL),
tt(UID) and tt(USERNAME) parameters)
itemiz(specifying command names containing tt(/))
itemiz(specifying command pathnames using tt(hash))
itemiz(redirecting output to files)
itemiz(using the tt(exec) builtin command to replace the shell with another
command)
itemiz(using tt(jobs -Z) to overwrite the shell process' argument and
environment space)
itemiz(using the tt(ARGV0) parameter to override tt(argv[0]) for external
commands)
itemiz(turning off restricted mode with tt(set +r) or tt(unsetopt
RESTRICTED))
enditemize()
These restrictions are enforced after processing the startup files. The
startup files should set up tt(PATH) to point to a directory of commands
which can be safely invoked in the restricted environment. They may also
add further restrictions by disabling selected builtins.
Restricted mode can also be activated any time by setting the
tt(RESTRICTED) option. This immediately enables all the restrictions
described above even if the shell still has not processed all startup
files.
A shell em(Restricted Mode) is an outdated way to restrict what users may
do: modern systems have better, safer and more reliable ways to
confine user actions, such as em(chroot jails), em(containers) and
em(zones).
A restricted shell is very difficult to implement safely. The feature
may be removed in a future version of zsh.
It is important to realise that the restrictions only apply to the shell,
not to the commands it runs (except for some shell builtins). While a
restricted shell can only run the restricted list of commands accessible
via the predefined `tt(PATH)' variable, it does not prevent those
commands from running any other command.
As an example, if `tt(env)' is among the list of em(allowed) commands,
then it allows the user to run any command as `tt(env)' is not a shell
builtin command and can run arbitrary executables.
So when implementing a restricted shell framework it is important to be
fully aware of what actions each of the em(allowed) commands or features
(which may be regarded as em(modules)) can perform.
Many commands can have their behaviour affected by environment
variables. Except for the few listed above, zsh does not restrict
the setting of environment variables.
If a `tt(perl)', `tt(python)', `tt(bash)', or other general purpose
interpreted script is treated as a restricted
command, the user can work around the restriction by
setting specially crafted `tt(PERL5LIB)', `tt(PYTHONPATH)',
`tt(BASH_ENV)' (etc.) environment variables. On GNU systems, any
command can be made to run arbitrary code when performing character set
conversion (including zsh itself) by setting a `tt(GCONV_PATH)'
environment variable. Those are only a few examples.
Bear in mind that, contrary to some other shells, `tt(readonly)' is not a
security feature in zsh as it can be undone and so cannot be used to
mitigate the above.
A restricted shell only works if the allowed commands are few
and carefully written so as not to grant more access to users than
intended. It is also important to restrict what zsh module the user may
load as some of them, such as `tt(zsh/system)', `tt(zsh/mapfile)' and
`tt(zsh/files)', allow bypassing most of the restrictions.

5
README
View File

@@ -52,6 +52,11 @@ or, if your $VISUAL and $EDITOR environment variables vary,
to your .zshrc file. These snippets are compatible with previous
versions of the shell.
Restricted mode has been removed. This was associated with the option
RESTRICTED (-r). This was an outdated way to restrict what users may do and
was very difficult to apply safely. Furthermore, modern systems have better,
safer and more reliable ways to confine user actions.
The ERR_EXIT and ERR_RETURN options were refined to be more self-
consistent and better aligned with the POSIX-2017 specification of
`set -e`:

View File

@@ -150,7 +150,7 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func))
* We need to do this before attempting to open the DB
* in case this variable is already tied to a DB.
*
* This can fail if the variable is readonly or restricted.
* This can fail if the variable is readonly.
* We could call unsetparam() and check errflag instead
* of the return status.
*/

View File

@@ -150,17 +150,12 @@ scanpmparameters(UNUSED(HashTable ht), ScanFunc func, int flags)
static void
setpmcommand(Param pm, char *value)
{
if (isset(RESTRICTED)) {
zwarn("restricted: %s", value);
zsfree(value);
} else {
Cmdnam cn = zshcalloc(sizeof(*cn));
Cmdnam cn = zshcalloc(sizeof(*cn));
cn->node.flags = HASHED;
cn->u.cmd = value;
cn->node.flags = HASHED;
cn->u.cmd = value;
cmdnamtab->addnode(cmdnamtab, ztrdup(pm->node.nam), &cn->node);
}
cmdnamtab->addnode(cmdnamtab, ztrdup(pm->node.nam), &cn->node);
}
/**/

View File

@@ -841,10 +841,6 @@ bin_cd(char *nam, char **argv, Options ops, int func)
{
LinkNode dir;
if (isset(RESTRICTED)) {
zwarnnam(nam, "restricted");
return 1;
}
doprintdir = (doprintdir == -1);
chasinglinks = OPT_ISSET(ops,'P') ||
@@ -2250,10 +2246,6 @@ typeset_single(char *cname, char *pname, Param pm, int func,
paramtab->printnode(&pm->node, PRINT_INCLUDEVALUE|with_ns);
return pm;
}
if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
zerrnam(cname, "%s: restricted", pname);
return pm;
}
if ((pm->node.flags & PM_READONLY) && !(off & PM_READONLY) &&
/* It seems as though these checks should not be specific to
* PM_NAMEREF, but changing that changes historic behavior */
@@ -2388,10 +2380,6 @@ typeset_single(char *cname, char *pname, Param pm, int func,
if (newspecial != NS_NONE) {
Param tpm, pm2;
if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
zerrnam(cname, "%s: restricted", pname);
return pm;
}
if (pm->node.flags & PM_SINGLE) {
zerrnam(cname, "%s: can only have a single instance", pname);
return pm;
@@ -2633,12 +2621,7 @@ typeset_single(char *cname, char *pname, Param pm, int func,
pm->gsu.s->setfn(pm, ztrdup(""));
break;
case PM_INTEGER:
/*
* Restricted integers are dangerous to initialize to 0,
* so don't do that.
*/
if (!(pm->old->node.flags & PM_RESTRICTED))
pm->gsu.i->setfn(pm, 0);
pm->gsu.i->setfn(pm, 0);
break;
case PM_EFLOAT:
case PM_FFLOAT:
@@ -3098,8 +3081,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
for (i = 0; i < paramtab->hsize; i++) {
for (pm = (Param) paramtab->nodes[i]; pm;
pm = (Param) pm->node.next) {
if (((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) ||
(pm->node.flags & PM_UNSET))
if (pm->node.flags & PM_UNSET)
continue;
if (pattry(pprog, pm->node.nam))
addlinknode(pmlist, pm);
@@ -3857,9 +3839,7 @@ bin_unset(char *name, char **argv, Options ops, int func)
for (pm = (Param) paramtab->nodes[i]; pm; pm = next) {
/* record pointer to next, since we may free this one */
next = (Param) pm->node.next;
if ((!(pm->node.flags & PM_RESTRICTED) ||
unset(RESTRICTED)) &&
pattry(pprog, pm->node.nam)) {
if (pattry(pprog, pm->node.nam)) {
if (!OPT_ISSET(ops,'n') &&
(pm->node.flags & PM_NAMEREF) && pm->u.str)
unsetparam(pm->u.str);
@@ -3912,10 +3892,7 @@ bin_unset(char *name, char **argv, Options ops, int func)
*/
if (!pm)
continue;
else if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
zerrnam(name, "%s: restricted", pm->node.nam);
returnval = 1;
} else if (ss) {
else if (ss) {
if ((pm->node.flags & PM_NAMEREF) &&
(!(pm = resolve_nameref(pm)) || pm->width)) {
/* warning? */
@@ -4317,34 +4294,28 @@ bin_hash(char *name, char **argv, Options ops, UNUSED(int func))
returnval = 1;
break;
} else if (ASG_VALUEP(asg)) {
if(isset(RESTRICTED)) {
zwarnnam(name, "restricted: %s", asg->value.scalar);
returnval = 1;
} else {
/* The argument is of the form foo=bar, *
* so define an entry for the table. */
if(OPT_ISSET(ops,'d')) {
/* shouldn't return NULL if asg->name is not NULL */
if (*itype_end(asg->name, IUSER, 0)) {
zwarnnam(name,
"invalid character in directory name: %s",
asg->name);
returnval = 1;
continue;
} else {
Nameddir nd = hn = zshcalloc(sizeof *nd);
nd->node.flags = 0;
nd->dir = ztrdup(asg->value.scalar);
}
/* The argument is of the form foo=bar, *
* so define an entry for the table. */
if (OPT_ISSET(ops, 'd')) {
/* shouldn't return NULL if asg->name is not NULL */
if (*itype_end(asg->name, IUSER, 0)) {
zwarnnam(name, "invalid character in directory name: %s",
asg->name);
returnval = 1;
continue;
} else {
Cmdnam cn = hn = zshcalloc(sizeof *cn);
cn->node.flags = HASHED;
cn->u.cmd = ztrdup(asg->value.scalar);
Nameddir nd = hn = zshcalloc(sizeof *nd);
nd->node.flags = 0;
nd->dir = ztrdup(asg->value.scalar);
}
ht->addnode(ht, ztrdup(asg->name), hn);
if(OPT_ISSET(ops,'v'))
ht->printnode(hn, 0);
} else {
Cmdnam cn = hn = zshcalloc(sizeof *cn);
cn->node.flags = HASHED;
cn->u.cmd = ztrdup(asg->value.scalar);
}
ht->addnode(ht, ztrdup(asg->name), hn);
if (OPT_ISSET(ops, 'v'))
ht->printnode(hn, 0);
} else if (!(hn = ht->getnode2(ht, asg->name))) {
/* With no `=value' part to the argument, *
* work out what it ought to be. */

View File

@@ -35,8 +35,6 @@
enum {
/* Export the variable for "VAR=val cmd ..." */
ADDVAR_EXPORT = 1 << 0,
/* Apply restrictions for variable */
ADDVAR_RESTRICT = 1 << 1,
/* Variable list is being restored later */
ADDVAR_RESTORE = 1 << 2
};
@@ -731,10 +729,6 @@ execute(LinkList args, int flags, int defpath)
int eno = 0, ee;
arg0 = (char *) peekfirst(args);
if (isset(RESTRICTED) && (strchr(arg0, '/') || defpath)) {
zerr("%s: restricted", arg0);
_exit(1);
}
/* If the parameter STTY is set in the command's environment, *
* we first run the stty command with the value of this *
@@ -755,7 +749,7 @@ execute(LinkList args, int flags, int defpath)
/* If ARGV0 is in the commands environment, we use *
* that as argv[0] for this external command */
if (unset(RESTRICTED) && (z = zgetenv("ARGV0"))) {
if ((z = zgetenv("ARGV0"))) {
setdata(firstnode(args), (void *) ztrdup(z));
/*
* Note we don't do anything with the parameter structure
@@ -2588,14 +2582,6 @@ addvars(Estate state, Wordcode pc, int addflags)
fputc(' ', xtrerr);
}
if ((addflags & ADDVAR_EXPORT) && !strchr(name, '[')) {
if ((addflags & ADDVAR_RESTRICT) && isset(RESTRICTED) &&
(pm = (Param) paramtab->removenode(paramtab, name)) &&
(pm->node.flags & PM_RESTRICTED)) {
zerr("%s: restricted", pm->node.nam);
zsfree(val);
state->pc = opc;
return;
}
if (strcmp(name, "STTY") == 0) {
zsfree(STTYval);
STTYval = ztrdup(val);
@@ -2604,7 +2590,7 @@ addvars(Estate state, Wordcode pc, int addflags)
opts[ALLEXPORT] = 1;
if (isset(KSHARRAYS))
unsetparam(name);
pm = assignsparam(name, val, myflags);
pm = assignsparam(name, val, myflags);
opts[ALLEXPORT] = allexp;
} else
pm = assignsparam(name, val, myflags);
@@ -3418,15 +3404,6 @@ execcmd_exec(Estate state, Execcmd_params eparams,
shelltime(&shti, &chti, &then, 1);
return;
}
} else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && do_exec) {
zerrnam("exec", "%s: restricted",
(char *) getdata(firstnode(args)));
lastval = 1;
if (forked)
_realexit();
if (how & Z_TIMED)
shelltime(&shti, &chti, &then, 1);
return;
}
/*
@@ -3783,10 +3760,6 @@ execcmd_exec(Estate state, Execcmd_params eparams,
fixfds(save);
execerr();
}
if (isset(RESTRICTED) && IS_WRITE_FILE(fn->type)) {
zwarn("writing redirection not allowed in restricted mode");
execerr();
}
if (unset(EXECOPT))
continue;
switch(fn->type) {
@@ -4314,7 +4287,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
}
if (type == WC_SIMPLE || type == WC_TYPESET) {
if (varspc) {
int addflags = ADDVAR_EXPORT|ADDVAR_RESTRICT;
int addflags = ADDVAR_EXPORT;
if (forked)
addflags |= ADDVAR_RESTORE;
addvars(state, varspc, addflags);
@@ -4463,8 +4436,7 @@ save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p)
tpm = (Param) zshcalloc(sizeof *tpm);
tpm->node.nam = ztrdup(pm->node.nam);
copyparam(tpm, pm, 0);
} else if (!(pm->node.flags & PM_READONLY) &&
(unset(RESTRICTED) || !(pm->node.flags & PM_RESTRICTED))) {
} else if (!(pm->node.flags & PM_READONLY)) {
/*
* In this case we're just saving parts of
* the parameter in a temporary, so use heap allocation
@@ -6114,9 +6086,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
/* take care of SUNKEYBOARDHACK but not of EMACS/VI */
if (funcsave->opts[SUNKEYBOARDHACK] != opts[SUNKEYBOARDHACK])
keyboardhackchar = funcsave->opts[SUNKEYBOARDHACK] ? '`' : '\0';
/* restore all shell options except PRIVILEGED and RESTRICTED */
/* restore all shell options except PRIVILEGED */
funcsave->opts[PRIVILEGED] = opts[PRIVILEGED];
funcsave->opts[RESTRICTED] = opts[RESTRICTED];
memcpy(opts, funcsave->opts, sizeof(opts));
emulation = funcsave->emulation;
if (init_typtab)

View File

@@ -255,8 +255,6 @@ loop(int toplevel, int justonce)
return LOOP_OK;
}
static int restricted;
/* original argv[0]. This is already metafied */
static char *argv0;
@@ -494,8 +492,6 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
if (!(optno = optlookup(*argv))) {
WARN_OPTION("no such option: %s", *argv);
return 1;
} else if (optno == RESTRICTED && toplevel) {
restricted = action;
} else if ((optno == EMACSMODE || optno == VIMODE) && !toplevel) {
WARN_OPTION("can't change option: %s", *argv);
} else {
@@ -524,8 +520,6 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
if (!(optno = optlookupc(**argv))) {
WARN_OPTION("bad option: -%c", **argv);
return 1;
} else if (optno == RESTRICTED && toplevel) {
restricted = action;
} else if ((optno == EMACSMODE || optno == VIMODE) &&
!toplevel) {
WARN_OPTION("can't change option: %s", *argv);
@@ -1529,12 +1523,10 @@ run_init_scripts(void)
void
init_misc(char *cmd, char *zsh_name)
{
#ifndef RESTRICTED_R
if ( restricted )
#else
if (*zsh_name == 'r' || restricted)
#endif
dosetopt(RESTRICTED, 1, 0, opts);
if (*zsh_name == 'r') {
zerrnam(zsh_name, "no support for restricted mode");
exit(1);
}
if (cmd) {
if (SHIN >= 10)
close(SHIN);

View File

@@ -2425,10 +2425,6 @@ bin_fg(char *name, char **argv, Options ops, int func)
if (OPT_ISSET(ops,'Z')) {
int len;
if(isset(RESTRICTED)) {
zwarnnam(name, "-Z is restricted");
return 1;
}
if(!argv[0] || argv[1]) {
zwarnnam(name, "-Z requires one argument");
return 1;

View File

@@ -240,7 +240,6 @@ static struct optname optns[] = {
{{NULL, "rcs", OPT_ALL}, RCS},
{{NULL, "recexact", 0}, RECEXACT},
{{NULL, "rematchpcre", 0}, REMATCHPCRE},
{{NULL, "restricted", OPT_SPECIAL}, RESTRICTED},
{{NULL, "rmstarsilent", OPT_BOURNE}, RMSTARSILENT},
{{NULL, "rmstarwait", 0}, RMSTARWAIT},
{{NULL, "sharehistory", OPT_KSH}, SHAREHISTORY},
@@ -357,7 +356,7 @@ static short zshletters[LAST_OPT - FIRST_OPT + 1] = {
/* o */ 0, /* long option name follows */
/* p */ PRIVILEGED,
/* q */ 0,
/* r */ RESTRICTED,
/* r */ 0, /* formerly RESTRICTED */
/* s */ SHINSTDIN,
/* t */ SINGLECOMMAND,
/* u */ -UNSET,
@@ -434,7 +433,7 @@ static short kshletters[LAST_OPT - FIRST_OPT + 1] = {
/* o */ 0,
/* p */ PRIVILEGED,
/* q */ 0,
/* r */ RESTRICTED,
/* r */ 0,
/* s */ SHINSTDIN,
/* t */ SINGLECOMMAND,
/* u */ -UNSET,
@@ -727,25 +726,6 @@ optlookupc(char c)
return optletters[c - FIRST_OPT];
}
/**/
static void
restrictparam(char *nam)
{
Param pm = (Param) paramtab->getnode(paramtab, nam);
if (pm) {
pm->node.flags |= PM_SPECIAL | PM_RESTRICTED;
return;
}
createparam(nam, PM_SCALAR | PM_UNSET | PM_SPECIAL | PM_RESTRICTED);
}
/* list of restricted parameters which are not otherwise special */
static char *rparams[] = {
"SHELL", "HISTFILE", "LD_LIBRARY_PATH", "LD_AOUT_LIBRARY_PATH",
"LD_PRELOAD", "LD_AOUT_PRELOAD", NULL
};
/* Set or unset an option, as a result of user request. The option *
* number may be negative, indicating that the sense is reversed *
* from the usual meaning of the option. */
@@ -760,16 +740,7 @@ dosetopt(int optno, int value, int force, char *new_opts)
optno = -optno;
value = !value;
}
if (optno == RESTRICTED) {
if (isset(RESTRICTED))
return value ? 0 : -1;
if (value) {
char **s;
for (s = rparams; *s; s++)
restrictparam(*s);
}
} else if(!force && optno == EXECOPT && !value && interact) {
if (!force && optno == EXECOPT && !value && interact) {
/* cannot set noexec when interactive */
return -1;
} else if(!force && (optno == INTERACTIVE || optno == SHINSTDIN ||

View File

@@ -296,18 +296,18 @@ static initparam special_params[] ={
#define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
IPDEF1("#", pound_gsu, PM_READONLY_SPECIAL),
IPDEF1("ERRNO", errno_gsu, PM_UNSET),
IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
IPDEF1("EGID", egid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
IPDEF1("HISTSIZE", histsize_gsu, PM_RESTRICTED),
IPDEF1("GID", gid_gsu, PM_DONTIMPORT),
IPDEF1("EGID", egid_gsu, PM_DONTIMPORT),
IPDEF1("HISTSIZE", histsize_gsu, 0),
IPDEF1("RANDOM", random_gsu, 0),
IPDEF1("SAVEHIST", savehist_gsu, PM_RESTRICTED),
IPDEF1("SAVEHIST", savehist_gsu, 0),
IPDEF1("SECONDS", intseconds_gsu, 0),
IPDEF1("UID", uid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
IPDEF1("EUID", euid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
IPDEF1("UID", uid_gsu, PM_DONTIMPORT),
IPDEF1("EUID", euid_gsu, PM_DONTIMPORT),
IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY_SPECIAL),
#define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0}
IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED),
IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT),
IPDEF2("-", dash_gsu, PM_READONLY_SPECIAL),
IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT),
IPDEF2("HOME", home_gsu, PM_UNSET),
@@ -315,7 +315,7 @@ IPDEF2("TERM", term_gsu, PM_UNSET),
IPDEF2("TERMINFO", terminfo_gsu, PM_UNSET),
IPDEF2("TERMINFO_DIRS", terminfodirs_gsu, PM_UNSET),
IPDEF2("WORDCHARS", wordchars_gsu, 0),
IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT | PM_RESTRICTED),
IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT),
IPDEF2("_", underscore_gsu, PM_DONTIMPORT),
IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu, PM_DONTIMPORT),
IPDEF2("0", argzero_gsu, 0),
@@ -396,12 +396,12 @@ IPDEF8("CDPATH", &cdpath, "cdpath", PM_TIED),
IPDEF8("FIGNORE", &fignore, "fignore", PM_TIED),
IPDEF8("FPATH", &fpath, "fpath", PM_TIED),
IPDEF8("MAILPATH", &mailpath, "mailpath", PM_TIED),
IPDEF8("PATH", &path, "path", PM_RESTRICTED|PM_TIED),
IPDEF8("PATH", &path, "path", PM_TIED),
IPDEF8("PSVAR", &psvar, "psvar", PM_TIED),
IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY_SPECIAL|PM_TIED),
/* MODULE_PATH is not imported for security reasons */
IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED|PM_TIED),
IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_TIED),
#define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
@@ -430,8 +430,8 @@ IPDEF9("psvar", &psvar, "PSVAR", PM_TIED),
IPDEF9("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_TIED|PM_READONLY_SPECIAL),
IPDEF9("module_path", &module_path, "MODULE_PATH", PM_TIED|PM_RESTRICTED),
IPDEF9("path", &path, "PATH", PM_TIED|PM_RESTRICTED),
IPDEF9("module_path", &module_path, "MODULE_PATH", PM_TIED),
IPDEF9("path", &path, "PATH", PM_TIED),
/* These are known to zsh alone. */
@@ -449,12 +449,12 @@ IPDEF8("CDPATH", &cdpath, NULL, 0),
IPDEF8("FIGNORE", &fignore, NULL, 0),
IPDEF8("FPATH", &fpath, NULL, 0),
IPDEF8("MAILPATH", &mailpath, NULL, 0),
IPDEF8("PATH", &path, NULL, PM_RESTRICTED),
IPDEF8("PATH", &path, NULL, 0),
IPDEF8("PSVAR", &psvar, NULL, 0),
IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY_SPECIAL),
/* MODULE_PATH is not imported for security reasons */
IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED),
IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT),
{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
};
@@ -1110,10 +1110,6 @@ createparam(char *name, int flags)
zerr("read-only variable: %s", name);
return NULL;
}
if ((oldpm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
zerr("%s: restricted", name);
return NULL;
}
if (!(oldpm->node.flags & PM_UNSET) ||
(oldpm->node.flags & PM_SPECIAL) ||
/* POSIXBUILTINS horror: we need to retain 'export' flags */
@@ -2702,11 +2698,6 @@ assignstrvalue(Value v, char *val, int flags)
zsfree(val);
return;
}
if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
zerr("%s: restricted", v->pm->node.nam);
zsfree(val);
return;
}
if ((v->pm->node.flags & PM_HASHED) &&
(v->scanflags & (SCANPM_MATCHMANY|SCANPM_ARRONLY))) {
zerr("%s: attempt to set slice of associative array", v->pm->node.nam);
@@ -2872,10 +2863,6 @@ setnumvalue(Value v, mnumber val)
zerr("read-only variable: %s", v->pm->node.nam);
return;
}
if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
zerr("%s: restricted", v->pm->node.nam);
return;
}
switch (PM_TYPE(v->pm->node.flags)) {
case PM_SCALAR:
case PM_NAMEREF:
@@ -2914,11 +2901,6 @@ setarrvalue(Value v, char **val)
freearray(val);
return;
}
if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
zerr("%s: restricted", v->pm->node.nam);
freearray(val);
return;
}
if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED))) {
freearray(val);
zerr("%s: attempt to assign array value to non-array",
@@ -3867,10 +3849,6 @@ unsetparam_pm(Param pm, int altflag, int exp)
pm->node.nam);
return 1;
}
if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
zerr("%s: restricted", pm->node.nam);
return 1;
}
if (pm->ename && !altflag)
altremove = ztrdup(pm->ename);

View File

@@ -451,7 +451,7 @@ zhandler(int sig)
case SIGINT:
if (!handletrap(SIGINT)) {
if ((isset(PRIVILEGED) || isset(RESTRICTED)) &&
if (isset(PRIVILEGED) &&
isset(INTERACTIVE) && (noerrexit & NOERREXIT_SIGNAL))
zexit(SIGINT, ZEXIT_SIGNAL);
errflag |= ERRFLAG_INT;

View File

@@ -1013,24 +1013,6 @@
>one'quoted'expression
>anotherquotedexpression
# too lazy to test jobs -Z and ARGV0.
(setopt restricted; cd /)
(setopt restricted; PATH=/bin:/usr/bin)
(setopt restricted; /bin/ls)
(setopt restricted; hash ls=/bin/ls)
(setopt restricted; print ha >outputfile)
(setopt restricted; exec ls)
(setopt restricted; unsetopt restricted)
:
0:RESTRICTED option
?(eval):cd:1: restricted
?(eval):2: PATH: restricted
?(eval):3: /bin/ls: restricted
?(eval):hash:4: restricted: /bin/ls
?(eval):5: writing redirection not allowed in restricted mode
?(eval):exec:6: ls: restricted
?(eval):unsetopt:7: can't change option: restricted
# ' emacs deconfusion
fn() {

View File

@@ -248,20 +248,6 @@ AC_ARG_ENABLE(dynamic,
AS_HELP_STRING([--disable-dynamic],[turn off dynamically loaded binary modules]),
[dynamic="$enableval"], [dynamic=yes])
dnl Do you want to disable restricted on r* commands
ifdef([restricted-r],[undefine([restricted-r])])dnl
AH_TEMPLATE([RESTRICTED_R],
[Undefine this if you don't want to get a restricted shell
when zsh is exec'd with basename that starts with r.
By default this is defined.])
AC_ARG_ENABLE(restricted-r,
AS_HELP_STRING([--disable-restricted-r],[turn off r* invocation for restricted shell]),
[if test x$enableval = xyes; then
AC_DEFINE(RESTRICTED_R)
fi],
AC_DEFINE(RESTRICTED_R)
)
dnl Do you want to disable use of locale functions
AH_TEMPLATE([CONFIG_LOCALE],
[Undefine if you don't want local features. By default this is defined.])