mirror of
https://git.code.sf.net/p/zsh/code
synced 2026-04-18 06:53:35 -04:00
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:
11
ChangeLog
11
ChangeLog
@@ -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:
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -64,7 +64,6 @@ menu(See Also)
|
||||
Invocation
|
||||
|
||||
menu(Compatibility)
|
||||
menu(Restricted Shell)
|
||||
|
||||
Shell Grammar
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
5
README
@@ -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`:
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -150,10 +150,6 @@ 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));
|
||||
|
||||
cn->node.flags = HASHED;
|
||||
@@ -161,7 +157,6 @@ setpmcommand(Param pm, char *value)
|
||||
|
||||
cmdnamtab->addnode(cmdnamtab, ztrdup(pm->node.nam), &cn->node);
|
||||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
static void
|
||||
|
||||
@@ -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,11 +2621,6 @@ 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);
|
||||
break;
|
||||
case PM_EFLOAT:
|
||||
@@ -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,17 +4294,12 @@ 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",
|
||||
zwarnnam(name, "invalid character in directory name: %s",
|
||||
asg->name);
|
||||
returnval = 1;
|
||||
continue;
|
||||
@@ -4344,7 +4316,6 @@ bin_hash(char *name, char **argv, Options ops, UNUSED(int func))
|
||||
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. */
|
||||
|
||||
37
Src/exec.c
37
Src/exec.c
@@ -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);
|
||||
@@ -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)
|
||||
|
||||
16
Src/init.c
16
Src/init.c
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
50
Src/params.c
50
Src/params.c
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
14
configure.ac
14
configure.ac
@@ -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.])
|
||||
|
||||
Reference in New Issue
Block a user