summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorJilles Tjoelker <jilles@FreeBSD.org>2020-05-30 16:00:49 +0000
committerJilles Tjoelker <jilles@FreeBSD.org>2020-05-30 16:00:49 +0000
commite0f5c1387df23c8c4811f5b24a7ef6ecac51a71a (patch)
tree720522fec5317bf9886be3cf971e5164c6facc5b /bin
parent51cefda17055328ac1e7ec8456a81ec7600cf8dd (diff)
downloadsrc-test2-e0f5c1387df23c8c4811f5b24a7ef6ecac51a71a.tar.gz
src-test2-e0f5c1387df23c8c4811f5b24a7ef6ecac51a71a.zip
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.
Notes
Notes: svn path=/head/; revision=361647
Diffstat (limited to 'bin')
-rw-r--r--bin/sh/exec.c34
-rw-r--r--bin/sh/tests/execution/Makefile1
-rw-r--r--bin/sh/tests/execution/shellproc6.08
3 files changed, 42 insertions, 1 deletions
diff --git a/bin/sh/exec.c b/bin/sh/exec.c
index cd489a40b9dd..60be83857466 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>
/*
@@ -140,6 +141,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)
{
@@ -155,7 +187,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 526541d50994..1f7f1c80ae2b 100644
--- a/bin/sh/tests/execution/Makefile
+++ b/bin/sh/tests/execution/Makefile
@@ -59,6 +59,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" ]