mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-18 03:41:16 -03:00
Allow more scripts without #!
This change modifies the fish safety check surrounding execve / spawn so
it can run shell scripts having concatenated binary content. We're using
the same safety check as FreeBSD /bin/sh [1] and the Z-shell [5]. POSIX
was recently revised to require this behavior:
"The input file may be of any type, but the initial portion of the
file intended to be parsed according to the shell grammar (XREF to
XSH 2.10.2 Shell Grammar Rules) shall consist of characters and
shall not contain the NUL character. The shell shall not enforce
any line length limits."
"Earlier versions of this standard required that input files to the
shell be text files except that line lengths were unlimited.
However, that was overly restrictive in relation to the fact that
shells can parse a script without a trailing newline, and in
relation to a common practice of concatenating a shell script
ending with an 'exit' or 'exec $command' with a binary data payload
to form a single-file self-extracting archive." [2] [3]
One example use case of such scripts, is the Cosmopolitan C Library [4]
which configuse the GNU Linker to output a polyglot shell+binary format
that runs on Linux / Mac / Windows / FreeBSD / OpenBSD / NetBSD / BIOS.
Fixes jart/cosmopolitan#88
[1] 9a1cd36331
[2] http://austingroupbugs.net/view.php?id=1250
[3] http://austingroupbugs.net/view.php?id=1226#c4394
[4] https://justine.lol/cosmopolitan/index.html
[5] 326d9c203b
This commit is contained in:
committed by
ridiculousfish
parent
df53d1415d
commit
0048730a67
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
@@ -39,6 +40,7 @@
|
||||
/// Fork error message.
|
||||
#define FORK_ERROR "Could not create child process - exiting"
|
||||
|
||||
extern bool is_thompson_shell_script(const char *path);
|
||||
static char *get_interpreter(const char *command, char *buffer, size_t buff_size);
|
||||
|
||||
/// Report the error code \p err for a failed setpgid call.
|
||||
@@ -300,7 +302,28 @@ posix_spawner_t::posix_spawner_t(const job_t *j, const dup2_list_t &dup2s) {
|
||||
maybe_t<pid_t> posix_spawner_t::spawn(const char *cmd, char *const argv[], char *const envp[]) {
|
||||
if (get_error()) return none();
|
||||
pid_t pid = -1;
|
||||
if (check_fail(posix_spawn(&pid, cmd, &*actions_, &*attr_, argv, envp))) return none();
|
||||
if (check_fail(posix_spawn(&pid, cmd, &*actions_, &*attr_, argv, envp))) {
|
||||
// The shebang wasn't introduced until UNIX Seventh Edition, so if
|
||||
// the kernel won't run the binary we hand it off to the intpreter
|
||||
// after performing a binary safety check, recommended by POSIX: a
|
||||
// line needs to exist before the first \0 with a lowercase letter
|
||||
if (error_ == ENOEXEC && is_thompson_shell_script(cmd)) {
|
||||
error_ = 0;
|
||||
size_t n = 0;
|
||||
while (argv[n]) ++n;
|
||||
std::unique_ptr<char *[]> argv2(new char *[1 + n + 1]);
|
||||
char interp[] = _PATH_BSHELL;
|
||||
argv2[0] = interp;
|
||||
for (size_t i = 0; i < n + 1; ++i) {
|
||||
argv2[i + 1] = argv[i];
|
||||
}
|
||||
if (check_fail(posix_spawn(&pid, interp, &*actions_, &*attr_, argv2.get(), envp))) {
|
||||
return none();
|
||||
}
|
||||
} else {
|
||||
return none();
|
||||
}
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user