From: Justine Tunney <jtunney@gmail.com>
To: zsh-workers@zsh.org
Subject: PATCH: Allow more scripts without #!
Date: Mon, 25 Jan 2021 22:35:18 -0800 [thread overview]
Message-ID: <CANtdasR_vBwBJEKKVtX1pf7-jR3HPdesA5zhcvOvQ-TYu7CLfg@mail.gmail.com> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 698 bytes --]
This change updates the binary safety check so that zsh can run shell
scripts with concatenated binary content within the first 128 bytes,
provided a line exists beforehand with a lowercase character or shell
expansion syntax. Note that this only impacts classic implicit shell
scripts which don't have a shebang line.
POSIX rules were updated to loosen binary restrictions and require this
behavior going forward. A similar change was made last year to the FreeBSD
Almquist Shell. It's needed by projects such as the Cosmopolitan C Library,
which creates polyglot executables that run on all operating systems.
I release this change into the public domain. See unlicense / creative
commons cc0.
[-- Attachment #1.2: Type: text/html, Size: 777 bytes --]
[-- Attachment #2: execve.patch --]
[-- Type: application/octet-stream, Size: 3388 bytes --]
commit 94a4bc14bb2e415ec3d10cf716512bd3e0d99f48
Author: Justine Tunney <jtunney@gmail.com>
Date: Mon Jan 25 21:34:50 2021 -0800
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
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);
next reply other threads:[~2021-01-26 6:36 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-26 6:35 Justine Tunney [this message]
2021-02-15 15:45 ` Daniel Shahaf
2021-02-15 22:44 ` Bart Schaefer
2021-02-15 23:06 ` Justine Tunney
2021-02-16 9:18 ` Peter Stephenson
2021-02-17 14:53 ` Justine Tunney
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CANtdasR_vBwBJEKKVtX1pf7-jR3HPdesA5zhcvOvQ-TYu7CLfg@mail.gmail.com \
--to=jtunney@gmail.com \
--cc=zsh-workers@zsh.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).