summary refs log tree commit diff
diff options
context:
space:
mode:
-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);