summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--Etc/FAQ.yo2
-rw-r--r--NEWS21
-rw-r--r--README6
-rw-r--r--Src/exec.c36
-rw-r--r--Test/A05execution.ztst22
6 files changed, 72 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index 9d95cda22..85d564601 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2018-09-03 Anthony Sottile <asottile@umich.edu>
+
+ * CVE-2018-0502, CVE-2018-13259: Fix two security issues in
+ shebang line parsing. [With Buck Evan]
+
2018-09-03 Daniel Shahaf <d.s@daniel.shahaf.name>
* 43367: Makefile.in: Add maintainer targets 'tarxz-src' and
diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo
index 12bd4eb3d..d4dc8a150 100644
--- a/Etc/FAQ.yo
+++ b/Etc/FAQ.yo
@@ -306,7 +306,7 @@ sect(On what machines will it run?)
sect(What's the latest version?)
- Zsh 5.5.1 is the latest production version. For details of all the
+ Zsh 5.6 is the latest production version. For details of all the
changes, see the NEWS file in the source distribution.
A beta of the next version is sometimes available. Development of zsh is
diff --git a/NEWS b/NEWS
index 93d879ce3..7b3e5692c 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,27 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
Note also the list of incompatibilities in the README file.
+Changes from 5.5.1-test-2 to 5.6
+--------------------------------
+
+CVE-2018-0502: Data from the second line of a #! script file might be passed to
+execve(). For example, in the following situation -
+.
+ printf '#!foo\nbar' > baz
+ ./baz
+.
+the shell might take "bar" rather than "foo" for the argv[0] to be passed to
+execve(). [ Reported by Anthony Sottile and Buck Evan. ]
+
+CVE-2018-13259: A shebang line longer than 64 characters would be truncated.
+For example, in the following situation:
+.
+ ( printf '#!'; repeat 64 printf 'x'; printf 'y' ) > foo
+ ./foo
+.
+the shell might execute x...x (64 repetitions) rather than x...xy (64 x's,
+one y). [ Reported by Daniel Shahaf. ]
+
Changes from 5.5.1 to 5.5.1-test-2
----------------------------------
diff --git a/README b/README
index 8817433e4..ed29d0107 100644
--- a/README
+++ b/README
@@ -5,9 +5,9 @@ THE Z SHELL (ZSH)
Version
-------
-This is version 5.5.1-test-2 of the shell. This is a test release. There
-are some significant bug fixes and a few user visible additions since
-5.5.1. All zsh installations are encouraged to upgrade.
+This is version 5.6 of the shell. This is a security and feature release.
+There are some significant bug fixes and a few user visible additions since
+5.5.1. All zsh installations are encouraged to upgrade as soon as possible.
Note in particular the changes highlighted under "Incompatibilities since
5.5.1" below. See NEWS for more information.
diff --git a/Src/exec.c b/Src/exec.c
index 615a5086f..09ee13209 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -458,7 +458,7 @@ execcursh(Estate state, int do_exec)
/* execve after handling $_ and #! */
-#define POUNDBANGLIMIT 64
+#define POUNDBANGLIMIT 128
/**/
static int
@@ -499,18 +499,20 @@ zexecve(char *pth, char **argv, char **newenvp)
if ((fd = open(pth, O_RDONLY|O_NOCTTY)) >= 0) {
argv0 = *argv;
*argv = pth;
- execvebuf[0] = '\0';
+ memset(execvebuf, '\0', POUNDBANGLIMIT + 1);
ct = read(fd, execvebuf, POUNDBANGLIMIT);
close(fd);
if (ct >= 0) {
- if (execvebuf[0] == '#') {
- if (execvebuf[1] == '!') {
- for (t0 = 0; t0 != ct; t0++)
- if (execvebuf[t0] == '\n')
- break;
+ if (ct >= 2 && execvebuf[0] == '#' && execvebuf[1] == '!') {
+ for (t0 = 0; t0 != ct; t0++)
+ if (execvebuf[t0] == '\n')
+ break;
+ if (t0 == ct)
+ zerr("%s: bad interpreter: %s: %e", pth,
+ execvebuf + 2, eno);
+ else {
while (inblank(execvebuf[t0]))
execvebuf[t0--] = '\0';
- execvebuf[POUNDBANGLIMIT] = '\0';
for (ptr = execvebuf + 2; *ptr && *ptr == ' '; ptr++);
for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++);
if (eno == ENOENT) {
@@ -519,10 +521,16 @@ zexecve(char *pth, char **argv, char **newenvp)
*ptr = '\0';
if (*ptr2 != '/' &&
(pprog = pathprog(ptr2, NULL))) {
- argv[-2] = ptr2;
- argv[-1] = ptr + 1;
- winch_unblock();
- execve(pprog, argv - 2, newenvp);
+ if (ptr == execvebuf + t0 + 1) {
+ argv[-1] = ptr2;
+ winch_unblock();
+ execve(pprog, argv - 1, newenvp);
+ } else {
+ argv[-2] = ptr2;
+ argv[-1] = ptr + 1;
+ winch_unblock();
+ execve(pprog, argv - 2, newenvp);
+ }
}
zerr("%s: bad interpreter: %s: %e", pth, ptr2,
eno);
@@ -537,10 +545,6 @@ zexecve(char *pth, char **argv, char **newenvp)
winch_unblock();
execve(ptr2, argv - 1, newenvp);
}
- } else if (eno == ENOEXEC) {
- argv[-1] = "sh";
- winch_unblock();
- execve("/bin/sh", argv - 1, newenvp);
}
} else if (eno == ENOEXEC) {
for (t0 = 0; t0 != ct; t0++)
diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst
index 0804691a7..fb39d0589 100644
--- a/Test/A05execution.ztst
+++ b/Test/A05execution.ztst
@@ -12,7 +12,14 @@
print '#!/bin/sh\necho This is dir2' >dir2/tstcmd
+ print -n '#!sh\necho This is slashless' >tstcmd-slashless
+ print -n '#!echo foo\necho This is arg' >tstcmd-arg
+ print '#!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxnyyy' >tstcmd-interp-too-long
+ print '#!/bin/sh\necho should not execute; exit 1' >xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxn
+
chmod 755 tstcmd dir1/tstcmd dir2/tstcmd
+ chmod 755 tstcmd-slashless tstcmd-arg tstcmd-interp-too-long
+ chmod 755 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxn
%test
./tstcmd
@@ -33,6 +40,21 @@
0:path (2)
>This is top
+ PATH=/bin:${ZTST_testdir}/command.tmp/ tstcmd-slashless
+0:path (3)
+>This is slashless
+
+ PATH=/bin:${ZTST_testdir}/command.tmp tstcmd-arg
+0:path (4)
+*>foo */command.tmp/tstcmd-arg
+
+ path=(/bin ${ZTST_testdir}/command.tmp/)
+ tstcmd-interp-too-long 2>&1; echo "status $?"
+ path=($storepath)
+0:path (5)
+*>*tstcmd-interp-too-long: bad interpreter: x*xn: no such file or directory
+>status 127
+
functst() { print $# arguments:; print -l $*; }
functst "Eines Morgens" "als Gregor Samsa"
functst ""