summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-12-03 14:58:20 +0100
committerGitHub <noreply@github.com>2020-12-03 14:58:20 +0100
commit6dd16814a56d2ce96ab3c4c611a61e47f2f7b663 (patch)
tree38cdececafec3b424ca0acbcd8d268e7419931e8 /src/shared
parent03d8ebb935fb989e03ec27065a16bf9b79a5816b (diff)
parentceedbf8185fc7593366679f02d31da63af8c4bd1 (diff)
downloadsystemd-6dd16814a56d2ce96ab3c4c611a61e47f2f7b663.tar.gz
Merge pull request #17079 from keszybz/late-exec-resolution
Resolve executable paths before execution, use fexecve()
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/exec-util.c26
-rw-r--r--src/shared/exec-util.h2
2 files changed, 27 insertions, 1 deletions
diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c
index 61ee3b18d5..bdea60ca02 100644
--- a/src/shared/exec-util.c
+++ b/src/shared/exec-util.c
@@ -11,11 +11,13 @@
#include "conf-files.h"
#include "env-file.h"
#include "env-util.h"
+#include "errno-util.h"
#include "exec-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "hashmap.h"
#include "macro.h"
+#include "missing_syscall.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "serialize.h"
@@ -33,7 +35,6 @@
assert_cc(EAGAIN == EWOULDBLOCK);
static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) {
-
pid_t _pid;
int r;
@@ -444,3 +445,26 @@ ExecCommandFlags exec_command_flags_from_string(const char *s) {
else
return 1 << idx;
}
+
+int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
+#if ENABLE_FEXECVE
+ execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
+
+ if (IN_SET(errno, ENOSYS, ENOENT) || ERRNO_IS_PRIVILEGE(errno))
+ /* Old kernel or a script or an overzealous seccomp filter? Let's fall back to execve().
+ *
+ * fexecve(3): "If fd refers to a script (i.e., it is an executable text file that names a
+ * script interpreter with a first line that begins with the characters #!) and the
+ * close-on-exec flag has been set for fd, then fexecve() fails with the error ENOENT. This
+ * error occurs because, by the time the script interpreter is executed, fd has already been
+ * closed because of the close-on-exec flag. Thus, the close-on-exec flag can't be set on fd
+ * if it refers to a script."
+ *
+ * Unfortunately, if we unset close-on-exec, the script will be executed just fine, but (at
+ * least in case of bash) the script name, $0, will be shown as /dev/fd/nnn, which breaks
+ * scripts which make use of $0. Thus, let's fall back to execve() in this case.
+ */
+#endif
+ execve(executable, argv, envp);
+ return -errno;
+}
diff --git a/src/shared/exec-util.h b/src/shared/exec-util.h
index a69d57c7ae..df6214e4c3 100644
--- a/src/shared/exec-util.h
+++ b/src/shared/exec-util.h
@@ -45,3 +45,5 @@ extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
const char* exec_command_flags_to_string(ExecCommandFlags i);
ExecCommandFlags exec_command_flags_from_string(const char *s);
+
+int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]);