From 2c31eda469603554b844f1880d44451a5f9e3499 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 3 Apr 2025 23:38:40 +0900 Subject: [PATCH 1/3] build-path: check if found path is executable binary Otherwise, the path may point to a non-executable, e.g. a directory. --- src/basic/build-path.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/basic/build-path.c b/src/basic/build-path.c index 4a94fcb717..bc0dfc7f9b 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,6 +246,26 @@ int invoke_callout_binary(const char *path, char *const argv[]) { return -errno; } +static int open_executable(const char *path) { + int r; + + assert(path); + + _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; + + return TAKE_FD(fd); +} + int pin_callout_binary(const char *path) { int r; @@ -261,14 +282,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); _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); if (r >= 0) return r; } - return RET_NERRNO(open(path, O_CLOEXEC|O_PATH)); + return open_executable(path); } From b58c240312a5cc0f9f9eab3018d6459e44d085e0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 3 Apr 2025 23:41:42 +0900 Subject: [PATCH 2/3] build-path: make pin_callout_binary() optionally provides the path to the found executable --- src/basic/build-path.c | 19 +++++++++++++------ src/basic/build-path.h | 2 +- src/core/manager.c | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/basic/build-path.c b/src/basic/build-path.c index bc0dfc7f9b..ba49273cd3 100644 --- a/src/basic/build-path.c +++ b/src/basic/build-path.c @@ -246,7 +246,7 @@ int invoke_callout_binary(const char *path, char *const argv[]) { return -errno; } -static int open_executable(const char *path) { +static int open_executable(const char *path, char **ret_path) { int r; assert(path); @@ -263,15 +263,22 @@ static int open_executable(const char *path) { 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) { +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. */ + /* 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); @@ -282,14 +289,14 @@ int pin_callout_binary(const char *path) { const char *e; if (find_environment_binary(fn, &e) >= 0) - return open_executable(e); + return open_executable(e, ret_path); _cleanup_free_ char *np = NULL; if (find_build_dir_binary(fn, &np) >= 0) { - r = open_executable(np); + r = open_executable(np, ret_path); if (r >= 0) return r; } - return open_executable(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"); From 72008278857fdcf5822fbdb903105d293c4251ff Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 3 Apr 2025 20:07:33 +0900 Subject: [PATCH 3/3] udev-spawn: search executed command in build directory This should be useful when debugging RUN{program}= and friends. --- src/udev/udev-spawn.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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); }