From ddb6c5b4c0ab9c6a7404112d367f0c7cc400ceec Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 3 Sep 2018 14:39:25 +0000 Subject: [PATCH] CVE-2018-0502, CVE-2018-13259: Fix two security issues in shebang line parsing. See NEWS for more information. Patch by Anthony Sottile and Buck Evan. Upstream-commit: 1c4c7b6a4d17294df028322b70c53803a402233d Signed-off-by: Kamil Dudka --- Etc/FAQ.yo | 2 +- Src/exec.c | 36 ++++++++++++++++++++---------------- Test/A05execution.ztst | 22 ++++++++++++++++++++++ 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo index 72ff7fa..8552fe7 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/Src/exec.c b/Src/exec.c index 216057a..0908a1a 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -453,7 +453,7 @@ execcursh(Estate state, int do_exec) /* execve after handling $_ and #! */ -#define POUNDBANGLIMIT 64 +#define POUNDBANGLIMIT 128 /**/ static int @@ -494,18 +494,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) { @@ -514,10 +516,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); @@ -532,10 +540,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 0804691..fb39d05 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 "" -- 2.17.1