git: 3708b615c354 - stable/12 - sh: Allow more scripts without #!
Jilles Tjoelker
jilles at FreeBSD.org
Sat Jan 30 15:11:45 UTC 2021
The branch stable/12 has been updated by jilles:
URL: https://cgit.FreeBSD.org/src/commit/?id=3708b615c354df013037c065d5a714207c041ea8
commit 3708b615c354df013037c065d5a714207c041ea8
Author: Jilles Tjoelker <jilles at FreeBSD.org>
AuthorDate: 2020-05-30 16:00:49 +0000
Commit: Jilles Tjoelker <jilles at 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" ]
More information about the dev-commits-src-all
mailing list