Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Security issue in Zsh restricted mode (zsh -r) – escape via history built‑ins



Jun T wrote:
>
> > 2026/04/06 3:24, Oliver Kiddle <opk@xxxxxxx> wrote:
> > 
> > It does nothing for invoking zsh as rzsh. In your (or anyone else's)
> > opinion, should that code be retained and also replaced with an error.
>
> I think rzsh should behave just like 'zsh -r', i.e., error exit.

That's probably best. The following patch replaces 54288, and also
addresses your earlier comment at the incorrect setup of the zshletters
array (thanks for that).

>
> > There's also [[ -o restricted ]]. We could patch optison() in cond.c to
> > silently return 1 or leave it also printing a "no such option" error and
> > aborting.
>
> This is more subtle, but aborting is overdone, and I feel it's OK to
> treat [[ -o r/restricted ]] just like other non_existent_options; i.e.,
> return 3 with warning, or silently return 1 if posix_builtins is set.

In terms of conditional expressions, [[ -o restricted ]] ends up being
false and anything like [[ -o restricted || -o privileged ]] will work
as expected just with the additional error message. The exceptions to
this are negations like [[ ! -o restricted ]] and [[ -o norestricted ]].
Given the flexibility zsh allows with respect to case and underscores,
special casing this is probably going too far and is part of why I
considered the approach of leaving a stub option in the initial patch.

Any restricted shell setup really ought to be fairly self contained and
not need to test for it.

Oliver

diff --git a/Completion/Zsh/Command/_set b/Completion/Zsh/Command/_set
index 27c7f3c7d..720c667a9 100644
--- a/Completion/Zsh/Command/_set
+++ b/Completion/Zsh/Command/_set
@@ -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]
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 729a6ac26..77dfb3fdb 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -2466,14 +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)))(
-This option is ignored and only exists for compatibility. Support
-for restricted mode has been removed.
-)
 pindex(SHIN_STDIN)
 pindex(NO_SHIN_STDIN)
 pindex(SHINSTDIN)
diff --git a/Src/init.c b/Src/init.c
index beb9b2c3c..7c3b82461 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -1523,6 +1523,10 @@ run_init_scripts(void)
 void
 init_misc(char *cmd, char *zsh_name)
 {
+    if (*zsh_name == 'r') {
+	zerrnam(zsh_name, "no support for restricted mode");
+	exit(1);
+    }
     if (cmd) {
 	if (SHIN >= 10)
 	    close(SHIN);
diff --git a/Src/options.c b/Src/options.c
index 649c654ba..1f459bba4 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -240,7 +240,6 @@ static struct optname optns[] = {
 {{NULL, "rcs",		      OPT_ALL},			 RCS},
 {{NULL, "recexact",	      0},			 RECEXACT},
 {{NULL, "rematchpcre",	      0},			 REMATCHPCRE},
-{{NULL, "restricted",	      0},			 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,6 @@ static short kshletters[LAST_OPT - FIRST_OPT + 1] = {
     /* o */  0,
     /* p */  PRIVILEGED,
     /* q */  0,
-    /* r */  RESTRICTED,
     /* s */  SHINSTDIN,
     /* t */  SINGLECOMMAND,
     /* u */ -UNSET,




Messages sorted by: Reverse Date, Date, Thread, Author