Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 30 Jan 2021 15:11:45 GMT
From:      Jilles Tjoelker <jilles@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 3708b615c354 - stable/12 - sh: Allow more scripts without #!
Message-ID:  <202101301511.10UFBjcd033018@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by jilles:

URL: https://cgit.FreeBSD.org/src/commit/?id=3708b615c354df013037c065d5a714207c041ea8

commit 3708b615c354df013037c065d5a714207c041ea8
Author:     Jilles Tjoelker <jilles@FreeBSD.org>
AuthorDate: 2020-05-30 16:00:49 +0000
Commit:     Jilles Tjoelker <jilles@FreeBSD.org>
CommitDate: 2021-01-30 15:10:26 +0000

    sh: Allow more scripts without #!
    
    Austin Group bugs #1226 and #1250 changed the requirements for shell scripts
    without #! (POSIX does not specify #!; this is about the shell execution
    when execve(2) returns an [ENOEXEC] error).
    
    POSIX says we shall allow execution if the initial part intended to be
    parsed by the shell consists of characters and does not contain the NUL
    character.  This allows concatenating a shell script (ending with exec or
    exit) and a binary payload.
    
    In order to reject common binary files such as PNG images, check that there
    is a lowercase letter or expansion before the last newline before the NUL
    character, in addition to the check for the newline character suggested by
    POSIX.
    
    (cherry picked from commit e0f5c1387df23c8c4811f5b24a7ef6ecac51a71a)
---
 bin/sh/exec.c                       | 34 +++++++++++++++++++++++++++++++++-
 bin/sh/tests/execution/Makefile     |  1 +
 bin/sh/tests/execution/shellproc6.0 |  8 ++++++++
 3 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/bin/sh/exec.c b/bin/sh/exec.c
index 95bf22a4a9f9..2bbef6ca0d27 100644
--- a/bin/sh/exec.c
+++ b/bin/sh/exec.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
 #include <fcntl.h>
 #include <errno.h>
 #include <paths.h>
+#include <stdbool.h>
 #include <stdlib.h>
 
 /*
@@ -144,6 +145,37 @@ shellexec(char **argv, char **envp, const char *path, int idx)
 }
 
 
+static bool
+isbinary(const char *data, size_t len)
+{
+	const char *nul, *p;
+	bool hasletter;
+
+	nul = memchr(data, '\0', len);
+	if (nul == NULL)
+		return false;
+	/*
+	 * POSIX says we shall allow execution if the initial part intended
+	 * to be parsed by the shell consists of characters and does not
+	 * contain the NUL character. This allows concatenating a shell
+	 * script (ending with exec or exit) and a binary payload.
+	 *
+	 * In order to reject common binary files such as PNG images, check
+	 * that there is a lowercase letter or expansion before the last
+	 * newline before the NUL character, in addition to the check for
+	 * the newline character suggested by POSIX.
+	 */
+	hasletter = false;
+	for (p = data; *p != '\0'; p++) {
+		if ((*p >= 'a' && *p <= 'z') || *p == '$' || *p == '`')
+			hasletter = true;
+		if (hasletter && *p == '\n')
+			return false;
+	}
+	return true;
+}
+
+
 static void
 tryexec(char *cmd, char **argv, char **envp)
 {
@@ -159,7 +191,7 @@ tryexec(char *cmd, char **argv, char **envp)
 		if (in != -1) {
 			n = pread(in, buf, sizeof buf, 0);
 			close(in);
-			if (n > 0 && memchr(buf, '\0', n) != NULL) {
+			if (n > 0 && isbinary(buf, n)) {
 				errno = ENOEXEC;
 				return;
 			}
diff --git a/bin/sh/tests/execution/Makefile b/bin/sh/tests/execution/Makefile
index bd6b2e06d55e..c7f68a7404aa 100644
--- a/bin/sh/tests/execution/Makefile
+++ b/bin/sh/tests/execution/Makefile
@@ -60,6 +60,7 @@ ${PACKAGE}FILES+=		shellproc2.0
 ${PACKAGE}FILES+=		shellproc3.0
 ${PACKAGE}FILES+=		shellproc4.0
 ${PACKAGE}FILES+=		shellproc5.0
+${PACKAGE}FILES+=		shellproc6.0
 ${PACKAGE}FILES+=		subshell1.0 subshell1.0.stdout
 ${PACKAGE}FILES+=		subshell2.0
 ${PACKAGE}FILES+=		subshell3.0
diff --git a/bin/sh/tests/execution/shellproc6.0 b/bin/sh/tests/execution/shellproc6.0
new file mode 100644
index 000000000000..1c06bc3b05a9
--- /dev/null
+++ b/bin/sh/tests/execution/shellproc6.0
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+T=`mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXXXX"` || exit
+trap 'rm -rf "${T}"' 0
+printf 'printf "this "\necho is a test\nexit\n\0' >"$T/testshellproc"
+chmod 755 "$T/testshellproc"
+PATH=$T:$PATH
+[ "`testshellproc`" = "this is a test" ]



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101301511.10UFBjcd033018>