summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustine Tunney <jtunney@gmail.com>2021-01-25 21:34:50 -0800
committerPeter Stephenson <p.stephenson@samsung.com>2021-02-16 09:16:20 +0000
commit326d9c203b3980c0f841bc62b06e37134c6e51ea (patch)
tree07854fc13213a27825758d55ac2cfc273ef4f4b5
parent83cc7c6bf08762c3fdeb76a44e4086734ff1db13 (diff)
downloadzsh-326d9c203b3980c0f841bc62b06e37134c6e51ea.tar.gz
zsh-326d9c203b3980c0f841bc62b06e37134c6e51ea.zip
Allow more scripts without #!
This change modifies the zsh binary safety check surrounding execve() so it can run shell scripts having concatenated binary content. We're using the same safety check as FreeBSD /bin/sh [1]. POSIX was recently revised to require this behavior: "The input file may be of any type, but the initial portion of the file intended to be parsed according to the shell grammar (XREF to XSH 2.10.2 Shell Grammar Rules) shall consist of characters and shall not contain the NUL character. The shell shall not enforce any line length limits." "Earlier versions of this standard required that input files to the shell be text files except that line lengths were unlimited. However, that was overly restrictive in relation to the fact that shells can parse a script without a trailing newline, and in relation to a common practice of concatenating a shell script ending with an 'exit' or 'exec $command' with a binary data payload to form a single-file self-extracting archive." [2] [3] One example use case of such scripts, is the Cosmopolitan C Library [4] which configuse the GNU Linker to output a polyglot shell+binary format that runs on Linux / Mac / Windows / FreeBSD / OpenBSD. [1] https://github.com/freebsd/freebsd-src/commit/9a1cd363318b7e9e70ef6af27d1675b371c16b1a [2] http://austingroupbugs.net/view.php?id=1250 [3] http://austingroupbugs.net/view.php?id=1226#c4394 [4] https://justine.lol/cosmopolitan/index.html
-rw-r--r--ChangeLog6
-rw-r--r--Src/exec.c27
2 files changed, 29 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 1648ea243..c89fce748 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2021-02-16 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 47876: Justtine Tunney: Src/exec.c: Add more cases where
+ shell scripts can be recognised from the first line as
+ described by POSIX.
+
2021-02-16 Lawrence Velázquez <vq@larryv.me>
* 47830: Doc/Zsh/contrib.yo, README: Fix some documentation typos
diff --git a/Src/exec.c b/Src/exec.c
index ecad923de..2301f85ad 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -547,10 +547,29 @@ zexecve(char *pth, char **argv, char **newenvp)
}
}
} else if (eno == ENOEXEC) {
- for (t0 = 0; t0 != ct; t0++)
- if (!execvebuf[t0])
- break;
- if (t0 == ct) {
+ /* Perform binary safety check on classic shell *
+ * scripts (shebang wasn't introduced until UNIX *
+ * Seventh Edition). POSIX says we shall allow *
+ * execution of scripts with concatenated binary *
+ * and suggests checking a line exists before the *
+ * first NUL character with a lowercase letter or *
+ * expansion. This is consistent with FreeBSD sh. */
+ int isbinary, hasletter;
+ if (!(ptr2 = memchr(execvebuf, '\0', ct))) {
+ isbinary = 0;
+ } else {
+ isbinary = 1;
+ hasletter = 0;
+ for (ptr = execvebuf; ptr < ptr2; ptr++) {
+ if (islower(*ptr) || *ptr == '$' || *ptr == '`')
+ hasletter = 1;
+ if (hasletter && *ptr == '\n') {
+ isbinary = 0;
+ break;
+ }
+ }
+ }
+ if (!isbinary) {
argv[-1] = "sh";
winch_unblock();
execve("/bin/sh", argv - 1, newenvp);