diff --git a/src/basic/build-path.c b/src/basic/build-path.c index 4a94fcb717..ba49273cd3 100644 --- a/src/basic/build-path.c +++ b/src/basic/build-path.c @@ -7,6 +7,7 @@ #include "build-path.h" #include "errno-list.h" #include "errno-util.h" +#include "fd-util.h" #include "macro.h" #include "path-util.h" #include "process-util.h" @@ -245,12 +246,39 @@ int invoke_callout_binary(const char *path, char *const argv[]) { return -errno; } -int pin_callout_binary(const char *path) { +static int open_executable(const char *path, char **ret_path) { int r; assert(path); - /* Similar to invoke_callout_binary(), but pins (i.e. O_PATH opens) the binary instead of executing it. */ + _cleanup_close_ int fd = RET_NERRNO(open(path, O_CLOEXEC|O_PATH)); + if (fd < 0) + return fd; + + r = fd_verify_regular(fd); + if (r < 0) + return r; + + r = access_fd(fd, X_OK); + if (r < 0) + return r; + + if (ret_path) { + r = fd_get_path(fd, ret_path); + if (r < 0) + return r; + } + + return TAKE_FD(fd); +} + +int pin_callout_binary(const char *path, char **ret_path) { + int r; + + assert(path); + + /* Similar to invoke_callout_binary(), but pins (i.e. O_PATH opens) the binary instead of executing + * it, also optionally provides the path to the binary. */ _cleanup_free_ char *fn = NULL; r = path_extract_filename(path, &fn); @@ -261,14 +289,14 @@ int pin_callout_binary(const char *path) { const char *e; if (find_environment_binary(fn, &e) >= 0) - return RET_NERRNO(open(e, O_CLOEXEC|O_PATH)); + return open_executable(e, ret_path); _cleanup_free_ char *np = NULL; if (find_build_dir_binary(fn, &np) >= 0) { - r = RET_NERRNO(open(np, O_CLOEXEC|O_PATH)); + r = open_executable(np, ret_path); if (r >= 0) return r; } - return RET_NERRNO(open(path, O_CLOEXEC|O_PATH)); + return open_executable(path, ret_path); } diff --git a/src/basic/build-path.h b/src/basic/build-path.h index 6c38a4a3bb..214f8ef564 100644 --- a/src/basic/build-path.h +++ b/src/basic/build-path.h @@ -5,4 +5,4 @@ int get_build_exec_dir(char **ret); int invoke_callout_binary(const char *path, char *const argv[]); -int pin_callout_binary(const char *path); +int pin_callout_binary(const char *path, char **ret_path); diff --git a/src/core/manager.c b/src/core/manager.c index 06d6f51a13..02623be4bf 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1048,7 +1048,7 @@ int manager_new(RuntimeScope runtime_scope, ManagerTestRunFlags test_run_flags, } if (!FLAGS_SET(test_run_flags, MANAGER_TEST_DONT_OPEN_EXECUTOR)) { - m->executor_fd = pin_callout_binary(SYSTEMD_EXECUTOR_BINARY_PATH); + m->executor_fd = pin_callout_binary(SYSTEMD_EXECUTOR_BINARY_PATH, /* ret_path = */ NULL); if (m->executor_fd < 0) return log_debug_errno(m->executor_fd, "Failed to pin executor binary: %m"); diff --git a/src/udev/udev-spawn.c b/src/udev/udev-spawn.c index 9bd6847ef4..62db775250 100644 --- a/src/udev/udev-spawn.c +++ b/src/udev/udev-spawn.c @@ -2,9 +2,11 @@ #include "sd-event.h" +#include "build-path.h" #include "device-private.h" #include "device-util.h" #include "event-util.h" +#include "exec-util.h" #include "fd-util.h" #include "path-util.h" #include "process-util.h" @@ -279,6 +281,14 @@ int udev_event_spawn( free_and_replace(argv[0], program); } + char *found; + _cleanup_close_ int fd_executable = r = pin_callout_binary(argv[0], &found); + if (r < 0) + return log_device_error_errno(event->dev, r, "Failed to find and pin callout binary \"%s\": %m", argv[0]); + + log_device_debug(event->dev, "Found callout binary: \"%s\".", found); + free_and_replace(argv[0], found); + char **envp; r = device_get_properties_strv(event->dev, &envp); if (r < 0) @@ -290,7 +300,7 @@ int udev_event_spawn( r = pidref_safe_fork_full( "(spawn)", (int[]) { -EBADF, outpipe[WRITE_END], errpipe[WRITE_END] }, - NULL, 0, + &fd_executable, 1, FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE, &pidref); if (r < 0) @@ -298,7 +308,7 @@ int udev_event_spawn( "Failed to fork() to execute command '%s': %m", cmd); if (r == 0) { DEVICE_TRACE_POINT(spawn_exec, event->dev, cmd); - execve(argv[0], argv, envp); + (void) fexecve_or_execve(fd_executable, argv[0], argv, envp); _exit(EXIT_FAILURE); }